Files
2025-12-18 12:29:20 -06:00

99 lines
2.5 KiB
Go

package handlers
import (
"database/sql"
"html/template"
"net/http"
"atcr.io/pkg/appview/db"
"atcr.io/pkg/atproto"
"github.com/go-chi/chi/v5"
)
// UserPageHandler handles the public user page showing all images for a user
type UserPageHandler struct {
DB *sql.DB
Templates *template.Template
RegistryURL string
}
func (h *UserPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
identifier := chi.URLParam(r, "handle")
// Resolve identifier (handle or DID) to canonical DID and current handle
did, resolvedHandle, pdsEndpoint, err := atproto.ResolveIdentity(r.Context(), identifier)
if err != nil {
http.Error(w, "User not found", http.StatusNotFound)
return
}
// Look up user by DID
viewedUser, err := db.GetUserByDID(h.DB, did)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
hasProfile := true
if viewedUser == nil {
// Valid ATProto user but hasn't set up ATCR profile
hasProfile = false
viewedUser = &db.User{
DID: did,
Handle: resolvedHandle,
PDSEndpoint: pdsEndpoint,
// Avatar intentionally empty - template shows '?' placeholder
}
} else if viewedUser.Handle != resolvedHandle {
// Opportunistically update cached handle if it changed
_ = db.UpdateUserHandle(h.DB, did, resolvedHandle)
viewedUser.Handle = resolvedHandle
}
// Fetch repositories for this user
repos, err := db.GetUserRepositories(h.DB, viewedUser.DID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Convert to RepoCardData for template
cards := make([]db.RepoCardData, 0, len(repos))
for _, repo := range repos {
stats, err := db.GetRepositoryStats(h.DB, viewedUser.DID, repo.Name)
if err != nil {
// Continue with zero stats on error
stats = &db.RepositoryStats{
DID: viewedUser.DID,
Repository: repo.Name,
}
}
cards = append(cards, db.RepoCardData{
OwnerHandle: viewedUser.Handle,
Repository: repo.Name,
Title: repo.Title,
Description: repo.Description,
IconURL: repo.IconURL,
StarCount: stats.StarCount,
PullCount: stats.PullCount,
})
}
data := struct {
PageData
ViewedUser *db.User // User whose page we're viewing
Repositories []db.RepoCardData
HasProfile bool
}{
PageData: NewPageData(r, h.RegistryURL),
ViewedUser: viewedUser,
Repositories: cards,
HasProfile: hasProfile,
}
if err := h.Templates.ExecuteTemplate(w, "user", data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}