Ability to ignore friend requests

This commit is contained in:
Noah Petherbridge 2023-10-22 19:57:18 -07:00
parent 61c47c032d
commit a97ed4562e
5 changed files with 104 additions and 22 deletions

View File

@ -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,10 +44,18 @@ 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,
"IsIgnored": isIgnored,
"Friends": friends,
"IgnoredFriendCount": ignoredFriendCount,
"Pager": pager,
}
if err := tmpl.Execute(w, r, vars); err != nil {

View File

@ -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 {

View File

@ -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) {

View File

@ -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 {

View File

@ -18,7 +18,7 @@
<div class="level-item">
<div class="tabs is-toggle">
<ul>
<li{{if and (not .IsRequests) (not .IsPending)}} class="is-active"{{end}}>
<li{{if and (not .IsRequests) (not .IsPending) (not .IsIgnored)}} class="is-active"{{end}}>
<a href="/friends">My Friends</a>
</li>
<li{{if .IsRequests}} class="is-active"{{end}}>
@ -32,6 +32,12 @@
Sent
</a>
</li>
<li{{if .IsIgnored}} class="is-active"{{end}}>
<a href="/friends?view=ignored">
Ignored
{{if .IgnoredFriendCount}}<span class="tag ml-2">{{.IgnoredFriendCount}}</span>{{end}}
</a>
</li>
</ul>
</div>
</div>
@ -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}}
</div>
@ -108,7 +115,7 @@
</div>
</div>
</div>
{{if $Root.IsRequests}}
{{if or $Root.IsRequests $Root.IsIgnored}}
<footer class="card-footer">
<button type="submit" name="verdict" value="approve" class="card-footer-item button is-success">
<span class="icon"><i class="fa fa-check"></i></span>
@ -118,6 +125,12 @@
<span class="icon"><i class="fa fa-xmark"></i></span>
<span>Reject</span>
</button>
{{if not $Root.IsIgnored}}
<button type="submit" name="verdict" value="ignore" class="card-footer-item button">
<span class="icon"><i class="fa fa-moon"></i></span>
<span>Ignore</span>
</button>
{{end}}
</footer>
{{else}}
<footer class="card-footer">