package account import ( "net/http" "net/url" "regexp" "strconv" "code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/log" "code.nonshy.com/nonshy/website/pkg/middleware" "code.nonshy.com/nonshy/website/pkg/models" "code.nonshy.com/nonshy/website/pkg/session" "code.nonshy.com/nonshy/website/pkg/templates" ) var NotesURLRegexp = regexp.MustCompile(`^/notes/u/([^@]+?)$`) // User notes page (/notes/u/username) func UserNotes() http.HandlerFunc { tmpl := templates.Must("account/user_notes.html") return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Parse the username out of the URL parameters. var username string m := NotesURLRegexp.FindStringSubmatch(r.URL.Path) if m != nil { username = m[1] } // Find this user. user, err := models.FindUser(username) if err != nil { templates.NotFoundPage(w, r) return } // Get the current user. currentUser, err := session.CurrentUser(r) if err != nil { session.FlashError(w, r, "You must be signed in to view this page.") templates.Redirect(w, "/login?next="+url.QueryEscape(r.URL.String())) return } // Is the site under a Maintenance Mode restriction? if middleware.MaintenanceMode(currentUser, w, r) { return } // Banned or disabled? Only admin can view then. if user.Status != models.UserStatusActive && !currentUser.IsAdmin { templates.NotFoundPage(w, r) return } // Is either one blocking? if models.IsBlocking(currentUser.ID, user.ID) && !currentUser.IsAdmin { templates.NotFoundPage(w, r) return } // Look up our current note about this person. var myNote = models.GetNoteBetweenUsers(currentUser, user) // Are we submitting a note? if r.Method == http.MethodPost { var message = r.FormValue("message") // Update & save our note. if message == "" { // Delete it. if err := myNote.Delete(); err != nil && err != models.ErrNoUserNoteToDelete { session.FlashError(w, r, "Error deleting your note: %s", err) } else if err == nil { session.Flash(w, r, "Your note was deleted!") } } else { // Update it. myNote.Message = message if err := myNote.Save(); err != nil { session.FlashError(w, r, "Error saving your note: %s", err) } else { session.Flash(w, r, "Your notes have been saved!") } } templates.Redirect(w, r.URL.Path) return } // Admin view: paginate their feedback & reports. var ( feedback = []*models.Feedback{} otherNotes = []*models.UserNote{} userMap = models.UserMap{} notePager = &models.Pagination{ Page: 1, PerPage: config.PageSizeAdminUserNotes, Sort: "updated_at desc", } fbPager = &models.Pagination{ Page: 1, PerPage: config.PageSizeAdminFeedbackNotesPage, Sort: "created_at desc", } ) notePager.ParsePage(r) fbPager.ParsePage(r) if currentUser.IsAdmin { // Paginate all notes written about this user. if on, err := models.PaginateUserNotes(user, notePager); err != nil { session.FlashError(w, r, "Paginating user notes: %s", err) } else { otherNotes = on } // Paginate feedback & reports. if fb, err := models.PaginateFeedbackAboutUser(user, fbPager); err != nil { session.FlashError(w, r, "Paginating feedback on this user: %s", err) } else { feedback = fb } // Map user IDs for the Feedback Reply-To line and the Note Givers for the paginated notes. var userIDs = []uint64{} for _, p := range feedback { if p.UserID > 0 { userIDs = append(userIDs, p.UserID) } } for _, p := range otherNotes { if p.UserID > 0 { userIDs = append(userIDs, p.UserID) } } if um, err := models.MapUsers(currentUser, userIDs); err != nil { session.FlashError(w, r, "Couldn't map user IDs: %s", err) } else { userMap = um } } vars := map[string]interface{}{ "User": user, "PhotoCount": models.CountPhotosICanSee(user, currentUser), "NoteCount": models.CountNotesAboutUser(currentUser, user), "FriendCount": models.CountFriends(user.ID), "MyNote": myNote, // Admin concerns. "Feedback": feedback, "FeedbackPager": fbPager, "OtherNotes": otherNotes, "NotePager": notePager, "UserMap": userMap, } if err := tmpl.Execute(w, r, vars); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } }) } // My user notes page (/notes/me) func MyNotes() http.HandlerFunc { tmpl := templates.Must("account/my_user_notes.html") // Whitelist for ordering options. var sortWhitelist = []string{ "updated_at desc", "updated_at asc", "username desc", "username asc", } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Filter parameters. var ( search = r.FormValue("search") sort = r.FormValue("sort") sortOK bool ) // Sort options. for _, v := range sortWhitelist { if sort == v { sortOK = true break } } if !sortOK { sort = sortWhitelist[0] } // Get the current user. currentUser, err := session.CurrentUser(r) if err != nil { session.FlashError(w, r, "You must be signed in to view this page.") templates.Redirect(w, "/login?next="+url.QueryEscape(r.URL.String())) return } // Is the site under a Maintenance Mode restriction? if middleware.MaintenanceMode(currentUser, w, r) { return } // Are we deleting a note? if r.Method == http.MethodPost { var ( intent = r.PostFormValue("intent") idStr = r.PostFormValue("id") ) noteID, err := strconv.Atoi(idStr) if err != nil { session.FlashError(w, r, "Invalid note ID.") templates.Redirect(w, r.URL.Path) return } note, err := models.GetNote(uint64(noteID)) if err != nil { session.FlashError(w, r, "Couldn't find that note.") templates.Redirect(w, r.URL.Path) return } // Assert it is our note to edit. if note.UserID != currentUser.ID { session.FlashError(w, r, "That is not your note to edit.") templates.Redirect(w, r.URL.Path) return } if intent == "delete" { // Delete it! if err := note.Delete(); err != nil { session.FlashError(w, r, "Error deleting the note: %s.", err) templates.Redirect(w, r.URL.Path) return } session.Flash(w, r, "That note has been deleted!") } templates.Redirect(w, r.URL.Path) return } var ( pager = &models.Pagination{ Page: 1, PerPage: config.PageSizeAdminUserNotes, Sort: sort, } userIDs = []uint64{} ) pager.ParsePage(r) notes, err := models.PaginateMyUserNotes(currentUser, search, pager) if err != nil { session.FlashError(w, r, "Error getting your user notes: %s", err) templates.Redirect(w, "/") return } // Map user IDs to users. for _, note := range notes { userIDs = append(userIDs, note.AboutUserID) } userMap, err := models.MapUsers(currentUser, userIDs) if err != nil { log.Error("MyUserNotes: couldn't MapUsers: %s", err) } vars := map[string]interface{}{ "Notes": notes, "Pager": pager, "UserMap": userMap, // Search filters "Search": search, "Sort": sort, } if err := tmpl.Execute(w, r, vars); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } }) }