forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package state
2
3import (
4 "log"
5 "net/http"
6 "sort"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9 "tangled.org/core/appview/db"
10 "tangled.org/core/appview/models"
11 "tangled.org/core/appview/pages"
12 "tangled.org/core/appview/pagination"
13 "tangled.org/core/consts"
14 "tangled.org/core/orm"
15)
16
17func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) {
18 user := s.oauth.GetUser(r)
19
20 page := pagination.FromContext(r.Context())
21
22 goodFirstIssueLabel := s.config.Label.GoodFirstIssue
23
24 gfiLabelDef, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", goodFirstIssueLabel))
25 if err != nil {
26 log.Println("failed to get gfi label def", err)
27 s.pages.Error500(w)
28 return
29 }
30
31 repoLabels, err := db.GetRepoLabels(s.db, orm.FilterEq("label_at", goodFirstIssueLabel))
32 if err != nil {
33 log.Println("failed to get repo labels", err)
34 s.pages.Error503(w)
35 return
36 }
37
38 if len(repoLabels) == 0 {
39 s.pages.GoodFirstIssues(w, pages.GoodFirstIssuesParams{
40 LoggedInUser: user,
41 RepoGroups: []*models.RepoGroup{},
42 LabelDefs: make(map[string]*models.LabelDefinition),
43 Page: page,
44 GfiLabel: gfiLabelDef,
45 })
46 return
47 }
48
49 repoUris := make([]string, 0, len(repoLabels))
50 for _, rl := range repoLabels {
51 repoUris = append(repoUris, rl.RepoAt.String())
52 }
53
54 allIssues, err := db.GetIssuesPaginated(
55 s.db,
56 pagination.Page{
57 Limit: 500,
58 },
59 orm.FilterIn("repo_at", repoUris),
60 orm.FilterEq("open", 1),
61 )
62 if err != nil {
63 log.Println("failed to get issues", err)
64 s.pages.Error503(w)
65 return
66 }
67
68 var goodFirstIssues []models.Issue
69 for _, issue := range allIssues {
70 if issue.Labels.ContainsLabel(goodFirstIssueLabel) {
71 goodFirstIssues = append(goodFirstIssues, issue)
72 }
73 }
74
75 repoGroups := make(map[syntax.ATURI]*models.RepoGroup)
76 for _, issue := range goodFirstIssues {
77 if group, exists := repoGroups[issue.Repo.RepoAt()]; exists {
78 group.Issues = append(group.Issues, issue)
79 } else {
80 repoGroups[issue.Repo.RepoAt()] = &models.RepoGroup{
81 Repo: issue.Repo,
82 Issues: []models.Issue{issue},
83 }
84 }
85 }
86
87 var sortedGroups []*models.RepoGroup
88 for _, group := range repoGroups {
89 sortedGroups = append(sortedGroups, group)
90 }
91
92 sort.Slice(sortedGroups, func(i, j int) bool {
93 iIsTangled := sortedGroups[i].Repo.Did == consts.TangledDid
94 jIsTangled := sortedGroups[j].Repo.Did == consts.TangledDid
95
96 // If one is tangled and the other isn't, non-tangled comes first
97 if iIsTangled != jIsTangled {
98 return jIsTangled // true if j is tangled (i should come first)
99 }
100
101 // Both tangled or both not tangled: sort by name
102 return sortedGroups[i].Repo.Name < sortedGroups[j].Repo.Name
103 })
104
105 groupStart := page.Offset
106 groupEnd := page.Offset + page.Limit
107 if groupStart > len(sortedGroups) {
108 groupStart = len(sortedGroups)
109 }
110 if groupEnd > len(sortedGroups) {
111 groupEnd = len(sortedGroups)
112 }
113
114 paginatedGroups := sortedGroups[groupStart:groupEnd]
115
116 var allIssuesFromGroups []models.Issue
117 for _, group := range paginatedGroups {
118 allIssuesFromGroups = append(allIssuesFromGroups, group.Issues...)
119 }
120
121 var allLabelDefs []models.LabelDefinition
122 if len(allIssuesFromGroups) > 0 {
123 labelDefUris := make(map[string]bool)
124 for _, issue := range allIssuesFromGroups {
125 for labelDefUri := range issue.Labels.Inner() {
126 labelDefUris[labelDefUri] = true
127 }
128 }
129
130 uriList := make([]string, 0, len(labelDefUris))
131 for uri := range labelDefUris {
132 uriList = append(uriList, uri)
133 }
134
135 if len(uriList) > 0 {
136 allLabelDefs, err = db.GetLabelDefinitions(s.db, orm.FilterIn("at_uri", uriList))
137 if err != nil {
138 log.Println("failed to fetch labels", err)
139 }
140 }
141 }
142
143 labelDefsMap := make(map[string]*models.LabelDefinition)
144 for i := range allLabelDefs {
145 labelDefsMap[allLabelDefs[i].AtUri().String()] = &allLabelDefs[i]
146 }
147
148 s.pages.GoodFirstIssues(w, pages.GoodFirstIssuesParams{
149 LoggedInUser: user,
150 RepoGroups: paginatedGroups,
151 LabelDefs: labelDefsMap,
152 Page: page,
153 GfiLabel: gfiLabelDef,
154 })
155}