Skip to content

Commit e41c7c3

Browse files
committed
feat: add stargazers page
Signed-off-by: Animesh Pathak <[email protected]>
1 parent b5f7786 commit e41c7c3

File tree

15 files changed

+1768
-56
lines changed

15 files changed

+1768
-56
lines changed

common/config.go

Lines changed: 0 additions & 12 deletions
This file was deleted.

common/type.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,49 @@ type StarPoint struct {
6666
type MultiRepoStarHistory struct {
6767
Repositories []StarHistory `json:"repositories"`
6868
}
69+
70+
// ActiveContributor represents a contributor's activity stats
71+
type ActiveContributor struct {
72+
Login string `json:"login"`
73+
Contributions int `json:"contributions"`
74+
LastActiveDate time.Time `json:"last_active_date"`
75+
}
76+
77+
// ActiveContributorsResponse represents the response for active contributors
78+
type ActiveContributorsResponse struct {
79+
RepoName string `json:"repo_name"`
80+
TimeRange string `json:"time_range"`
81+
ActiveContributors []ActiveContributor `json:"active_contributors"`
82+
}
83+
84+
type StargazerResponse struct {
85+
User User `json:"user"`
86+
StarredAt time.Time `json:"starred_at"`
87+
}
88+
89+
type User struct {
90+
Login string `json:"login"`
91+
AvatarURL string `json:"avatar_url"`
92+
Name string `json:"name"`
93+
Location string `json:"location"`
94+
HTMLURL string `json:"html_url"`
95+
}
96+
97+
type Stargazer struct {
98+
Login string `json:"login"`
99+
AvatarURL string `json:"avatar_url"`
100+
HTMLURL string `json:"html_url"`
101+
Name string `json:"name,omitempty"`
102+
Location string `json:"location,omitempty"`
103+
StarredAt time.Time `json:"starred_at"`
104+
}
105+
106+
type PageData struct {
107+
Stargazers []Stargazer
108+
RepoOwner string
109+
RepoName string
110+
Error string
111+
HasMore bool
112+
NextPage int
113+
TotalCount int
114+
}

coverage.out

Lines changed: 270 additions & 0 deletions
Large diffs are not rendered by default.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
module github.com/sonichigo/hg
1+
module github.com/sonichigo/gitstats
22

33
go 1.22.5

handlers/api.go

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import (
44
"encoding/json"
55
"fmt"
66
"net/http"
7+
"strconv"
78
"strings"
89

9-
cu "github.com/sonichigo/hg/common"
10+
cu "github.com/sonichigo/gitstats/common"
1011
)
1112

1213
func HandleRepoStats(w http.ResponseWriter, r *http.Request) {
@@ -94,6 +95,7 @@ func HandleStarHistory(w http.ResponseWriter, r *http.Request) {
9495
w.Header().Set("Content-Type", "application/json")
9596
json.NewEncoder(w).Encode(result)
9697
}
98+
9799
func HandleOrgContributors(w http.ResponseWriter, r *http.Request) {
98100
if r.Method != http.MethodGet {
99101
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@@ -124,3 +126,98 @@ func HandleOrgContributors(w http.ResponseWriter, r *http.Request) {
124126
w.Header().Set("Content-Type", "application/json")
125127
json.NewEncoder(w).Encode(stats)
126128
}
129+
130+
func HandleActiveContributors(w http.ResponseWriter, r *http.Request) {
131+
if r.Method != http.MethodGet {
132+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
133+
return
134+
}
135+
136+
repoURL := r.URL.Query().Get("repo")
137+
orgName := r.URL.Query().Get("org")
138+
139+
if orgName == "" && repoURL == "" {
140+
http.Error(w, "Either organization name or repository URL is required", http.StatusBadRequest)
141+
return
142+
}
143+
144+
var config *cu.Config
145+
146+
// If repoURL is provided, handle single repository
147+
if repoURL != "" {
148+
owner, repo, err := extractRepoInfo(repoURL)
149+
if err != nil {
150+
http.Error(w, fmt.Sprintf("Invalid repository URL: %v", err), http.StatusBadRequest)
151+
return
152+
}
153+
handleSingleRepo(w, owner, repo, config)
154+
return
155+
}
156+
157+
// Handle organization-wide contributors
158+
handleOrganization(w, orgName, config)
159+
}
160+
161+
func HandleStargazers(w http.ResponseWriter, r *http.Request) {
162+
if r.Method != http.MethodGet {
163+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
164+
return
165+
}
166+
167+
// Get query parameters
168+
owner := r.URL.Query().Get("owner")
169+
repo := r.URL.Query().Get("repo")
170+
171+
if owner == "" || repo == "" {
172+
http.Error(w, "Both owner and repository name are required", http.StatusBadRequest)
173+
return
174+
}
175+
176+
// Parse page number
177+
page, err := strconv.Atoi(r.URL.Query().Get("page"))
178+
if err != nil || page < 1 {
179+
page = 1
180+
}
181+
182+
// Get token from Authorization header
183+
var token string
184+
authHeader := r.Header.Get("Authorization")
185+
if authHeader != "" {
186+
token = strings.TrimPrefix(authHeader, "Bearer ")
187+
token = strings.TrimSpace(token)
188+
}
189+
190+
// Fetch stargazers
191+
stargazers, hasMore, total, err := fetchStargazers(owner, repo, token, page)
192+
if err != nil {
193+
http.Error(w, err.Error(), http.StatusInternalServerError)
194+
return
195+
}
196+
197+
// Prepare response data
198+
response := struct {
199+
Stargazers []cu.Stargazer `json:"stargazers"`
200+
HasMore bool `json:"has_more"`
201+
TotalCount int `json:"total_count"`
202+
CurrentPage int `json:"current_page"`
203+
NextPage int `json:"nextzz_page,omitempty"`
204+
}{
205+
Stargazers: stargazers,
206+
HasMore: hasMore,
207+
TotalCount: total,
208+
CurrentPage: page,
209+
}
210+
211+
if hasMore {
212+
response.NextPage = page + 1
213+
}
214+
215+
// Set response headers
216+
w.Header().Set("Content-Type", "application/json")
217+
218+
// Encode and send response
219+
if err := json.NewEncoder(w).Encode(response); err != nil {
220+
http.Error(w, "Error encoding response", http.StatusInternalServerError)
221+
return
222+
}
223+
}

handlers/static.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,17 @@ func ServerStartPage(w http.ResponseWriter, r *http.Request) {
2121
return
2222
}
2323
}
24+
func ServerParticipantPage(w http.ResponseWriter, r *http.Request) {
25+
if r.URL.Path == "/participants" {
26+
http.ServeFile(w, r, "./web/participants.html")
27+
return
28+
}
29+
}
30+
31+
func ServerStargazersPage(w http.ResponseWriter, r *http.Request) {
32+
if r.URL.Path == "/stargazers" {
33+
http.ServeFile(w, r, "./web/stargazers.html")
34+
return
35+
}
36+
http.NotFound(w, r)
37+
}

0 commit comments

Comments
 (0)