From 11ea3b4d47a732fe1c6abc39ce452f899f70859f Mon Sep 17 00:00:00 2001
From: r <r@freesoftwareextremist.com>
Date: Mon, 5 Feb 2024 13:08:23 +0000
Subject: Add inline follow/unfollow buttons on follow list page

---
 mastodon/accounts.go          | 44 +++++++++++++++++++++++++++++++++++++++----
 renderer/model.go             | 11 +++++------
 service/service.go            |  1 -
 templates/user.tmpl           | 10 +++++-----
 templates/userlistfollow.tmpl | 30 +++++++++++++++++++++++++++++
 5 files changed, 80 insertions(+), 16 deletions(-)
 create mode 100644 templates/userlistfollow.tmpl

diff --git a/mastodon/accounts.go b/mastodon/accounts.go
index c9e0065..1a0ac2e 100644
--- a/mastodon/accounts.go
+++ b/mastodon/accounts.go
@@ -14,7 +14,7 @@ import (
 )
 
 type AccountPleroma struct {
-	Relationship Relationship `json:"relationship"`
+	Relationship *Relationship `json:"relationship"`
 }
 
 // Account hold information for mastodon account.
@@ -73,7 +73,7 @@ func (c *Client) GetAccount(ctx context.Context, id string) (*Account, error) {
 			return nil, err
 		}
 		if len(rs) > 0 {
-			account.Pleroma = &AccountPleroma{*rs[0]}
+			account.Pleroma = &AccountPleroma{rs[0]}
 		}
 	}
 	return &account, nil
@@ -221,10 +221,40 @@ func (c *Client) GetAccountStatuses(ctx context.Context, id string, onlyMedia bo
 	return statuses, nil
 }
 
