summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Kangas <gabek@real-ity.com>2022-02-11 13:37:55 -0800
committerGabe Kangas <gabek@real-ity.com>2022-02-11 13:37:55 -0800
commitf0435fc7cda1b20935fc1500fa0a67c5d8b5914d (patch)
tree017f445164303ad524b3475a9cf5ec64ab6c33c1
parent63dd625f91f034e3dd1a86a72e8dab44a953915a (diff)
Use Paginated API for followers tab on frontendgek/paginate-federated-actions-admin
-rw-r--r--activitypub/controllers/followers.go2
-rw-r--r--activitypub/outbox/outbox.go2
-rw-r--r--activitypub/persistence/followers.go12
-rw-r--r--controllers/followers.go10
-rw-r--r--router/router.go4
-rw-r--r--webroot/js/components/federation/followers.js40
6 files changed, 39 insertions, 31 deletions
diff --git a/activitypub/controllers/followers.go b/activitypub/controllers/followers.go
index 11193f51a..9a1ba7bdf 100644
--- a/activitypub/controllers/followers.go
+++ b/activitypub/controllers/followers.go
@@ -98,7 +98,7 @@ func getFollowersPage(page string, r *http.Request) (vocab.ActivityStreamsOrdere
return nil, errors.Wrap(err, "unable to get follower count")
}
- followers, err := persistence.GetFederationFollowers(followersPageSize, (pageInt-1)*followersPageSize)
+ followers, _, err := persistence.GetFederationFollowers(followersPageSize, (pageInt-1)*followersPageSize)
if err != nil {
return nil, errors.Wrap(err, "unable to get federation followers")
}
diff --git a/activitypub/outbox/outbox.go b/activitypub/outbox/outbox.go
index cf9c2da46..ce79fbe06 100644
--- a/activitypub/outbox/outbox.go
+++ b/activitypub/outbox/outbox.go
@@ -171,7 +171,7 @@ func getHashtagLinkHTMLFromTagString(baseHashtag string) string {
func SendToFollowers(payload []byte) error {
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
- followers, err := persistence.GetFederationFollowers(-1, 0)
+ followers, _, err := persistence.GetFederationFollowers(-1, 0)
if err != nil {
log.Errorln("unable to fetch followers to send to", err)
return errors.New("unable to fetch followers to send payload to")
diff --git a/activitypub/persistence/followers.go b/activitypub/persistence/followers.go
index 77863038e..df40c581f 100644
--- a/activitypub/persistence/followers.go
+++ b/activitypub/persistence/followers.go
@@ -6,6 +6,7 @@ import (
"github.com/owncast/owncast/db"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/utils"
+ "github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
@@ -44,14 +45,19 @@ func GetFollowerCount() (int64, error) {
}
// GetFederationFollowers will return a slice of the followers we keep track of locally.
-func GetFederationFollowers(limit int, offset int) ([]models.Follower, error) {
+func GetFederationFollowers(limit int, offset int) ([]models.Follower, int, error) {
ctx := context.Background()
+ total, err := _datastore.GetQueries().GetFollowerCount(ctx)
+ if err != nil {
+ return nil, 0, errors.Wrap(err, "unable to fetch total number of followers")
+ }
+
followersResult, err := _datastore.GetQueries().GetFederationFollowersWithOffset(ctx, db.GetFederationFollowersWithOffsetParams{
Limit: int32(limit),
Offset: int32(offset),
})
if err != nil {
- return nil, err
+ return nil, 0, err
}
followers := make([]models.Follower, 0)
@@ -69,7 +75,7 @@ func GetFederationFollowers(limit int, offset int) ([]models.Follower, error) {
followers = append(followers, singleFollower)
}
- return followers, nil
+ return followers, int(total), nil
}
// GetPendingFollowRequests will return pending follow requests.
diff --git a/controllers/followers.go b/controllers/followers.go
index 8561d25a4..0f9c98eaa 100644
--- a/controllers/followers.go
+++ b/controllers/followers.go
@@ -7,12 +7,16 @@ import (
)
// GetFollowers will handle an API request to fetch the list of followers (non-activitypub response).
-func GetFollowers(w http.ResponseWriter, r *http.Request) {
- followers, err := persistence.GetFederationFollowers(-1, 0)
+func GetFollowers(offset int, limit int, w http.ResponseWriter, r *http.Request) {
+ followers, total, err := persistence.GetFederationFollowers(limit, offset)
if err != nil {
WriteSimpleResponse(w, false, "unable to fetch followers")
return
}
- WriteResponse(w, followers)
+ response := PaginatedResponse{
+ Total: total,
+ Results: followers,
+ }
+ WriteResponse(w, response)
}
diff --git a/router/router.go b/router/router.go
index 6f881d8ba..55d3f94c5 100644
--- a/router/router.go
+++ b/router/router.go
@@ -77,7 +77,7 @@ func Start() error {
http.HandleFunc("/api/remotefollow", controllers.RemoteFollow)
// return followers
- http.HandleFunc("/api/followers", controllers.GetFollowers)
+ http.HandleFunc("/api/followers", middleware.HandlePagination(controllers.GetFollowers))
// Authenticated admin requests
@@ -127,7 +127,7 @@ func Start() error {
http.HandleFunc("/api/admin/chat/users/moderators", middleware.RequireAdminAuth(admin.GetModerators))
// return followers
- http.HandleFunc("/api/admin/followers", middleware.RequireAdminAuth(controllers.GetFollowers))
+ http.HandleFunc("/api/admin/followers", middleware.RequireAdminAuth(middleware.HandlePagination(controllers.GetFollowers)))
// Get a list of pending follow requests
http.HandleFunc("/api/admin/followers/pending", middleware.RequireAdminAuth(admin.GetPendingFollowRequests))
diff --git a/webroot/js/components/federation/followers.js b/webroot/js/components/federation/followers.js
index 6bd6a08b8..89825af62 100644
--- a/webroot/js/components/federation/followers.js
+++ b/webroot/js/components/federation/followers.js
@@ -2,7 +2,6 @@ import { h, Component } from '/js/web_modules/preact.js';
import htm from '/js/web_modules/htm.js';
import { URL_FOLLOWERS } from '/js/utils/constants.js';
const html = htm.bind(h);
-import { paginateArray } from '../../utils/helpers.js';
export default class FollowerList extends Component {
constructor(props) {
super(props);
@@ -10,6 +9,8 @@ export default class FollowerList extends Component {
this.state = {
followers: [],
followersPage: 0,
+ currentPage: 0,
+ total: 0,
};
}
@@ -22,23 +23,26 @@ export default class FollowerList extends Component {
}
async getFollowers() {
- const response = await fetch(URL_FOLLOWERS);
+ const { currentPage } = this.state;
+ const limit = 16;
+ const offset = currentPage * limit;
+ const u = `${URL_FOLLOWERS}?offset=${offset}&limit=${limit}`;
+ const response = await fetch(u);
const followers = await response.json();
this.setState({
- followers: followers,
+ followers: followers.results,
+ total: response.total,
});
}
changeFollowersPage(page) {
- this.setState({ followersPage: page });
+ this.setState({ currentPage: page });
+ this.getFollowers();
}
render() {
- const FOLLOWER_PAGE_SIZE = 16;
- const { followersPage } = this.state;
-
- const { followers } = this.state;
+ const { followers, total, currentPage } = this.state;
if (!followers) {
return null;
}
@@ -57,21 +61,15 @@ export default class FollowerList extends Component {
</p>
</div>`;
- const paginatedFollowers = paginateArray(
- followers,
- followersPage + 1,
- FOLLOWER_PAGE_SIZE
- );
-
const paginationControls =
- paginatedFollowers.totalPages > 1 &&
- Array(paginatedFollowers.totalPages)
+ total > 1 &&
+ Array(total)
.fill()
.map((x, n) => {
const activePageClass =
- n === followersPage &&
+ n === currentPage &&
'bg-indigo-600 rounded-full shadow-md focus:shadow-md text-white';
- return html` <li class="page-item active">
+ return html` <li class="page-item active w-10">
<a
class="page-link relative block cursor-pointer hover:no-underline py-1.5 px-3 border-0 rounded-full hover:text-gray-800 hover:bg-gray-200 outline-none transition-all duration-300 ${activePageClass}"
onClick=${() => this.changeFollowersPage(n)}
@@ -85,13 +83,13 @@ export default class FollowerList extends Component {
<div>
<div class="flex flex-wrap">
${followers.length === 0 && noFollowersInfo}
- ${paginatedFollowers.items.map((follower) => {
+ ${followers.map((follower) => {
return html` <${SingleFollower} user=${follower} /> `;
})}
</div>
<div class="flex">
- <nav aria-label="Page navigation example">
- <ul class="flex list-style-none">
+ <nav aria-label="Tab pages">
+ <ul class="flex list-style-none flex-wrap">
${paginationControls}
</ul>
</nav>