From a97ed4562ee59b7d74edc7bff65bd435883ae46e Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sun, 22 Oct 2023 19:57:18 -0700 Subject: [PATCH] Ability to ignore friend requests --- pkg/controller/friend/friends.go | 20 ++++++++--- pkg/controller/friend/request.go | 9 +++++ pkg/controller/photo/site_gallery.go | 26 +++++++++----- pkg/models/friend.go | 54 ++++++++++++++++++++++++---- web/templates/friend/friends.html | 17 +++++++-- 5 files changed, 104 insertions(+), 22 deletions(-) diff --git a/pkg/controller/friend/friends.go b/pkg/controller/friend/friends.go index 4d2897c..9c36ba6 100644 --- a/pkg/controller/friend/friends.go +++ b/pkg/controller/friend/friends.go @@ -4,6 +4,7 @@ import ( "net/http" "code.nonshy.com/nonshy/website/pkg/config" + "code.nonshy.com/nonshy/website/pkg/log" "code.nonshy.com/nonshy/website/pkg/models" "code.nonshy.com/nonshy/website/pkg/session" "code.nonshy.com/nonshy/website/pkg/templates" @@ -17,6 +18,7 @@ func Friends() http.HandlerFunc { view = r.FormValue("view") isRequests = view == "requests" isPending = view == "pending" + isIgnored = view == "ignored" ) currentUser, err := session.CurrentUser(r) @@ -32,7 +34,7 @@ func Friends() http.HandlerFunc { Sort: "updated_at desc", } pager.ParsePage(r) - friends, err := models.PaginateFriends(currentUser, isRequests, isPending, pager) + friends, err := models.PaginateFriends(currentUser, isRequests, isPending, isIgnored, pager) if err != nil { session.FlashError(w, r, "Couldn't paginate friends: %s", err) templates.Redirect(w, "/") @@ -42,11 +44,19 @@ func Friends() http.HandlerFunc { // Inject relationship booleans. models.SetUserRelationships(currentUser, friends) + // Ignored friend request count. + ignoredFriendCount, err := models.CountIgnoredFriendRequests(currentUser.ID) + if err != nil { + log.Error("Ignored Friend Request Count (%s): %s", currentUser.Username, err) + } + var vars = map[string]interface{}{ - "IsRequests": isRequests, - "IsPending": isPending, - "Friends": friends, - "Pager": pager, + "IsRequests": isRequests, + "IsPending": isPending, + "IsIgnored": isIgnored, + "Friends": friends, + "IgnoredFriendCount": ignoredFriendCount, + "Pager": pager, } if err := tmpl.Execute(w, r, vars); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/pkg/controller/friend/request.go b/pkg/controller/friend/request.go index 6f9f6b9..4788fb0 100644 --- a/pkg/controller/friend/request.go +++ b/pkg/controller/friend/request.go @@ -71,6 +71,15 @@ func AddFriend() http.HandlerFunc { templates.Redirect(w, "/friends?view=requests") } templates.Redirect(w, "/friends") + return + } else if verdict == "ignore" { + if err := models.IgnoreFriendRequest(currentUser, user); err != nil { + session.FlashError(w, r, "Error marking the friend request as ignored: %s", err) + } else { + session.Flash(w, r, "You have ignored the friend request from %s.", username) + } + templates.Redirect(w, "/friends") + return } else { // Post the friend request. if err := models.AddFriend(currentUser.ID, user.ID); err != nil { diff --git a/pkg/controller/photo/site_gallery.go b/pkg/controller/photo/site_gallery.go index ee09760..bf35648 100644 --- a/pkg/controller/photo/site_gallery.go +++ b/pkg/controller/photo/site_gallery.go @@ -44,14 +44,6 @@ func SiteGallery() http.HandlerFunc { sort = sortWhitelist[0] } - // Defaults. - if viewStyle != "full" { - viewStyle = "cards" - } - if who != "friends" && who != "everybody" { - who = "friends" - } - // Load the current user. currentUser, err := session.CurrentUser(r) if err != nil { @@ -59,7 +51,23 @@ func SiteGallery() http.HandlerFunc { } // Is the current viewer shy? - var isShy = currentUser.IsShy() + var ( + isShy = currentUser.IsShy() + myFriendCount = models.CountFriends(currentUser.ID) + ) + + // Defaults. + if viewStyle != "full" { + viewStyle = "cards" + } + if who != "friends" && who != "everybody" { + // Default Who setting should be Friends-only, unless you have no friends. + if myFriendCount > 0 { + who = "friends" + } else { + who = "everybody" + } + } // Admin scope warning. if adminView && !currentUser.HasAdminScope(config.ScopePhotoModerator) { diff --git a/pkg/models/friend.go b/pkg/models/friend.go index b97b190..9802227 100644 --- a/pkg/models/friend.go +++ b/pkg/models/friend.go @@ -15,6 +15,7 @@ type Friend struct { SourceUserID uint64 `gorm:"index"` TargetUserID uint64 `gorm:"index"` Approved bool `gorm:"index"` + Ignored bool CreatedAt time.Time UpdatedAt time.Time } @@ -39,6 +40,7 @@ func AddFriend(sourceUserID, targetUserID uint64) error { if reverse == nil && forward != nil { // Approve the reverse. rev.Approved = true + rev.Ignored = false rev.Save() // Add the matching forward. @@ -46,6 +48,7 @@ func AddFriend(sourceUserID, targetUserID uint64) error { SourceUserID: sourceUserID, TargetUserID: targetUserID, Approved: true, + Ignored: false, } return DB.Create(f).Error } @@ -240,13 +243,25 @@ func FriendIDsInCircleAreExplicit(userId uint64) []uint64 { func CountFriendRequests(userID uint64) (int64, error) { var count int64 result := DB.Where( - "target_user_id = ? AND approved = ?", + "target_user_id = ? AND approved = ? AND ignored IS NOT true", userID, false, ).Model(&Friend{}).Count(&count) return count, result.Error } +// CountIgnoredFriendRequests gets a count of ignored pending friend requests for the user. +func CountIgnoredFriendRequests(userID uint64) (int64, error) { + var count int64 + result := DB.Where( + "target_user_id = ? AND approved = ? AND ignored = ?", + userID, + false, + true, + ).Model(&Friend{}).Count(&count) + return count, result.Error +} + // CountFriends gets a count of friends for the user. func CountFriends(userID uint64) int64 { var count int64 @@ -269,7 +284,7 @@ The `requests` and `sent` bools are mutually exclusive (use only one, or neither asks for unanswered friend requests to you, and `sent` returns the friend requests that you have sent and have not been answered. */ -func PaginateFriends(user *User, requests bool, sent bool, pager *Pagination) ([]*User, error) { +func PaginateFriends(user *User, requests bool, sent bool, ignored bool, pager *Pagination) ([]*User, error) { // We paginate over the Friend table. var ( fs = []*Friend{} @@ -277,20 +292,25 @@ func PaginateFriends(user *User, requests bool, sent bool, pager *Pagination) ([ query *gorm.DB ) - if requests && sent { + if requests && sent && ignored { return nil, errors.New("requests and sent are mutually exclusive options, use one or neither") } if requests { query = DB.Where( - "target_user_id = ? AND approved = ?", + "target_user_id = ? AND approved = ? AND ignored IS NOT true", user.ID, false, ) } else if sent { query = DB.Where( - "source_user_id = ? AND approved = ?", + "source_user_id = ? AND approved = ? AND ignored IS NOT true", user.ID, false, ) + } else if ignored { + query = DB.Where( + "target_user_id = ? AND approved = ? AND ignored = ?", + user.ID, false, true, + ) } else { query = DB.Where( "source_user_id = ? AND approved = ?", @@ -307,7 +327,7 @@ func PaginateFriends(user *User, requests bool, sent bool, pager *Pagination) ([ // Now of these friends get their User objects. for _, friend := range fs { - if requests { + if requests || ignored { userIDs = append(userIDs, friend.SourceUserID) } else { userIDs = append(userIDs, friend.TargetUserID) @@ -384,6 +404,28 @@ func GetFriendRequests(userID uint64) ([]*Friend, error) { return fs, result.Error } +// IgnoreFriendRequest ignores a pending friend request that was sent to targetUserID. +func IgnoreFriendRequest(currentUser *User, fromUser *User) error { + // Is there a reverse friend request pending? (The one we ideally hope to mark Ignored) + rev := &Friend{} + reverse := DB.Where( + "source_user_id = ? AND target_user_id = ?", + fromUser.ID, currentUser.ID, + ).First(&rev).Error + + // If the reverse exists (requested us) mark it as Ignored. + if reverse == nil { + // Ignore the reverse friend request (happy path). + log.Error("%s ignoring friend request from %s", currentUser.Username, fromUser.Username) + rev.Approved = false + rev.Ignored = true + return rev.Save() + } + + log.Error("rev: %+v", rev) + return errors.New("unexpected error while ignoring friend request") +} + // RemoveFriend severs a friend connection both directions, used when // rejecting a request or removing a friend. func RemoveFriend(sourceUserID, targetUserID uint64) error { diff --git a/web/templates/friend/friends.html b/web/templates/friend/friends.html index 622ca81..99dada7 100644 --- a/web/templates/friend/friends.html +++ b/web/templates/friend/friends.html @@ -18,7 +18,7 @@
@@ -52,6 +58,7 @@ {{Pluralize64 .Pager.Total "has" "have"}} not been approved yet. {{else}} You have {{.Pager.Total}} friend{{if .IsRequests}} request{{end}}{{Pluralize64 .Pager.Total}} + {{if .IsIgnored}} on ignore -- they don't know you ignored their request and they can not send another one.{{end}} (page {{.Pager.Page}} of {{.Pager.Pages}}). {{end}} @@ -108,7 +115,7 @@ - {{if $Root.IsRequests}} + {{if or $Root.IsRequests $Root.IsIgnored}} {{else}}