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