+func (c *Client) getMissingRelationships(ctx context.Context, accounts []*Account) ([]*Account, error) {
+	var ids []string
+	for _, a := range accounts {
+		if a.Pleroma == nil || len(a.Pleroma.Relationship.ID) < 1 {
+			ids = append(ids, a.ID)
+		}
+	}
+	if len(ids) < 1 {
+		return accounts, nil
+	}
+	rs, err := c.GetAccountRelationships(ctx, ids)
+	if err != nil {
+		return nil, err
+	}
+	rsm := make(map[string]*Relationship, len(rs))
+	for _, r := range rs {
+		rsm[r.ID] = r
+	}
+	for _, a := range accounts {
+		a.Pleroma = &AccountPleroma{rsm[a.ID]}
+	}
+	return accounts, nil
+}
+
 // GetAccountFollowers return followers list.
 func (c *Client) GetAccountFollowers(ctx context.Context, id string, pg *Pagination) ([]*Account, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/followers", url.PathEscape(string(id))), nil, &accounts, pg)
+	params := url.Values{}
+	params.Set("with_relationships", strconv.FormatBool(true))
+	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/followers", url.PathEscape(string(id))), params, &accounts, pg)
+	if err != nil {
+		return nil, err
+	}
+	accounts, err = c.getMissingRelationships(ctx, accounts)
 	if err != nil {
 		return nil, err
 	}
@@ -234,7 +264,13 @@ func (c *Client) GetAccountFollowers(ctx context.Context, id string, pg *Paginat
 // GetAccountFollowing return following list.
 func (c *Client) GetAccountFollowing(ctx context.Context, id string, pg *Pagination) ([]*Account, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/following", url.PathEscape(string(id))), nil, &accounts, pg)
+	params := url.Values{}
+	params.Set("with_relationships", strconv.FormatBool(true))
+	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/following", url.PathEscape(string(id))), params, &accounts, pg)
+	if err != nil {
+		return nil, err
+	}
+	accounts, err = c.getMissingRelationships(ctx, accounts)
 	if err != nil {
 		return nil, err
 	}
diff --git a/renderer/model.go b/renderer/model.go
index e43279d..59b0059 100644
--- a/renderer/model.go
+++ b/renderer/model.go
@@ -99,12 +99,11 @@ type NotificationData struct {
 
 type UserData struct {
 	*CommonData
-	User      *mastodon.Account
-	IsCurrent bool
-	Type      string
-	Users     []*mastodon.Account
-	Statuses  []*mastodon.Status
-	NextLink  string
+	User     *mastodon.Account
+	Type     string
+	Users    []*mastodon.Account
+	Statuses []*mastodon.Status
+	NextLink string
 }
 
 type UserSearchData struct {
diff --git a/service/service.go b/service/service.go
index db309ff..953a1b9 100644
--- a/service/service.go
+++ b/service/service.go
@@ -628,7 +628,6 @@ func (s *service) UserPage(c *client, id string, pageType string,
 	cdata := s.cdata(c, user.DisplayName+" @"+user.Acct, 0, 0, "")
 	data := &renderer.UserData{
 		User:       user,
-		IsCurrent:  isCurrent,
 		Type:       pageType,
 		Users:      users,
 		Statuses:   statuses,
diff --git a/templates/user.tmpl b/templates/user.tmpl
index 8f47929..f34a9df 100644
--- a/templates/user.tmpl
+++ b/templates/user.tmpl
@@ -16,7 +16,7 @@
 				source
 			</a>
 		</div>
-		{{if not .IsCurrent}}
+		{{if (ne $.Ctx.UserID .User.ID)}}
 		<div>
 			<span> {{if .User.Pleroma.Relationship.FollowedBy}} follows you - {{end}} </span>  
 			{{if .User.Pleroma.Relationship.BlockedBy}} blocks you - {{end}}
@@ -104,7 +104,7 @@
 			<a href="/user/{{.User.ID}}/followers">followers ({{.User.FollowersCount}})</a> -
 			<a href="/user/{{.User.ID}}/media">media</a>
 		</div>
-		{{if .IsCurrent}}
+		{{if (eq $.Ctx.UserID .User.ID)}}
 		<div>
 			<a href="/user/{{.User.ID}}/bookmarks">bookmarks</a>
 			- <a href="/user/{{.User.ID}}/likes">likes</a>
@@ -115,7 +115,7 @@
 		{{end}}
 		<div>
 			<a href="/usersearch/{{.User.ID}}">search statuses</a>
-			{{if .IsCurrent}} - <a href="/filters">filters</a> {{end}}
+			{{if (eq $.Ctx.UserID .User.ID)}} - <a href="/filters">filters</a> {{end}}
 		</div>
 	</div>
 	<div class="user-profile-description">
@@ -140,11 +140,11 @@
 
 {{else if eq .Type "following"}}
 <h1>Following</h1>
-{{template "userlist.tmpl" (WithContext .Users $.Ctx)}}
+{{template "userlistfollow.tmpl" (WithContext .Users $.Ctx)}}
 
 {{else if eq .Type "followers"}}
 <h1>Followers</h1>
-{{template "userlist.tmpl" (WithContext .Users $.Ctx)}}
+{{template "userlistfollow.tmpl" (WithContext .Users $.Ctx)}}
 
 {{else if eq .Type "media"}}
 <h1>Statuses with media</h1>
diff --git a/templates/userlistfollow.tmpl b/templates/userlistfollow.tmpl
new file mode 100644
index 0000000..298142f
--- /dev/null
+++ b/templates/userlistfollow.tmpl
@@ -0,0 +1,30 @@
+{{with .Data}}
+{{if .}}
+<table>
+{{range .}}
+	<tr>
+		<td> {{template "userlistitem.tmpl" (WithContext . $.Ctx)}} </td>
+		<td>
+			{{if (ne $.Ctx.UserID .ID)}}
+				{{if .Pleroma.Relationship.Following}}
+				<form class="user-list-action" action="/unfollow/{{.ID}}" method="POST">
+					<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
+					<input type="hidden" name="referrer" value="{{$.Ctx.Referrer}}">
+					<button type="submit">Unfollow</button>
+				</form>
+				{{else}}
+				<form class="user-list-action" action="/follow/{{.ID}}" method="POST">
+					<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
+					<input type="hidden" name="referrer" value="{{$.Ctx.Referrer}}">
+					<button type="submit">Follow</button>
+				</form>
+				{{end}}
+			{{end}}
+		</td>
+	</tr>
+{{end}}
+</table>
+{{else}}
+<p>No data found</p>
+{{end}}
+{{end}}
-- 
cgit v1.2.3