feat(handlers/profile): use slogger #15

merged
opened by brookjeynes.dev targeting master from push-trrpxxyxxmot
Changed files
+56 -40
internal
server
handlers
+56 -40
internal/server/handlers/profile.go
···
import (
"errors"
"fmt"
-
"log"
"net/http"
"strconv"
"time"
···
PendingProfileUpdate string = "pending_profile_update"
)
-
func parseProfileForm(r *http.Request) (db.Profile, error) {
err := r.ParseForm()
if err != nil {
return db.Profile{}, fmt.Errorf("invalid profile form: %w", err)
···
for _, code := range languageCodes {
language, ok := db.Languages[db.LanguageCode(code)]
if !ok {
-
log.Printf("invalid language code submitted: %s", code)
continue
}
languages = append(languages, language)
···
}
func (h *Handler) HandleProfilePage(w http.ResponseWriter, r *http.Request) {
didOrHandle := chi.URLParam(r, "user")
if didOrHandle == "" {
http.Error(w, "Bad request", http.StatusBadRequest)
···
totalStudyTime, err = db.GetTotalStudyTime(h.Db, profileDid)
if err != nil {
-
log.Println("failed to get total study time:", err)
}
totalStudySessions, _ = db.GetTotalStudySessions(h.Db, profileDid)
if err != nil {
-
log.Println("failed to get total study study sessions:", err)
}
followers, following, _ = db.GetFollowerFollowingCount(h.Db, profileDid)
if err != nil {
-
log.Println("failed to get follow stats:", err)
}
streak, _ = db.GetCurrentStreak(h.Db, profileDid)
if err != nil {
-
log.Println("failed to get streak:", err)
}
if user != nil {
···
})
if err := g.Wait(); err != nil {
-
log.Printf("failed to fetch critical profile data for %s: %v", profileDid, err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to fetch profile data, try again later.")
return
}
···
err := h.Posthog.Enqueue(capture)
if err != nil {
-
log.Println("failed to enqueue posthog event:", err)
}
}
···
}
func (h *Handler) HandleEditProfilePage(w http.ResponseWriter, r *http.Request) {
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
-
log.Println("failed to get logged-in user:", err)
htmx.HxRedirect(w, "/login")
return
}
profile, err := h.GetUserProfileWithAvatar(user.Did)
if err != nil {
-
log.Printf("failed to find %s in db: %s", user.Did, err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
}
if user.Did != profile.Did {
-
log.Printf("user '%s' does not own record '%s'", user.Did, profile.Did)
htmx.HxError(w, http.StatusUnauthorized, "You do not have permissions to edit this profile.")
return
}
···
case http.MethodPost:
client, err := h.Oauth.AuthorizedClient(r)
if err != nil {
-
log.Println("failed to get authorized client:", err)
htmx.HxRedirect(w, "/login")
return
}
-
updatedProfile, err := parseProfileForm(r)
if err != nil {
-
log.Println("invalid profile form:", err)
htmx.HxError(w, http.StatusBadRequest, "Failed to update profile, ensure all fields contain valid data.")
return
}
···
}
if err := db.ValidateProfile(updatedProfile); err != nil {
-
log.Println("invalid profile:", err)
switch {
case errors.Is(err, db.ErrProfileNameTooLong):
htmx.HxError(w, http.StatusBadRequest, "Profile name cannot be more than 64 characters.")
···
SwapRecord: cid,
})
if err != nil {
-
log.Println("failed to put profile record:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to update PDS, try again later.")
return
}
err = SavePendingUpdate(h, w, r, PendingProfileUpdate, profile)
if err != nil {
-
log.Printf("failed to save yoten-session to add pending profile update: %v", err)
}
if !h.Config.Core.Dev {
···
Properties: properties,
})
if err != nil {
-
log.Println("failed to enqueue posthog identify event:", err)
}
err = h.Posthog.Enqueue(posthog.Capture{
···
Event: ph.ProfileRecordEditedEvent,
})
if err != nil {
-
log.Println("failed to enqueue posthog event:", err)
}
}
···
}
func (h *Handler) HandleResourcesPage(w http.ResponseWriter, r *http.Request) {
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
-
log.Println("failed to get logged-in user:", err)
htmx.HxRedirect(w, "/login")
return
}
resources, err := db.GetResourcesByDid(h.Db, user.Did)
if err != nil {
-
log.Println("failed to get resources:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile resources, try again later.")
return
}
resources, err = ApplyPendingChanges(h, w, r, resources, PendingResourceCreation, PendingResourceUpdates, PendingResourceDeletion)
if err != nil {
-
log.Printf("failed to save yoten-session after processing pending changes: %v", err)
}
activeResources := utils.Filter(resources, func(resource db.Resource) bool {
···
}
func (h *Handler) HandleActivitiesPage(w http.ResponseWriter, r *http.Request) {
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
-
log.Println("failed to get logged-in user:", err)
htmx.HxRedirect(w, "/login")
return
}
activities, err := db.GetActivitiesByDid(h.Db, user.Did)
if err != nil {
-
log.Println("failed to get activities:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile activities, try again later.")
return
}
activities, err = ApplyPendingChanges(h, w, r, activities, PendingActivityCreation, PendingActivityUpdates, PendingActivityDeletion)
if err != nil {
-
log.Printf("failed to save yoten-session after processing pending changes: %v", err)
}
activeActivities := utils.Filter(activities, func(activity db.Activity) bool {
···
}
func (h *Handler) HandleProfileFeed(w http.ResponseWriter, r *http.Request) {
didOrHandle := chi.URLParam(r, "user")
if didOrHandle == "" {
http.Error(w, "Bad request", http.StatusBadRequest)
···
profile, err := h.GetUserProfileWithAvatar(ident.DID.String())
if err != nil {
-
log.Printf("failed to find %s in db: %s", ident.DID.String(), err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
···
bskyProfile, err := bsky.GetBskyProfile(ident.DID.String())
if err != nil {
-
log.Println("failed to get bsky profile:", err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
···
}
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil {
-
log.Println("failed to parse page value:", err)
page = 1
}
if page == 0 {
···
sessions, err := db.GetStudySessionLogs(h.Db, ident.DID.String(), pageSize+1, int(offset))
if err != nil {
-
log.Println("failed to get study sessions:", err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
···
sessions, err = ApplyPendingChanges(h, w, r, sessions, PendingStudySessionCreation, PendingStudySessionUpdates, PendingStudySessionDeletion)
if err != nil {
-
log.Printf("failed to save yoten-session after processing pending changes: %v", err)
}
feed := []*db.StudySessionFeedItem{}
···
}
func (h *Handler) HandleFriendsPage(w http.ResponseWriter, r *http.Request) {
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
-
log.Println("failed to get logged-in user:", err)
htmx.HxRedirect(w, "/login")
return
}
followers, following, err := db.GetFollowerFollowingCount(h.Db, user.Did)
if err != nil {
-
log.Printf("getting follow stats repos for %s: %s", user.Did, err)
}
views.FriendsPage(views.FriendsPageParams{
···
}
func (h *Handler) HandleFriendsFeed(w http.ResponseWriter, r *http.Request) {
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
-
log.Println("failed to get logged-in user")
htmx.HxRedirect(w, "/login")
return
}
···
}
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil {
-
log.Println("failed to parse page value:", err)
page = 1
}
if page == 0 {
···
if mode == partials.Following {
feed, err := db.GetFollowing(h.Db, user.Did, pageSize+1, int(offset))
if err != nil {
-
log.Println("failed to get following list:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.")
return
}
bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed)
if err != nil {
-
log.Println("failed to hydrate bsky profiles:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.")
return
}
} else {
feed, err := db.GetFollowers(h.Db, user.Did, pageSize+1, int(offset))
if err != nil {
-
log.Println("failed to get followers list:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get followers list, try again later.")
return
}
bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed)
if err != nil {
-
log.Println("failed to hydrate bsky profiles:", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.")
return
}
···
}
func (h *Handler) HandleNotificationsPage(w http.ResponseWriter, r *http.Request) {
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
-
log.Println("failed to get logged-in user:", err)
htmx.HxRedirect(w, "/login")
return
}
···
import (
"errors"
"fmt"
+
"log/slog"
"net/http"
"strconv"
"time"
···
PendingProfileUpdate string = "pending_profile_update"
)
+
func parseProfileForm(r *http.Request, logger *slog.Logger) (db.Profile, error) {
err := r.ParseForm()
if err != nil {
return db.Profile{}, fmt.Errorf("invalid profile form: %w", err)
···
for _, code := range languageCodes {
language, ok := db.Languages[db.LanguageCode(code)]
if !ok {
+
logger.Warn("invalid language code submitted", "languageCode", code)
continue
}
languages = append(languages, language)
···
}
func (h *Handler) HandleProfilePage(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleProfilePage")
+
didOrHandle := chi.URLParam(r, "user")
if didOrHandle == "" {
http.Error(w, "Bad request", http.StatusBadRequest)
···
totalStudyTime, err = db.GetTotalStudyTime(h.Db, profileDid)
if err != nil {
+
l.Error("failed to get total study time", "err", err)
}
totalStudySessions, _ = db.GetTotalStudySessions(h.Db, profileDid)
if err != nil {
+
l.Error("failed to get total study study sessions", "err", err)
}
followers, following, _ = db.GetFollowerFollowingCount(h.Db, profileDid)
if err != nil {
+
l.Error("failed to get follow stats", "err", err)
}
streak, _ = db.GetCurrentStreak(h.Db, profileDid)
if err != nil {
+
l.Error("failed to get streak", "err", err)
}
if user != nil {
···
})
if err := g.Wait(); err != nil {
+
l.Error("failed to fetch critical profile data for", "did", profileDid, "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to fetch profile data, try again later.")
return
}
···
err := h.Posthog.Enqueue(capture)
if err != nil {
+
l.Error("failed to enqueue posthog event", "err", err)
}
}
···
}
func (h *Handler) HandleEditProfilePage(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleEditProfilePage")
+
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
+
l.Error("failed to get logged-in user", "err", err)
htmx.HxRedirect(w, "/login")
return
}
profile, err := h.GetUserProfileWithAvatar(user.Did)
if err != nil {
+
l.Error("failed to find user in db", "did", user.Did, "err", err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
}
if user.Did != profile.Did {
+
l.Error("user does not own record", "did", user.Did, "profileDid", profile.Did)
htmx.HxError(w, http.StatusUnauthorized, "You do not have permissions to edit this profile.")
return
}
···
case http.MethodPost:
client, err := h.Oauth.AuthorizedClient(r)
if err != nil {
+
l.Error("failed to get authorized client", "err", err)
htmx.HxRedirect(w, "/login")
return
}
+
updatedProfile, err := parseProfileForm(r, l)
if err != nil {
+
l.Error("invalid profile form", "err", err)
htmx.HxError(w, http.StatusBadRequest, "Failed to update profile, ensure all fields contain valid data.")
return
}
···
}
if err := db.ValidateProfile(updatedProfile); err != nil {
+
l.Error("invalid profile", "err", err)
switch {
case errors.Is(err, db.ErrProfileNameTooLong):
htmx.HxError(w, http.StatusBadRequest, "Profile name cannot be more than 64 characters.")
···
SwapRecord: cid,
})
if err != nil {
+
l.Error("failed to put profile record", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to update PDS, try again later.")
return
}
err = SavePendingUpdate(h, w, r, PendingProfileUpdate, profile)
if err != nil {
+
l.Error("failed to save yoten-session to add pending profile update", "err", err)
}
if !h.Config.Core.Dev {
···
Properties: properties,
})
if err != nil {
+
l.Error("failed to enqueue posthog identify event", "err", err)
}
err = h.Posthog.Enqueue(posthog.Capture{
···
Event: ph.ProfileRecordEditedEvent,
})
if err != nil {
+
l.Error("failed to enqueue posthog event", "err", err)
}
}
···
}
func (h *Handler) HandleResourcesPage(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleResourcesPage")
+
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
+
l.Error("failed to get logged-in user", "err", err)
htmx.HxRedirect(w, "/login")
return
}
resources, err := db.GetResourcesByDid(h.Db, user.Did)
if err != nil {
+
l.Error("failed to get resources", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile resources, try again later.")
return
}
resources, err = ApplyPendingChanges(h, w, r, resources, PendingResourceCreation, PendingResourceUpdates, PendingResourceDeletion)
if err != nil {
+
l.Error("failed to save yoten-session after processing pending changes", "err", err)
}
activeResources := utils.Filter(resources, func(resource db.Resource) bool {
···
}
func (h *Handler) HandleActivitiesPage(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleActivitiesPage")
+
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
+
l.Error("failed to get logged-in user", "err", err)
htmx.HxRedirect(w, "/login")
return
}
activities, err := db.GetActivitiesByDid(h.Db, user.Did)
if err != nil {
+
l.Error("failed to get activities", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile activities, try again later.")
return
}
activities, err = ApplyPendingChanges(h, w, r, activities, PendingActivityCreation, PendingActivityUpdates, PendingActivityDeletion)
if err != nil {
+
l.Error("failed to save yoten-session after processing pending changes", "err", err)
}
activeActivities := utils.Filter(activities, func(activity db.Activity) bool {
···
}
func (h *Handler) HandleProfileFeed(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleProfileFeed")
+
didOrHandle := chi.URLParam(r, "user")
if didOrHandle == "" {
http.Error(w, "Bad request", http.StatusBadRequest)
···
profile, err := h.GetUserProfileWithAvatar(ident.DID.String())
if err != nil {
+
l.Error("failed to find user in db", "did", ident.DID.String(), "err", err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
···
bskyProfile, err := bsky.GetBskyProfile(ident.DID.String())
if err != nil {
+
l.Error("failed to get bsky profile", "err", err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
···
}
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil {
+
l.Error("failed to parse page value", "err", err)
page = 1
}
if page == 0 {
···
sessions, err := db.GetStudySessionLogs(h.Db, ident.DID.String(), pageSize+1, int(offset))
if err != nil {
+
l.Error("failed to get study sessions", "err", err)
w.WriteHeader(http.StatusNotFound)
views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w)
return
···
sessions, err = ApplyPendingChanges(h, w, r, sessions, PendingStudySessionCreation, PendingStudySessionUpdates, PendingStudySessionDeletion)
if err != nil {
+
l.Error("failed to save yoten-session after processing pending changes", "err", err)
}
feed := []*db.StudySessionFeedItem{}
···
}
func (h *Handler) HandleFriendsPage(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleFriendsPage")
+
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
+
l.Error("failed to get logged-in user", "err", err)
htmx.HxRedirect(w, "/login")
return
}
followers, following, err := db.GetFollowerFollowingCount(h.Db, user.Did)
if err != nil {
+
l.Error("failed to get follow stats", "err", err)
}
views.FriendsPage(views.FriendsPageParams{
···
}
func (h *Handler) HandleFriendsFeed(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleFriendsFeed")
+
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
+
l.Error("failed to get logged-in user")
htmx.HxRedirect(w, "/login")
return
}
···
}
page, err := strconv.ParseInt(pageStr, 10, 64)
if err != nil {
+
l.Error("failed to parse page value", "err", err)
page = 1
}
if page == 0 {
···
if mode == partials.Following {
feed, err := db.GetFollowing(h.Db, user.Did, pageSize+1, int(offset))
if err != nil {
+
l.Error("failed to get following list", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.")
return
}
bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed)
if err != nil {
+
l.Error("failed to hydrate bsky profiles", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.")
return
}
} else {
feed, err := db.GetFollowers(h.Db, user.Did, pageSize+1, int(offset))
if err != nil {
+
l.Error("failed to get followers list", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get followers list, try again later.")
return
}
bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed)
if err != nil {
+
l.Error("failed to hydrate bsky profiles", "err", err)
htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.")
return
}
···
}
func (h *Handler) HandleNotificationsPage(w http.ResponseWriter, r *http.Request) {
+
l := h.Logger.With("handler", "HandleNotificationsPage")
+
user, err := bsky.GetUserWithBskyProfile(h.Oauth, r)
if err != nil {
+
l.Error("failed to get logged-in user", "err", err)
htmx.HxRedirect(w, "/login")
return
}