Add following and followers page
authorr <r@freesoftwareextremist.com>
Sun, 29 Dec 2019 03:43:57 +0000 (03:43 +0000)
committerr <r@freesoftwareextremist.com>
Sun, 29 Dec 2019 03:43:57 +0000 (03:43 +0000)
renderer/model.go
renderer/renderer.go
service/auth.go
service/logging.go
service/service.go
service/transport.go
templates/followers.tmpl [new file with mode: 0644]
templates/following.tmpl [new file with mode: 0644]
templates/user.tmpl

index 12fa90f5b65e74efcb369c6d908954fe98eaf15a..3d344b4fb24fe74e31e7b7c0a4e5e6752e940c30 100644 (file)
@@ -90,6 +90,20 @@ type RetweetedByData struct {
        NextLink string
 }
 
+type FollowingData struct {
+       *CommonData
+       Users []*mastodon.Account
+       HasNext  bool
+       NextLink string
+}
+
+type FollowersData struct {
+       *CommonData
+       Users []*mastodon.Account
+       HasNext  bool
+       NextLink string
+}
+
 type SearchData struct {
        *CommonData
        Q        string
index a46cfd25aba47dcb60be98684d8b079c87976073..efc412d616efc9f50d22a887d003b9f3bb520f83 100644 (file)
@@ -23,6 +23,8 @@ type Renderer interface {
        RenderEmojiPage(ctx context.Context, writer io.Writer, data *EmojiData) (err error)
        RenderLikedByPage(ctx context.Context, writer io.Writer, data *LikedByData) (err error)
        RenderRetweetedByPage(ctx context.Context, writer io.Writer, data *RetweetedByData) (err error)
+       RenderFollowingPage(ctx context.Context, writer io.Writer, data *FollowingData) (err error)
+       RenderFollowersPage(ctx context.Context, writer io.Writer, data *FollowersData) (err error)
        RenderSearchPage(ctx context.Context, writer io.Writer, data *SearchData) (err error)
        RenderSettingsPage(ctx context.Context, writer io.Writer, data *SettingsData) (err error)
 }
@@ -93,6 +95,14 @@ func (r *renderer) RenderRetweetedByPage(ctx context.Context, writer io.Writer,
        return r.template.ExecuteTemplate(writer, "retweetedby.tmpl", data)
 }
 
+func (r *renderer) RenderFollowingPage(ctx context.Context, writer io.Writer, data *FollowingData) (err error) {
+       return r.template.ExecuteTemplate(writer, "following.tmpl", data)
+}
+
+func (r *renderer) RenderFollowersPage(ctx context.Context, writer io.Writer, data *FollowersData) (err error) {
+       return r.template.ExecuteTemplate(writer, "followers.tmpl", data)
+}
+
 func (r *renderer) RenderSearchPage(ctx context.Context, writer io.Writer, data *SearchData) (err error) {
        return r.template.ExecuteTemplate(writer, "search.tmpl", data)
 }
index 4d1b5af86b5715b8c35fe004c6cbda92838e8f61..efc8dd3ca7fe7e3f42e6fd814ff3eccdeadf7598 100644 (file)
@@ -149,6 +149,22 @@ func (s *authService) ServeRetweetedByPage(ctx context.Context, client io.Writer
        return s.Service.ServeRetweetedByPage(ctx, client, c, id)
 }
 
+func (s *authService) ServeFollowingPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error) {
+       c, err = s.getClient(ctx)
+       if err != nil {
+               return
+       }
+       return s.Service.ServeFollowingPage(ctx, client, c, id, maxID, minID)
+}
+
+func (s *authService) ServeFollowersPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error) {
+       c, err = s.getClient(ctx)
+       if err != nil {
+               return
+       }
+       return s.Service.ServeFollowersPage(ctx, client, c, id, maxID, minID)
+}
+
 func (s *authService) ServeSearchPage(ctx context.Context, client io.Writer, c *model.Client, q string, qType string, offset int) (err error) {
        c, err = s.getClient(ctx)
        if err != nil {
index cfd3654645bba3806059e6ed6fc42be700e17e8a..d1685ac9cfd72054bf84bd4353166ef8ff01c603 100644 (file)
@@ -125,6 +125,22 @@ func (s *loggingService) ServeRetweetedByPage(ctx context.Context, client io.Wri
        return s.Service.ServeRetweetedByPage(ctx, client, c, id)
 }
 
+func (s *loggingService) ServeFollowingPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error) {
+       defer func(begin time.Time) {
+               s.logger.Printf("method=%v, id=%v, max_id=%v, min_id=%v, took=%v, err=%v\n",
+                       "ServeFollowingPage", id, maxID, minID, time.Since(begin), err)
+       }(time.Now())
+       return s.Service.ServeFollowingPage(ctx, client, c, id, maxID, minID)
+}
+
+func (s *loggingService) ServeFollowersPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error) {
+       defer func(begin time.Time) {
+               s.logger.Printf("method=%v, id=%v, max_id=%v, min_id=%v, took=%v, err=%v\n",
+                       "ServeFollowersPage", id, maxID, minID, time.Since(begin), err)
+       }(time.Now())
+       return s.Service.ServeFollowersPage(ctx, client, c, id, maxID, minID)
+}
+
 func (s *loggingService) ServeSearchPage(ctx context.Context, client io.Writer, c *model.Client, q string, qType string, offset int) (err error) {
        defer func(begin time.Time) {
                s.logger.Printf("method=%v, q=%v, type=%v, offset=%v, took=%v, err=%v\n",
index bf7967d38bdc72fb93a302d18046d0d0c982483f..d9482c87e05195d5843c80d3821802ad9c9aad45 100644 (file)
@@ -39,6 +39,8 @@ type Service interface {
        ServeEmojiPage(ctx context.Context, client io.Writer, c *model.Client) (err error)
        ServeLikedByPage(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
        ServeRetweetedByPage(ctx context.Context, client io.Writer, c *model.Client, id string) (err error)
+       ServeFollowingPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error)
+       ServeFollowersPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error)
        ServeSearchPage(ctx context.Context, client io.Writer, c *model.Client, q string, qType string, offset int) (err error)
        ServeSettingsPage(ctx context.Context, client io.Writer, c *model.Client) (err error)
        SaveSettings(ctx context.Context, client io.Writer, c *model.Client, settings *model.Settings) (err error)
@@ -603,6 +605,87 @@ func (svc *service) ServeRetweetedByPage(ctx context.Context, client io.Writer,
        return
 }
 
+func (svc *service) ServeFollowingPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error) {
+       var hasNext bool
+       var nextLink string
+
+       var pg = mastodon.Pagination{
+               MaxID: maxID,
+               MinID: minID,
+               Limit: 20,
+       }
+
+       followings, err := c.GetAccountFollowing(ctx, id, &pg)
+       if err != nil {
+               return
+       }
+
+       if len(followings) == 20 && len(pg.MaxID) > 0 {
+               hasNext = true
+               nextLink = "/following/" + id + "?max_id=" + pg.MaxID
+       }
+
+       commonData, err := svc.getCommonData(ctx, client, c)
+       if err != nil {
+               return
+       }
+
+       data := &renderer.FollowingData{
+               CommonData: commonData,
+               Users:      followings,
+               HasNext:    hasNext,
+               NextLink:   nextLink,
+       }
+
+       err = svc.renderer.RenderFollowingPage(ctx, client, data)
+       if err != nil {
+               return
+       }
+
+       return
+}
+
+func (svc *service) ServeFollowersPage(ctx context.Context, client io.Writer, c *model.Client, id string, maxID string, minID string) (err error) {
+       var hasNext bool
+       var nextLink string
+
+       var pg = mastodon.Pagination{
+               MaxID: maxID,
+               MinID: minID,
+               Limit: 20,
+       }
+
+       followers, err := c.GetAccountFollowers(ctx, id, &pg)
+       if err != nil {
+               return
+       }
+
+       fmt.Println(len(followers), pg.MaxID)
+       if len(followers) == 20 && len(pg.MaxID) > 0 {
+               hasNext = true
+               nextLink = "/followers/" + id + "?max_id=" + pg.MaxID
+       }
+
+       commonData, err := svc.getCommonData(ctx, client, c)
+       if err != nil {
+               return
+       }
+
+       data := &renderer.FollowersData{
+               CommonData: commonData,
+               Users:      followers,
+               HasNext:    hasNext,
+               NextLink:   nextLink,
+       }
+
+       err = svc.renderer.RenderFollowersPage(ctx, client, data)
+       if err != nil {
+               return
+       }
+
+       return
+}
+
 func (svc *service) ServeSearchPage(ctx context.Context, client io.Writer, c *model.Client, q string, qType string, offset int) (err error) {
        var hasNext bool
        var nextLink string
index 3ab25467e0fa6b91fdaad7977fb0a930ff089e4b..20d96a58df024ba6fd1d5009008277b6e02bd4d2 100644 (file)
@@ -122,6 +122,34 @@ func NewHandler(s Service, staticDir string) http.Handler {
                }
        }).Methods(http.MethodGet)
 
+       r.HandleFunc("/following/{id}", func(w http.ResponseWriter, req *http.Request) {
+               ctx := getContextWithSession(context.Background(), req)
+
+               id, _ := mux.Vars(req)["id"]
+               maxID := req.URL.Query().Get("max_id")
+               minID := req.URL.Query().Get("min_id")
+
+               err := s.ServeFollowingPage(ctx, w, nil, id, maxID, minID)
+               if err != nil {
+                       s.ServeErrorPage(ctx, w, err)
+                       return
+               }
+       }).Methods(http.MethodGet)
+
+       r.HandleFunc("/followers/{id}", func(w http.ResponseWriter, req *http.Request) {
+               ctx := getContextWithSession(context.Background(), req)
+
+               id, _ := mux.Vars(req)["id"]
+               maxID := req.URL.Query().Get("max_id")
+               minID := req.URL.Query().Get("min_id")
+
+               err := s.ServeFollowersPage(ctx, w, nil, id, maxID, minID)
+               if err != nil {
+                       s.ServeErrorPage(ctx, w, err)
+                       return
+               }
+       }).Methods(http.MethodGet)
+
        r.HandleFunc("/like/{id}", func(w http.ResponseWriter, req *http.Request) {
                ctx := getContextWithSession(context.Background(), req)
                id, _ := mux.Vars(req)["id"]
@@ -323,7 +351,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
                copyScope := req.FormValue("copy_scope") == "true"
                settings := &model.Settings{
                        DefaultVisibility: visibility,
-                       CopyScope: copyScope,
+                       CopyScope:         copyScope,
                }
 
                err := s.SaveSettings(ctx, w, nil, settings)
diff --git a/templates/followers.tmpl b/templates/followers.tmpl
new file mode 100644 (file)
index 0000000..1c4e9eb
--- /dev/null
@@ -0,0 +1,12 @@
+{{template "header.tmpl" .HeaderData}}
+{{template "navigation.tmpl" .NavbarData}}
+<div class="page-title"> Followers </div>
+
+{{template "userlist.tmpl" .Users}}
+<div class="pagination">
+       {{if .HasNext}}
+               <a href="{{.NextLink}}">next</a>
+       {{end}}
+</div>
+
+{{template "footer.tmpl"}}
diff --git a/templates/following.tmpl b/templates/following.tmpl
new file mode 100644 (file)
index 0000000..b1d8499
--- /dev/null
@@ -0,0 +1,12 @@
+{{template "header.tmpl" .HeaderData}}
+{{template "navigation.tmpl" .NavbarData}}
+<div class="page-title"> Following </div>
+
+{{template "userlist.tmpl" .Users}}
+<div class="pagination">
+       {{if .HasNext}}
+               <a href="{{.NextLink}}">next</a>
+       {{end}}
+</div>
+
+{{template "footer.tmpl"}}
index fa193380884eff6e60414e20193c2f61135b8b7c..0c134af9bbb452232021879481ae95b76c7d11e4 100644 (file)
@@ -36,7 +36,9 @@
                        {{end}} 
                </div>
                <div>
-                       {{.User.StatusesCount}} statuses - {{.User.FollowingCount}} following - {{.User.FollowersCount}} followers
+                       {{.User.StatusesCount}} statuses - 
+                       <a href="/following/{{.User.ID}}"> {{.User.FollowingCount}} following </a> - 
+                       <a href="/followers/{{.User.ID}}"> {{.User.FollowersCount}} followers </a>
                </div>
        </div>
        <div class="user-profile-decription">