aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorr <r@freesoftwareextremist.com>2020-09-27 09:29:17 +0000
committerr <r@freesoftwareextremist.com>2020-09-27 09:37:15 +0000
commitda22d19fb45b5504f4191ad06d4e7637bfbc3916 (patch)
tree73a44f90ec525caddfe3d01caf688a1b4afdc4af
parent0b8c41ca7c99f6ab31a3769b16c760fd028f7c2b (diff)
downloadbloat-da22d19fb45b5504f4191ad06d4e7637bfbc3916.tar.gz
bloat-da22d19fb45b5504f4191ad06d4e7637bfbc3916.zip
Add bookmarks
- Add bookmark/unbookmark link on mouse hover - Add bookmarks section on user profile page
-rw-r--r--mastodon/accounts.go10
-rw-r--r--mastodon/status.go23
-rw-r--r--service/auth.go27
-rw-r--r--service/logging.go19
-rw-r--r--service/service.go41
-rw-r--r--service/transport.go44
-rw-r--r--templates/status.tmpl13
-rw-r--r--templates/user.tmpl17
8 files changed, 181 insertions, 13 deletions
diff --git a/mastodon/accounts.go b/mastodon/accounts.go
index 7a44e2b..c5eb227 100644
--- a/mastodon/accounts.go
+++ b/mastodon/accounts.go
@@ -353,3 +353,13 @@ func (c *Client) UnSubscribe(ctx context.Context, id string) (*Relationship, err
}
return relationship, nil
}
+
+// GetBookmarks returns the list of bookmarked statuses
+func (c *Client) GetBookmarks(ctx context.Context, pg *Pagination) ([]*Status, error) {
+ var statuses []*Status
+ err := c.doAPI(ctx, http.MethodGet, "/api/v1/bookmarks", nil, &statuses, pg)
+ if err != nil {
+ return nil, err
+ }
+ return statuses, nil
+}
diff --git a/mastodon/status.go b/mastodon/status.go
index 7a29b99..c8555d6 100644
--- a/mastodon/status.go
+++ b/mastodon/status.go
@@ -47,6 +47,7 @@ type Status struct {
Application Application `json:"application"`
Language string `json:"language"`
Pinned interface{} `json:"pinned"`
+ Bookmarked bool `json:"bookmarked"`
Poll *Poll `json:"poll"`
// Custom fields
@@ -366,3 +367,25 @@ func (c *Client) UnmuteConversation(ctx context.Context, id string) (*Status, er
}
return &status, nil
}
+
+// Bookmark bookmarks status specified by id.
+func (c *Client) Bookmark(ctx context.Context, id string) (*Status, error) {
+ var status Status
+
+ err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%s/bookmark", id), nil, &status, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &status, nil
+}
+
+// Unbookmark bookmarks status specified by id.
+func (c *Client) Unbookmark(ctx context.Context, id string) (*Status, error) {
+ var status Status
+
+ err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%s/unbookmark", id), nil, &status, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &status, nil
+}
diff --git a/service/auth.go b/service/auth.go
index ef701c1..7845675 100644
--- a/service/auth.go
+++ b/service/auth.go
@@ -443,8 +443,7 @@ func (s *as) Delete(c *model.Client, id string) (err error) {
return s.Service.Delete(c, id)
}
-func (s *as) ReadNotifications(c *model.Client,
- maxID string) (err error) {
+func (s *as) ReadNotifications(c *model.Client, maxID string) (err error) {
err = s.authenticateClient(c)
if err != nil {
return
@@ -455,3 +454,27 @@ func (s *as) ReadNotifications(c *model.Client,
}
return s.Service.ReadNotifications(c, maxID)
}
+
+func (s *as) Bookmark(c *model.Client, id string) (err error) {
+ err = s.authenticateClient(c)
+ if err != nil {
+ return
+ }
+ err = checkCSRF(c)
+ if err != nil {
+ return
+ }
+ return s.Service.Bookmark(c, id)
+}
+
+func (s *as) UnBookmark(c *model.Client, id string) (err error) {
+ err = s.authenticateClient(c)
+ if err != nil {
+ return
+ }
+ err = checkCSRF(c)
+ if err != nil {
+ return
+ }
+ return s.Service.UnBookmark(c, id)
+}
diff --git a/service/logging.go b/service/logging.go
index 7df03de..3cb99bf 100644
--- a/service/logging.go
+++ b/service/logging.go
@@ -316,11 +316,26 @@ func (s *ls) Delete(c *model.Client, id string) (err error) {
return s.Service.Delete(c, id)
}
-func (s *ls) ReadNotifications(c *model.Client,
- maxID string) (err error) {
+func (s *ls) ReadNotifications(c *model.Client, maxID string) (err error) {
defer func(begin time.Time) {
s.logger.Printf("method=%v, max_id=%v, took=%v, err=%v\n",
"ReadNotifications", maxID, time.Since(begin), err)
}(time.Now())
return s.Service.ReadNotifications(c, maxID)
}
+
+func (s *ls) Bookmark(c *model.Client, id string) (err error) {
+ defer func(begin time.Time) {
+ s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
+ "Bookmark", id, time.Since(begin), err)
+ }(time.Now())
+ return s.Service.Bookmark(c, id)
+}
+
+func (s *ls) UnBookmark(c *model.Client, id string) (err error) {
+ defer func(begin time.Time) {
+ s.logger.Printf("method=%v, id=%v, took=%v, err=%v\n",
+ "UnBookmark", id, time.Since(begin), err)
+ }(time.Now())
+ return s.Service.UnBookmark(c, id)
+}
diff --git a/service/service.go b/service/service.go
index c56d96a..de450b9 100644
--- a/service/service.go
+++ b/service/service.go
@@ -62,6 +62,8 @@ type Service interface {
UnMuteConversation(c *model.Client, id string) (err error)
Delete(c *model.Client, id string) (err error)
ReadNotifications(c *model.Client, maxID string) (err error)
+ Bookmark(c *model.Client, id string) (err error)
+ UnBookmark(c *model.Client, id string) (err error)
}
type service struct {
@@ -109,13 +111,13 @@ func getRendererContext(c *model.Client) *renderer.Context {
settings = *model.NewSettings()
}
return &renderer.Context{
- HideAttachments: settings.HideAttachments,
- MaskNSFW: settings.MaskNSFW,
- ThreadInNewTab: settings.ThreadInNewTab,
- FluorideMode: settings.FluorideMode,
- DarkMode: settings.DarkMode,
- CSRFToken: session.CSRFToken,
- UserID: session.UserID,
+ HideAttachments: settings.HideAttachments,
+ MaskNSFW: settings.MaskNSFW,
+ ThreadInNewTab: settings.ThreadInNewTab,
+ FluorideMode: settings.FluorideMode,
+ DarkMode: settings.DarkMode,
+ CSRFToken: session.CSRFToken,
+ UserID: session.UserID,
AntiDopamineMode: settings.AntiDopamineMode,
}
}
@@ -464,6 +466,7 @@ func (svc *service) ServeUserPage(c *model.Client, id string, pageType string,
if err != nil {
return
}
+ isCurrent := c.Session.UserID == user.ID
switch pageType {
case "":
@@ -502,6 +505,18 @@ func (svc *service) ServeUserPage(c *model.Client, id string, pageType string,
nextLink = fmt.Sprintf("/user/%s/media?max_id=%s",
id, pg.MaxID)
}
+ case "bookmarks":
+ if !isCurrent {
+ return errInvalidArgument
+ }
+ statuses, err = c.GetBookmarks(ctx, &pg)
+ if err != nil {
+ return
+ }
+ if len(statuses) == 20 && len(pg.MaxID) > 0 {
+ nextLink = fmt.Sprintf("/user/%s/bookmarks?max_id=%s",
+ id, pg.MaxID)
+ }
default:
return errInvalidArgument
}
@@ -509,7 +524,7 @@ func (svc *service) ServeUserPage(c *model.Client, id string, pageType string,
commonData := svc.getCommonData(c, user.DisplayName)
data := &renderer.UserData{
User: user,
- IsCurrent: c.Session.UserID == user.ID,
+ IsCurrent: isCurrent,
Type: pageType,
Users: users,
Statuses: statuses,
@@ -890,3 +905,13 @@ func (svc *service) Delete(c *model.Client, id string) (err error) {
func (svc *service) ReadNotifications(c *model.Client, maxID string) (err error) {
return c.ReadNotifications(ctx, maxID)
}
+
+func (svc *service) Bookmark(c *model.Client, id string) (err error) {
+ _, err = c.Bookmark(ctx, id)
+ return
+}
+
+func (svc *service) UnBookmark(c *model.Client, id string) (err error) {
+ _, err = c.Unbookmark(ctx, id)
+ return
+}
diff --git a/service/transport.go b/service/transport.go
index 7d27a84..4f73c5e 100644
--- a/service/transport.go
+++ b/service/transport.go
@@ -76,7 +76,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
c := newClient(w, req, "")
err := s.ServeRootPage(c)
if err != nil {
- if (err == errInvalidAccessToken) {
+ if err == errInvalidAccessToken {
w.Header().Add("Location", "/signin")
w.WriteHeader(http.StatusFound)
return
@@ -676,6 +676,46 @@ func NewHandler(s Service, staticDir string) http.Handler {
w.WriteHeader(http.StatusFound)
}
+ bookmark := func(w http.ResponseWriter, req *http.Request) {
+ c := newClient(w, req, req.FormValue("csrf_token"))
+ id, _ := mux.Vars(req)["id"]
+ retweetedByID := req.FormValue("retweeted_by_id")
+
+ err := s.Bookmark(c, id)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ s.ServeErrorPage(c, err)
+ return
+ }
+
+ rID := id
+ if len(retweetedByID) > 0 {
+ rID = retweetedByID
+ }
+ w.Header().Add("Location", req.Header.Get("Referer")+"#status-"+rID)
+ w.WriteHeader(http.StatusFound)
+ }
+
+ unBookmark := func(w http.ResponseWriter, req *http.Request) {
+ c := newClient(w, req, req.FormValue("csrf_token"))
+ id, _ := mux.Vars(req)["id"]
+ retweetedByID := req.FormValue("retweeted_by_id")
+
+ err := s.UnBookmark(c, id)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ s.ServeErrorPage(c, err)
+ return
+ }
+
+ rID := id
+ if len(retweetedByID) > 0 {
+ rID = retweetedByID
+ }
+ w.Header().Add("Location", req.Header.Get("Referer")+"#status-"+rID)
+ w.WriteHeader(http.StatusFound)
+ }
+
signout := func(w http.ResponseWriter, req *http.Request) {
c := newClient(w, req, req.FormValue("csrf_token"))
@@ -791,6 +831,8 @@ func NewHandler(s Service, staticDir string) http.Handler {
r.HandleFunc("/unmuteconv/{id}", unMuteConversation).Methods(http.MethodPost)
r.HandleFunc("/delete/{id}", delete).Methods(http.MethodPost)
r.HandleFunc("/notifications/read", readNotifications).Methods(http.MethodPost)
+ r.HandleFunc("/bookmark/{id}", bookmark).Methods(http.MethodPost)
+ r.HandleFunc("/unbookmark/{id}", unBookmark).Methods(http.MethodPost)
r.HandleFunc("/signout", signout).Methods(http.MethodPost)
r.HandleFunc("/fluoride/like/{id}", fLike).Methods(http.MethodPost)
r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost)
diff --git a/templates/status.tmpl b/templates/status.tmpl
index 1e3d514..6c255a0 100644
--- a/templates/status.tmpl
+++ b/templates/status.tmpl
@@ -46,6 +46,19 @@
<input type="submit" value="mute" class="btn-link more-link">
</form>
{{end}}
+ {{if .Bookmarked}}
+ <form action="/unbookmark/{{.ID}}" method="post" target="_self">
+ <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
+ <input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}">
+ <input type="submit" value="unbookmark" class="btn-link more-link">
+ </form>
+ {{else}}
+ <form action="/bookmark/{{.ID}}" method="post" target="_self">
+ <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
+ <input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}">
+ <input type="submit" value="bookmark" class="btn-link more-link">
+ </form>
+ {{end}}
{{if eq $.Ctx.UserID .Account.ID}}
<form action="/delete/{{.ID}}" method="post" target="_self">
<input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
diff --git a/templates/user.tmpl b/templates/user.tmpl
index cb21b8a..3bb7523 100644
--- a/templates/user.tmpl
+++ b/templates/user.tmpl
@@ -97,6 +97,11 @@
<a href="/user/{{.User.ID}}/followers"> followers ({{.User.FollowersCount}}) </a> -
<a href="/user/{{.User.ID}}/media"> media </a>
</div>
+ {{if .IsCurrent}}
+ <div>
+ <a href="/user/{{.User.ID}}/bookmarks"> bookmarks </a>
+ </div>
+ {{end}}
<div>
<a href="/usersearch/{{.User.ID}}"> search statuses </a>
</div>
@@ -111,6 +116,8 @@
<div class="page-title"> Statuses </div>
{{range .Statuses}}
{{template "status.tmpl" (WithContext . $.Ctx)}}
+{{else}}
+<div class="no-data-found">No data found</div>
{{end}}
{{else if eq .Type "following"}}
@@ -125,6 +132,16 @@
<div class="page-title"> Statuses with media </div>
{{range .Statuses}}
{{template "status.tmpl" (WithContext . $.Ctx)}}
+{{else}}
+<div class="no-data-found">No data found</div>
+{{end}}
+
+{{else if eq .Type "bookmarks"}}
+<div class="page-title"> Bookmarks </div>
+{{range .Statuses}}
+{{template "status.tmpl" (WithContext . $.Ctx)}}
+{{else}}
+<div class="no-data-found">No data found</div>
{{end}}
{{end}}