aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Zamarin <arthurzam@gentoo.org>2024-03-20 22:03:58 +0200
committerArthur Zamarin <arthurzam@gentoo.org>2024-03-20 22:14:31 +0200
commitb3af97293aaa47c39fc3ae9fcabd2c67ca332d23 (patch)
tree5cfb2844a2265d3bf0e28e7645f03e5a49642dcd
parentdb: when logging query, also log the duration (diff)
downloadsoko-b3af97293aaa47c39fc3ae9fcabd2c67ca332d23.tar.gz
soko-b3af97293aaa47c39fc3ae9fcabd2c67ca332d23.tar.bz2
soko-b3af97293aaa47c39fc3ae9fcabd2c67ca332d23.zip
app/category: optimize and simplify the show
Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
-rw-r--r--pkg/app/handler/categories/feeds.go38
-rw-r--r--pkg/app/handler/categories/show.go207
-rw-r--r--pkg/app/handler/categories/show.templ67
-rw-r--r--pkg/app/handler/maintainer/show.go15
-rw-r--r--pkg/app/serve.go12
-rw-r--r--pkg/app/utils/stabilization.go20
6 files changed, 199 insertions, 160 deletions
diff --git a/pkg/app/handler/categories/feeds.go b/pkg/app/handler/categories/feeds.go
new file mode 100644
index 0000000..2afdf13
--- /dev/null
+++ b/pkg/app/handler/categories/feeds.go
@@ -0,0 +1,38 @@
+package categories
+
+import (
+ "net/http"
+ "soko/pkg/app/utils"
+ "soko/pkg/database"
+ "soko/pkg/models"
+)
+
+func OutdatedFeed(w http.ResponseWriter, r *http.Request) {
+ categoryName := r.PathValue("category")
+ var outdated []models.OutdatedPackages
+ err := database.DBCon.Model(&outdated).
+ Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
+ Order("atom").
+ Select()
+ if err != nil {
+ http.NotFound(w, r)
+ return
+ }
+ utils.OutdatedFeed(w, "https://packages.gentoo.org/categories/"+categoryName+"/outdated", "category "+categoryName, outdated)
+}
+
+func StabilizationFeed(w http.ResponseWriter, r *http.Request) {
+ categoryName := r.PathValue("category")
+ var results []*models.PkgCheckResult
+ err := database.DBCon.Model(&results).
+ Column("atom", "cpv", "message").
+ Where("class = ?", "StableRequest").
+ Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
+ OrderExpr("cpv").
+ Select()
+ if err != nil {
+ http.NotFound(w, r)
+ return
+ }
+ utils.StabilizationFeed(w, "https://packages.gentoo.org/categories/"+categoryName+"/stabilization", "category "+categoryName, results)
+}
diff --git a/pkg/app/handler/categories/show.go b/pkg/app/handler/categories/show.go
index b48e37c..4f8bc60 100644
--- a/pkg/app/handler/categories/show.go
+++ b/pkg/app/handler/categories/show.go
@@ -5,112 +5,148 @@ package categories
import (
"encoding/json"
"net/http"
- "soko/pkg/app/utils"
- "soko/pkg/database"
- "soko/pkg/models"
"strings"
"github.com/go-pg/pg/v10"
+
+ "soko/pkg/app/handler/packages/components"
+ "soko/pkg/app/utils"
+ "soko/pkg/database"
+ "soko/pkg/models"
)
-// Show renders a template to show a given category
-func Show(w http.ResponseWriter, r *http.Request) {
+func common(w http.ResponseWriter, r *http.Request) (categoryName string, category models.Category, err error) {
+ categoryName = r.PathValue("category")
+
+ err = database.DBCon.Model(&category).
+ Where("category.name = ?", categoryName).
+ Relation("PackagesInformation").Select()
+ if err == pg.ErrNoRows {
+ http.NotFound(w, r)
+ return
+ } else if err != nil {
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ return
+ }
+ return
+}
+
+type packageInfo struct {
+ Package string
+ Description string
+}
+
+func ShowPackages(w http.ResponseWriter, r *http.Request) {
categoryName := r.PathValue("category")
- pageUrl := r.PathValue("pageName")
+ if strings.HasSuffix(categoryName, ".json") {
+ buildJson(w, categoryName[:len(categoryName)-5])
+ return
+ }
+ categoryName, category, err := common(w, r)
+ if err != nil {
+ return
+ }
- if pageUrl == "" && strings.HasSuffix(categoryName, ".json") {
- buildJson(w, r, strings.TrimSuffix(categoryName, ".json"))
+ var packages []packageInfo
+ err = database.DBCon.Model((*models.Version)(nil)).
+ DistinctOn("package").
+ Column("package", "description").
+ Where("category = ?", categoryName).
+ Order("package ASC").
+ Select(&packages)
+ if err != nil {
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
+ renderShowPage(w, r, "Packages", &category,
+ showPackages(categoryName, packages))
+}
- var pullRequests []*models.GithubPullRequest
- category := new(models.Category)
- query := database.DBCon.Model(category).
- Where("category.name = ?", categoryName).
- Relation("PackagesInformation").
- Relation("Packages", func(q *pg.Query) (*pg.Query, error) {
- return q.Order("name ASC"), nil
- })
-
- pageName := "Packages"
- switch pageUrl {
- case "stabilization":
- pageName = "Stabilization"
- query = query.Relation("Packages.Versions").
- Relation("Packages.Versions.PkgCheckResults", func(q *pg.Query) (*pg.Query, error) {
- return q.Where("class = 'StableRequest'"), nil
- })
- case "outdated":
- pageName = "Outdated"
- query = query.Relation("Packages.Versions").
- Relation("Packages.Outdated")
- case "outdated.atom":
- var outdated []models.OutdatedPackages
- err := database.DBCon.Model(&outdated).
- Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
- Order("atom").
- Select()
- if err != nil {
- http.NotFound(w, r)
- return
- }
- utils.OutdatedFeed(w, "https://packages.gentoo.org/categories/"+categoryName+"/outdated", "category "+categoryName, outdated)
+func ShowOutdated(w http.ResponseWriter, r *http.Request) {
+ categoryName, category, err := common(w, r)
+ if err != nil {
return
- case "pull-requests":
- pageName = "Pull requests"
- err := database.DBCon.Model(&pullRequests).
- Join("JOIN package_to_github_pull_requests ON package_to_github_pull_requests.github_pull_request_id = github_pull_request.id").
- Where("package_to_github_pull_requests.package_atom LIKE ?", categoryName+"/%").
- Group("github_pull_request.id").
- Order("github_pull_request.created_at DESC").
- Select()
- if err != nil {
- http.NotFound(w, r)
- return
- }
- case "stabilization.json", "stabilization.xml", "stabilization.list":
- err := query.Relation("Packages.Versions").
- Relation("Packages.Versions.PkgCheckResults", func(q *pg.Query) (*pg.Query, error) {
- return q.Where("class = 'StableRequest'"), nil
- }).Select()
- if err != nil {
- http.NotFound(w, r)
- return
- }
- utils.StabilizationExport(w, pageUrl, category.Packages)
+ }
+
+ var outdated []components.OutdatedItem
+ descriptionQuery := database.DBCon.Model((*models.Version)(nil)).
+ Column("description").
+ Where("atom = outdated_packages.atom").
+ Limit(1)
+ err = database.DBCon.Model((*models.OutdatedPackages)(nil)).
+ Column("atom").ColumnExpr("(?) AS description", descriptionQuery).
+ Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
+ Order("atom").
+ Select(&outdated)
+ if err != nil {
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
- case "stabilization.atom":
- var results []*models.PkgCheckResult
- err := database.DBCon.Model(&results).
- Column("atom", "cpv", "message").
- Where("class = ?", "StableRequest").
- Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
- OrderExpr("cpv").
- Select()
- if err != nil {
- http.NotFound(w, r)
- return
- }
- utils.StabilizationFeed(w, "https://packages.gentoo.org/categories/"+categoryName+"/stabilization", "category "+categoryName, results)
+ }
+ renderShowPage(w, r, "Outdated", &category,
+ components.Outdated(outdated))
+}
+
+func ShowPullRequests(w http.ResponseWriter, r *http.Request) {
+ categoryName, category, err := common(w, r)
+ if err != nil {
return
- case "", "packages":
- query = query.Relation("Packages.Versions")
- default:
- http.NotFound(w, r)
+ }
+
+ var pullRequests []*models.GithubPullRequest
+ err = database.DBCon.Model(&pullRequests).
+ Join("JOIN package_to_github_pull_requests ON package_to_github_pull_requests.github_pull_request_id = github_pull_request.id").
+ Where("package_to_github_pull_requests.package_atom LIKE ?", categoryName+"/%").
+ Group("github_pull_request.id").
+ Order("github_pull_request.created_at DESC").
+ Select()
+ if err != nil {
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
+ renderShowPage(w, r, "Pull requests", &category,
+ components.PullRequests(category.PackagesInformation.PullRequests > 0, pullRequests))
+}
- err := query.Select()
+func ShowStabilizations(w http.ResponseWriter, r *http.Request) {
+ categoryName, category, err := common(w, r)
if err != nil {
- http.NotFound(w, r)
return
}
- renderShowPage(w, r, pageName, category, pullRequests)
+ var results []*models.PkgCheckResult
+ err = database.DBCon.Model(&results).
+ Column("atom", "cpv", "message").
+ Where("class = ?", "StableRequest").
+ Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
+ OrderExpr("cpv").
+ Select()
+ if err != nil {
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ return
+ }
+ renderShowPage(w, r, "Stabilization", &category,
+ components.Stabilizations(category.PackagesInformation.StableRequests > 0, results))
+}
+
+func ShowStabilizationFile(w http.ResponseWriter, r *http.Request) {
+ categoryName := r.PathValue("category")
+ var results []*models.PkgCheckResult
+ err := database.DBCon.Model(&results).
+ Column("category", "package", "version", "message").
+ Where("class = ?", "StableRequest").
+ Where("SPLIT_PART(atom, '/', 1) = ?", categoryName).
+ OrderExpr("cpv").
+ Select()
+ if err != nil {
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ return
+ }
+ pageName := r.URL.Path[strings.LastIndexByte(r.URL.Path, '/')+1:]
+ utils.StabilizationExport(w, pageName, results)
}
// build the json for the category
-func buildJson(w http.ResponseWriter, r *http.Request, categoryName string) {
+func buildJson(w http.ResponseWriter, categoryName string) {
var jsonCategory struct {
Name string `json:"name"`
Href string `json:"href"`
@@ -129,7 +165,7 @@ func buildJson(w http.ResponseWriter, r *http.Request, categoryName string) {
Order("package ASC").
Select(&jsonCategory.Packages)
if err != nil {
- http.NotFound(w, r)
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
@@ -138,8 +174,7 @@ func buildJson(w http.ResponseWriter, r *http.Request, categoryName string) {
b, err := json.Marshal(jsonCategory)
if err != nil {
- http.Error(w, http.StatusText(http.StatusInternalServerError),
- http.StatusInternalServerError)
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
diff --git a/pkg/app/handler/categories/show.templ b/pkg/app/handler/categories/show.templ
index 82cf4bb..92812cc 100644
--- a/pkg/app/handler/categories/show.templ
+++ b/pkg/app/handler/categories/show.templ
@@ -3,7 +3,6 @@ package categories
import "net/http"
import "strconv"
import "strings"
-import "soko/pkg/app/handler/packages/components"
import "soko/pkg/app/layout"
import "soko/pkg/models"
@@ -11,7 +10,7 @@ func packageLetter(name string) string {
return strings.ToLower(strings.TrimLeft(name, "_")[:1])
}
-templ showPackages(packages []*models.Package) {
+templ showPackages(categoryName string, packages []packageInfo) {
<div class="row">
<div class="col-12">
<div class="row">
@@ -23,12 +22,12 @@ templ showPackages(packages []*models.Package) {
<table class="table mb-0 rounded">
for i, pkg := range packages {
<tr
- if i == 0 || packageLetter(pkg.Name) != packageLetter(packages[i-1].Name) {
- id={ packageLetter(pkg.Name) }
+ if i == 0 || packageLetter(pkg.Package) != packageLetter(packages[i-1].Package) {
+ id={ packageLetter(pkg.Package) }
}
>
- <th class="kk-nobreak-cell"><a href={ templ.URL("/packages/" + pkg.Atom) }>{ pkg.Name }</a></th>
- <td>{ pkg.Versions[0].Description }</td>
+ <th class="kk-nobreak-cell"><a href={ templ.URL("/packages/" + categoryName + "/" + pkg.Package) }>{ pkg.Package }</a></th>
+ <td>{ pkg.Description }</td>
</tr>
}
</table>
@@ -42,10 +41,10 @@ templ showPackages(packages []*models.Package) {
<h4 class="mt-4">Filter by Category</h4>
<div class="row pl-4 pr-5 mr-5">
for i, pkg := range packages {
- if i == 0 || packageLetter(pkg.Name) != packageLetter(packages[i-1].Name) {
+ if i == 0 || packageLetter(pkg.Package) != packageLetter(packages[i-1].Package) {
<div class="col-md-2 px-2">
- <a href={ templ.URL("#" + packageLetter(pkg.Name)) } class="text-muted text-capitalize">
- { packageLetter(pkg.Name) }
+ <a href={ templ.URL("#" + packageLetter(pkg.Package)) } class="text-muted text-capitalize">
+ { packageLetter(pkg.Package) }
</a>
</div>
}
@@ -57,54 +56,18 @@ templ showPackages(packages []*models.Package) {
</div>
}
-func collectStabilizations(packages []*models.Package) (stabilizations []*models.PkgCheckResult) {
- for _, pkg := range packages {
- for _, ver := range pkg.Versions {
- for _, res := range ver.PkgCheckResults {
- if res.Class == "StableRequest" {
- stabilizations = append(stabilizations, res)
- break
- }
- }
- }
- }
- return
-}
-
-func collectOutdated(packages []*models.Package) (outdated []components.OutdatedItem) {
- for _, pkg := range packages {
- if len(pkg.Outdated) > 0 {
- outdated = append(outdated, components.OutdatedItem{
- Atom: pkg.Atom,
- Description: pkg.Description(),
- })
- }
- }
- return
-}
-
-templ show(pageName string, category *models.Category, pullRequests []*models.GithubPullRequest) {
+templ show(component templ.Component) {
<div class="container mb-5 tab-pane fade show active" id="overview" role="tabpanel" aria-labelledby="overview-tab">
- switch pageName {
- case "Packages":
- @showPackages(category.Packages)
- case "Stabilization":
- @components.Stabilizations(category.PackagesInformation.StableRequests > 0, collectStabilizations(category.Packages))
- case "Outdated":
- @components.Outdated(collectOutdated(category.Packages))
- case "Pull requests":
- @components.PullRequests(category.PackagesInformation.PullRequests > 0, pullRequests)
- }
+ @component
</div>
}
-func renderShowPage(w http.ResponseWriter, r *http.Request, currentTab string, category *models.Category, pullRequests []*models.GithubPullRequest) {
+func renderShowPage(w http.ResponseWriter, r *http.Request, currentTab string, category *models.Category, component templ.Component) {
layout.TabbedLayout(category.Name, "packages", category.Name, "fa fa-fw fa-cubes", category.Description, []layout.SubTab{
{
- Name: "Packages",
- Link: templ.URL("/categories/" + category.Name),
- Icon: "fa fa-list-ul mr-1",
- BadgeValue: strconv.Itoa(len(category.Packages)),
+ Name: "Packages",
+ Link: templ.URL("/categories/" + category.Name),
+ Icon: "fa fa-list-ul mr-1",
},
{
Name: "Stabilization",
@@ -124,5 +87,5 @@ func renderShowPage(w http.ResponseWriter, r *http.Request, currentTab string, c
Icon: "octicon octicon-git-pull-request opticon-resource-icon ml-1",
BadgeValue: strconv.Itoa(category.PackagesInformation.PullRequests),
},
- }, currentTab, show(currentTab, category, pullRequests)).Render(r.Context(), w)
+ }, currentTab, show(component)).Render(r.Context(), w)
}
diff --git a/pkg/app/handler/maintainer/show.go b/pkg/app/handler/maintainer/show.go
index 981a5c6..5f05382 100644
--- a/pkg/app/handler/maintainer/show.go
+++ b/pkg/app/handler/maintainer/show.go
@@ -261,17 +261,18 @@ func ShowStabilizationFile(w http.ResponseWriter, r *http.Request) {
}
pageName := r.URL.Path[strings.LastIndexByte(r.URL.Path, '/')+1:]
- var gpackages []*models.Package
- err = query.Model(&gpackages).
- Relation("Versions").
- Relation("Versions.PkgCheckResults", func(q *pg.Query) (*pg.Query, error) {
- return q.Where("class = ?", "StableRequest"), nil
- }).Select()
+ var results []*models.PkgCheckResult
+ err = database.DBCon.Model(&results).
+ Column("atom", "cpv", "message").
+ Where("class = ?", "StableRequest").
+ Where("atom IN (?)", query).
+ OrderExpr("cpv").
+ Select()
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
- utils.StabilizationExport(w, pageName, gpackages)
+ utils.StabilizationExport(w, pageName, results)
}
func ShowStabilizationFeed(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/app/serve.go b/pkg/app/serve.go
index d13cada..6a6bf9a 100644
--- a/pkg/app/serve.go
+++ b/pkg/app/serve.go
@@ -27,14 +27,20 @@ import (
// Serve is used to serve the web application
func Serve() {
-
database.Connect()
defer database.DBCon.Close()
setRoute("GET /categories", categories.Index)
setRoute("GET /categories.json", categories.JSONCategories)
- setRoute("GET /categories/{category}", categories.Show)
- setRoute("GET /categories/{category}/{pageName}", categories.Show)
+ setRoute("GET /categories/{category}", categories.ShowPackages)
+ setRoute("GET /categories/{category}/outdated", categories.ShowOutdated)
+ setRoute("GET /categories/{category}/outdated.atom", categories.OutdatedFeed)
+ setRoute("GET /categories/{category}/pull-requests", categories.ShowPullRequests)
+ setRoute("GET /categories/{category}/stabilization", categories.ShowStabilizations)
+ setRoute("GET /categories/{category}/stabilization.atom", categories.StabilizationFeed)
+ setRoute("GET /categories/{category}/stabilization.json", categories.ShowStabilizationFile)
+ setRoute("GET /categories/{category}/stabilization.list", categories.ShowStabilizationFile)
+ setRoute("GET /categories/{category}/stabilization.xml", categories.ShowStabilizationFile)
setRoute("GET /useflags/popular.json", useflags.Popular)
setRoute("GET /useflags/suggest.json", useflags.Suggest)
diff --git a/pkg/app/utils/stabilization.go b/pkg/app/utils/stabilization.go
index 4395294..85a8111 100644
--- a/pkg/app/utils/stabilization.go
+++ b/pkg/app/utils/stabilization.go
@@ -24,18 +24,14 @@ func (s stabilization) String() string {
return s.Category + "/" + s.Package + "-" + s.Version + " # " + s.Message
}
-func StabilizationExport(w http.ResponseWriter, pageUrl string, gpackages []*models.Package) {
- result := make([]stabilization, 0)
- for _, gpackage := range gpackages {
- for _, version := range gpackage.Versions {
- for _, pkgcheck := range version.PkgCheckResults {
- result = append(result, stabilization{
- Category: pkgcheck.Category,
- Package: pkgcheck.Package,
- Version: pkgcheck.Version,
- Message: pkgcheck.Message,
- })
- }
+func StabilizationExport(w http.ResponseWriter, pageUrl string, results []*models.PkgCheckResult) {
+ result := make([]stabilization, len(results))
+ for i, pkgcheck := range results {
+ result[i] = stabilization{
+ Category: pkgcheck.Category,
+ Package: pkgcheck.Package,
+ Version: pkgcheck.Version,
+ Message: pkgcheck.Message,
}
}