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
··· 3 import ( 4 "errors" 5 "fmt" 6 - "log" 7 "net/http" 8 "strconv" 9 "time" ··· 30 PendingProfileUpdate string = "pending_profile_update" 31 ) 32 33 - func parseProfileForm(r *http.Request) (db.Profile, error) { 34 err := r.ParseForm() 35 if err != nil { 36 return db.Profile{}, fmt.Errorf("invalid profile form: %w", err) ··· 45 for _, code := range languageCodes { 46 language, ok := db.Languages[db.LanguageCode(code)] 47 if !ok { 48 - log.Printf("invalid language code submitted: %s", code) 49 continue 50 } 51 languages = append(languages, language) ··· 62 } 63 64 func (h *Handler) HandleProfilePage(w http.ResponseWriter, r *http.Request) { 65 didOrHandle := chi.URLParam(r, "user") 66 if didOrHandle == "" { 67 http.Error(w, "Bad request", http.StatusBadRequest) ··· 102 103 totalStudyTime, err = db.GetTotalStudyTime(h.Db, profileDid) 104 if err != nil { 105 - log.Println("failed to get total study time:", err) 106 } 107 108 totalStudySessions, _ = db.GetTotalStudySessions(h.Db, profileDid) 109 if err != nil { 110 - log.Println("failed to get total study study sessions:", err) 111 } 112 113 followers, following, _ = db.GetFollowerFollowingCount(h.Db, profileDid) 114 if err != nil { 115 - log.Println("failed to get follow stats:", err) 116 } 117 118 streak, _ = db.GetCurrentStreak(h.Db, profileDid) 119 if err != nil { 120 - log.Println("failed to get streak:", err) 121 } 122 123 if user != nil { ··· 128 }) 129 130 if err := g.Wait(); err != nil { 131 - log.Printf("failed to fetch critical profile data for %s: %v", profileDid, err) 132 htmx.HxError(w, http.StatusInternalServerError, "Failed to fetch profile data, try again later.") 133 return 134 } ··· 160 161 err := h.Posthog.Enqueue(capture) 162 if err != nil { 163 - log.Println("failed to enqueue posthog event:", err) 164 } 165 } 166 ··· 178 } 179 180 func (h *Handler) HandleEditProfilePage(w http.ResponseWriter, r *http.Request) { 181 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 182 if err != nil { 183 - log.Println("failed to get logged-in user:", err) 184 htmx.HxRedirect(w, "/login") 185 return 186 } 187 188 profile, err := h.GetUserProfileWithAvatar(user.Did) 189 if err != nil { 190 - log.Printf("failed to find %s in db: %s", user.Did, err) 191 w.WriteHeader(http.StatusNotFound) 192 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 193 return 194 } 195 196 if user.Did != profile.Did { 197 - log.Printf("user '%s' does not own record '%s'", user.Did, profile.Did) 198 htmx.HxError(w, http.StatusUnauthorized, "You do not have permissions to edit this profile.") 199 return 200 } ··· 214 case http.MethodPost: 215 client, err := h.Oauth.AuthorizedClient(r) 216 if err != nil { 217 - log.Println("failed to get authorized client:", err) 218 htmx.HxRedirect(w, "/login") 219 return 220 } 221 222 - updatedProfile, err := parseProfileForm(r) 223 if err != nil { 224 - log.Println("invalid profile form:", err) 225 htmx.HxError(w, http.StatusBadRequest, "Failed to update profile, ensure all fields contain valid data.") 226 return 227 } ··· 236 } 237 238 if err := db.ValidateProfile(updatedProfile); err != nil { 239 - log.Println("invalid profile:", err) 240 switch { 241 case errors.Is(err, db.ErrProfileNameTooLong): 242 htmx.HxError(w, http.StatusBadRequest, "Profile name cannot be more than 64 characters.") ··· 280 SwapRecord: cid, 281 }) 282 if err != nil { 283 - log.Println("failed to put profile record:", err) 284 htmx.HxError(w, http.StatusInternalServerError, "Failed to update PDS, try again later.") 285 return 286 } 287 288 err = SavePendingUpdate(h, w, r, PendingProfileUpdate, profile) 289 if err != nil { 290 - log.Printf("failed to save yoten-session to add pending profile update: %v", err) 291 } 292 293 if !h.Config.Core.Dev { ··· 308 Properties: properties, 309 }) 310 if err != nil { 311 - log.Println("failed to enqueue posthog identify event:", err) 312 } 313 314 err = h.Posthog.Enqueue(posthog.Capture{ ··· 316 Event: ph.ProfileRecordEditedEvent, 317 }) 318 if err != nil { 319 - log.Println("failed to enqueue posthog event:", err) 320 } 321 } 322 ··· 325 } 326 327 func (h *Handler) HandleResourcesPage(w http.ResponseWriter, r *http.Request) { 328 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 329 if err != nil { 330 - log.Println("failed to get logged-in user:", err) 331 htmx.HxRedirect(w, "/login") 332 return 333 } 334 335 resources, err := db.GetResourcesByDid(h.Db, user.Did) 336 if err != nil { 337 - log.Println("failed to get resources:", err) 338 htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile resources, try again later.") 339 return 340 } 341 342 resources, err = ApplyPendingChanges(h, w, r, resources, PendingResourceCreation, PendingResourceUpdates, PendingResourceDeletion) 343 if err != nil { 344 - log.Printf("failed to save yoten-session after processing pending changes: %v", err) 345 } 346 347 activeResources := utils.Filter(resources, func(resource db.Resource) bool { ··· 355 } 356 357 func (h *Handler) HandleActivitiesPage(w http.ResponseWriter, r *http.Request) { 358 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 359 if err != nil { 360 - log.Println("failed to get logged-in user:", err) 361 htmx.HxRedirect(w, "/login") 362 return 363 } 364 365 activities, err := db.GetActivitiesByDid(h.Db, user.Did) 366 if err != nil { 367 - log.Println("failed to get activities:", err) 368 htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile activities, try again later.") 369 return 370 } 371 372 activities, err = ApplyPendingChanges(h, w, r, activities, PendingActivityCreation, PendingActivityUpdates, PendingActivityDeletion) 373 if err != nil { 374 - log.Printf("failed to save yoten-session after processing pending changes: %v", err) 375 } 376 377 activeActivities := utils.Filter(activities, func(activity db.Activity) bool { ··· 400 } 401 402 func (h *Handler) HandleProfileFeed(w http.ResponseWriter, r *http.Request) { 403 didOrHandle := chi.URLParam(r, "user") 404 if didOrHandle == "" { 405 http.Error(w, "Bad request", http.StatusBadRequest) ··· 415 416 profile, err := h.GetUserProfileWithAvatar(ident.DID.String()) 417 if err != nil { 418 - log.Printf("failed to find %s in db: %s", ident.DID.String(), err) 419 w.WriteHeader(http.StatusNotFound) 420 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 421 return ··· 423 424 bskyProfile, err := bsky.GetBskyProfile(ident.DID.String()) 425 if err != nil { 426 - log.Println("failed to get bsky profile:", err) 427 w.WriteHeader(http.StatusNotFound) 428 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 429 return ··· 435 } 436 page, err := strconv.ParseInt(pageStr, 10, 64) 437 if err != nil { 438 - log.Println("failed to parse page value:", err) 439 page = 1 440 } 441 if page == 0 { ··· 447 448 sessions, err := db.GetStudySessionLogs(h.Db, ident.DID.String(), pageSize+1, int(offset)) 449 if err != nil { 450 - log.Println("failed to get study sessions:", err) 451 w.WriteHeader(http.StatusNotFound) 452 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 453 return ··· 455 456 sessions, err = ApplyPendingChanges(h, w, r, sessions, PendingStudySessionCreation, PendingStudySessionUpdates, PendingStudySessionDeletion) 457 if err != nil { 458 - log.Printf("failed to save yoten-session after processing pending changes: %v", err) 459 } 460 461 feed := []*db.StudySessionFeedItem{} ··· 493 } 494 495 func (h *Handler) HandleFriendsPage(w http.ResponseWriter, r *http.Request) { 496 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 497 if err != nil { 498 - log.Println("failed to get logged-in user:", err) 499 htmx.HxRedirect(w, "/login") 500 return 501 } 502 503 followers, following, err := db.GetFollowerFollowingCount(h.Db, user.Did) 504 if err != nil { 505 - log.Printf("getting follow stats repos for %s: %s", user.Did, err) 506 } 507 508 views.FriendsPage(views.FriendsPageParams{ ··· 513 } 514 515 func (h *Handler) HandleFriendsFeed(w http.ResponseWriter, r *http.Request) { 516 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 517 if err != nil { 518 - log.Println("failed to get logged-in user") 519 htmx.HxRedirect(w, "/login") 520 return 521 } ··· 529 } 530 page, err := strconv.ParseInt(pageStr, 10, 64) 531 if err != nil { 532 - log.Println("failed to parse page value:", err) 533 page = 1 534 } 535 if page == 0 { ··· 545 if mode == partials.Following { 546 feed, err := db.GetFollowing(h.Db, user.Did, pageSize+1, int(offset)) 547 if err != nil { 548 - log.Println("failed to get following list:", err) 549 htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.") 550 return 551 } 552 bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed) 553 if err != nil { 554 - log.Println("failed to hydrate bsky profiles:", err) 555 htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.") 556 return 557 } 558 } else { 559 feed, err := db.GetFollowers(h.Db, user.Did, pageSize+1, int(offset)) 560 if err != nil { 561 - log.Println("failed to get followers list:", err) 562 htmx.HxError(w, http.StatusInternalServerError, "Failed to get followers list, try again later.") 563 return 564 } 565 bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed) 566 if err != nil { 567 - log.Println("failed to hydrate bsky profiles:", err) 568 htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.") 569 return 570 } ··· 586 } 587 588 func (h *Handler) HandleNotificationsPage(w http.ResponseWriter, r *http.Request) { 589 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 590 if err != nil { 591 - log.Println("failed to get logged-in user:", err) 592 htmx.HxRedirect(w, "/login") 593 return 594 }
··· 3 import ( 4 "errors" 5 "fmt" 6 + "log/slog" 7 "net/http" 8 "strconv" 9 "time" ··· 30 PendingProfileUpdate string = "pending_profile_update" 31 ) 32 33 + func parseProfileForm(r *http.Request, logger *slog.Logger) (db.Profile, error) { 34 err := r.ParseForm() 35 if err != nil { 36 return db.Profile{}, fmt.Errorf("invalid profile form: %w", err) ··· 45 for _, code := range languageCodes { 46 language, ok := db.Languages[db.LanguageCode(code)] 47 if !ok { 48 + logger.Warn("invalid language code submitted", "languageCode", code) 49 continue 50 } 51 languages = append(languages, language) ··· 62 } 63 64 func (h *Handler) HandleProfilePage(w http.ResponseWriter, r *http.Request) { 65 + l := h.Logger.With("handler", "HandleProfilePage") 66 + 67 didOrHandle := chi.URLParam(r, "user") 68 if didOrHandle == "" { 69 http.Error(w, "Bad request", http.StatusBadRequest) ··· 104 105 totalStudyTime, err = db.GetTotalStudyTime(h.Db, profileDid) 106 if err != nil { 107 + l.Error("failed to get total study time", "err", err) 108 } 109 110 totalStudySessions, _ = db.GetTotalStudySessions(h.Db, profileDid) 111 if err != nil { 112 + l.Error("failed to get total study study sessions", "err", err) 113 } 114 115 followers, following, _ = db.GetFollowerFollowingCount(h.Db, profileDid) 116 if err != nil { 117 + l.Error("failed to get follow stats", "err", err) 118 } 119 120 streak, _ = db.GetCurrentStreak(h.Db, profileDid) 121 if err != nil { 122 + l.Error("failed to get streak", "err", err) 123 } 124 125 if user != nil { ··· 130 }) 131 132 if err := g.Wait(); err != nil { 133 + l.Error("failed to fetch critical profile data for", "did", profileDid, "err", err) 134 htmx.HxError(w, http.StatusInternalServerError, "Failed to fetch profile data, try again later.") 135 return 136 } ··· 162 163 err := h.Posthog.Enqueue(capture) 164 if err != nil { 165 + l.Error("failed to enqueue posthog event", "err", err) 166 } 167 } 168 ··· 180 } 181 182 func (h *Handler) HandleEditProfilePage(w http.ResponseWriter, r *http.Request) { 183 + l := h.Logger.With("handler", "HandleEditProfilePage") 184 + 185 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 186 if err != nil { 187 + l.Error("failed to get logged-in user", "err", err) 188 htmx.HxRedirect(w, "/login") 189 return 190 } 191 192 profile, err := h.GetUserProfileWithAvatar(user.Did) 193 if err != nil { 194 + l.Error("failed to find user in db", "did", user.Did, "err", err) 195 w.WriteHeader(http.StatusNotFound) 196 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 197 return 198 } 199 200 if user.Did != profile.Did { 201 + l.Error("user does not own record", "did", user.Did, "profileDid", profile.Did) 202 htmx.HxError(w, http.StatusUnauthorized, "You do not have permissions to edit this profile.") 203 return 204 } ··· 218 case http.MethodPost: 219 client, err := h.Oauth.AuthorizedClient(r) 220 if err != nil { 221 + l.Error("failed to get authorized client", "err", err) 222 htmx.HxRedirect(w, "/login") 223 return 224 } 225 226 + updatedProfile, err := parseProfileForm(r, l) 227 if err != nil { 228 + l.Error("invalid profile form", "err", err) 229 htmx.HxError(w, http.StatusBadRequest, "Failed to update profile, ensure all fields contain valid data.") 230 return 231 } ··· 240 } 241 242 if err := db.ValidateProfile(updatedProfile); err != nil { 243 + l.Error("invalid profile", "err", err) 244 switch { 245 case errors.Is(err, db.ErrProfileNameTooLong): 246 htmx.HxError(w, http.StatusBadRequest, "Profile name cannot be more than 64 characters.") ··· 284 SwapRecord: cid, 285 }) 286 if err != nil { 287 + l.Error("failed to put profile record", "err", err) 288 htmx.HxError(w, http.StatusInternalServerError, "Failed to update PDS, try again later.") 289 return 290 } 291 292 err = SavePendingUpdate(h, w, r, PendingProfileUpdate, profile) 293 if err != nil { 294 + l.Error("failed to save yoten-session to add pending profile update", "err", err) 295 } 296 297 if !h.Config.Core.Dev { ··· 312 Properties: properties, 313 }) 314 if err != nil { 315 + l.Error("failed to enqueue posthog identify event", "err", err) 316 } 317 318 err = h.Posthog.Enqueue(posthog.Capture{ ··· 320 Event: ph.ProfileRecordEditedEvent, 321 }) 322 if err != nil { 323 + l.Error("failed to enqueue posthog event", "err", err) 324 } 325 } 326 ··· 329 } 330 331 func (h *Handler) HandleResourcesPage(w http.ResponseWriter, r *http.Request) { 332 + l := h.Logger.With("handler", "HandleResourcesPage") 333 + 334 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 335 if err != nil { 336 + l.Error("failed to get logged-in user", "err", err) 337 htmx.HxRedirect(w, "/login") 338 return 339 } 340 341 resources, err := db.GetResourcesByDid(h.Db, user.Did) 342 if err != nil { 343 + l.Error("failed to get resources", "err", err) 344 htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile resources, try again later.") 345 return 346 } 347 348 resources, err = ApplyPendingChanges(h, w, r, resources, PendingResourceCreation, PendingResourceUpdates, PendingResourceDeletion) 349 if err != nil { 350 + l.Error("failed to save yoten-session after processing pending changes", "err", err) 351 } 352 353 activeResources := utils.Filter(resources, func(resource db.Resource) bool { ··· 361 } 362 363 func (h *Handler) HandleActivitiesPage(w http.ResponseWriter, r *http.Request) { 364 + l := h.Logger.With("handler", "HandleActivitiesPage") 365 + 366 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 367 if err != nil { 368 + l.Error("failed to get logged-in user", "err", err) 369 htmx.HxRedirect(w, "/login") 370 return 371 } 372 373 activities, err := db.GetActivitiesByDid(h.Db, user.Did) 374 if err != nil { 375 + l.Error("failed to get activities", "err", err) 376 htmx.HxError(w, http.StatusInternalServerError, "Failed to retrieve profile activities, try again later.") 377 return 378 } 379 380 activities, err = ApplyPendingChanges(h, w, r, activities, PendingActivityCreation, PendingActivityUpdates, PendingActivityDeletion) 381 if err != nil { 382 + l.Error("failed to save yoten-session after processing pending changes", "err", err) 383 } 384 385 activeActivities := utils.Filter(activities, func(activity db.Activity) bool { ··· 408 } 409 410 func (h *Handler) HandleProfileFeed(w http.ResponseWriter, r *http.Request) { 411 + l := h.Logger.With("handler", "HandleProfileFeed") 412 + 413 didOrHandle := chi.URLParam(r, "user") 414 if didOrHandle == "" { 415 http.Error(w, "Bad request", http.StatusBadRequest) ··· 425 426 profile, err := h.GetUserProfileWithAvatar(ident.DID.String()) 427 if err != nil { 428 + l.Error("failed to find user in db", "did", ident.DID.String(), "err", err) 429 w.WriteHeader(http.StatusNotFound) 430 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 431 return ··· 433 434 bskyProfile, err := bsky.GetBskyProfile(ident.DID.String()) 435 if err != nil { 436 + l.Error("failed to get bsky profile", "err", err) 437 w.WriteHeader(http.StatusNotFound) 438 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 439 return ··· 445 } 446 page, err := strconv.ParseInt(pageStr, 10, 64) 447 if err != nil { 448 + l.Error("failed to parse page value", "err", err) 449 page = 1 450 } 451 if page == 0 { ··· 457 458 sessions, err := db.GetStudySessionLogs(h.Db, ident.DID.String(), pageSize+1, int(offset)) 459 if err != nil { 460 + l.Error("failed to get study sessions", "err", err) 461 w.WriteHeader(http.StatusNotFound) 462 views.NotFoundPage(views.NotFoundPageParams{}).Render(r.Context(), w) 463 return ··· 465 466 sessions, err = ApplyPendingChanges(h, w, r, sessions, PendingStudySessionCreation, PendingStudySessionUpdates, PendingStudySessionDeletion) 467 if err != nil { 468 + l.Error("failed to save yoten-session after processing pending changes", "err", err) 469 } 470 471 feed := []*db.StudySessionFeedItem{} ··· 503 } 504 505 func (h *Handler) HandleFriendsPage(w http.ResponseWriter, r *http.Request) { 506 + l := h.Logger.With("handler", "HandleFriendsPage") 507 + 508 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 509 if err != nil { 510 + l.Error("failed to get logged-in user", "err", err) 511 htmx.HxRedirect(w, "/login") 512 return 513 } 514 515 followers, following, err := db.GetFollowerFollowingCount(h.Db, user.Did) 516 if err != nil { 517 + l.Error("failed to get follow stats", "err", err) 518 } 519 520 views.FriendsPage(views.FriendsPageParams{ ··· 525 } 526 527 func (h *Handler) HandleFriendsFeed(w http.ResponseWriter, r *http.Request) { 528 + l := h.Logger.With("handler", "HandleFriendsFeed") 529 + 530 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 531 if err != nil { 532 + l.Error("failed to get logged-in user") 533 htmx.HxRedirect(w, "/login") 534 return 535 } ··· 543 } 544 page, err := strconv.ParseInt(pageStr, 10, 64) 545 if err != nil { 546 + l.Error("failed to parse page value", "err", err) 547 page = 1 548 } 549 if page == 0 { ··· 559 if mode == partials.Following { 560 feed, err := db.GetFollowing(h.Db, user.Did, pageSize+1, int(offset)) 561 if err != nil { 562 + l.Error("failed to get following list", "err", err) 563 htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.") 564 return 565 } 566 bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed) 567 if err != nil { 568 + l.Error("failed to hydrate bsky profiles", "err", err) 569 htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.") 570 return 571 } 572 } else { 573 feed, err := db.GetFollowers(h.Db, user.Did, pageSize+1, int(offset)) 574 if err != nil { 575 + l.Error("failed to get followers list", "err", err) 576 htmx.HxError(w, http.StatusInternalServerError, "Failed to get followers list, try again later.") 577 return 578 } 579 bskyHydratedFeed, err = h.GetHydratedFollowerProfiles(feed) 580 if err != nil { 581 + l.Error("failed to hydrate bsky profiles", "err", err) 582 htmx.HxError(w, http.StatusInternalServerError, "Failed to get following list, try again later.") 583 return 584 } ··· 600 } 601 602 func (h *Handler) HandleNotificationsPage(w http.ResponseWriter, r *http.Request) { 603 + l := h.Logger.With("handler", "HandleNotificationsPage") 604 + 605 user, err := bsky.GetUserWithBskyProfile(h.Oauth, r) 606 if err != nil { 607 + l.Error("failed to get logged-in user", "err", err) 608 htmx.HxRedirect(w, "/login") 609 return 610 }