From 3faef9aeb9b62e207ffdffae1640c6e1ea40eb6b Mon Sep 17 00:00:00 2001 From: orangix Date: Tue, 15 Aug 2023 17:38:44 +0200 Subject: [PATCH] added user comments --- api/comments.go | 10 +-- api/user.go | 126 +++++++++++++++++++++--------- main.go | 3 +- pages/user.go | 53 ++++++++++++- views/partials/contextComment.hbs | 38 +++++++++ views/userComments.hbs | 47 +++++++++++ 6 files changed, 232 insertions(+), 45 deletions(-) create mode 100644 views/partials/contextComment.hbs create mode 100644 views/userComments.hbs diff --git a/api/comments.go b/api/comments.go index 3e9c31d..a61e41f 100644 --- a/api/comments.go +++ b/api/comments.go @@ -9,21 +9,21 @@ import ( "codeberg.org/rimgo/rimgo/utils" "github.com/dustin/go-humanize" "github.com/microcosm-cc/bluemonday" - "github.com/patrickmn/go-cache" "github.com/tidwall/gjson" "gitlab.com/golang-commonmark/linkify" ) type Comment struct { Comments []Comment - User User + User User + Post Submission Id string Comment string Upvotes int64 Downvotes int64 Platform string CreatedAt string - RelTime string + RelTime string UpdatedAt string DeletedAt string } @@ -55,7 +55,6 @@ func (client *Client) FetchComments(galleryID string) ([]Comment, error) { ) wg.Wait() - client.Cache.Set(galleryID + "-comments", comments, cache.DefaultExpiration) return comments, nil } @@ -130,13 +129,14 @@ func parseComment(data gjson.Result) Comment { Username: data.Get("account.username").String(), Avatar: userAvatar, }, + Post: parseSubmission(data.Get("post")), Id: data.Get("id").String(), Comment: comment, Upvotes: data.Get("upvote_count").Int(), Downvotes: data.Get("downvote_count").Int(), Platform: data.Get("platform").String(), CreatedAt: createdAt, - RelTime: humanize.Time(createdTime), + RelTime: humanize.Time(createdTime), UpdatedAt: updatedAt, DeletedAt: deletedAt, } diff --git a/api/user.go b/api/user.go index 3af2026..c98758c 100644 --- a/api/user.go +++ b/api/user.go @@ -8,6 +8,7 @@ import ( "time" "codeberg.org/rimgo/rimgo/utils" + "github.com/patrickmn/go-cache" "github.com/tidwall/gjson" ) @@ -64,7 +65,7 @@ func (client *Client) FetchUser(username string) (User, error) { CreatedAt: createdTime.Format("January 2, 2006"), } - client.Cache.Set(username + "-user", user, 1*time.Hour) + client.Cache.Set(username+"-user", user, 1*time.Hour) return user, nil } @@ -89,41 +90,7 @@ func (client *Client) FetchSubmissions(username string, sort string, page string go func() { defer wg.Done() - coverData := value.Get("images.#(id==\"" + value.Get("cover").String() + "\")") - cover := Media{ - Id: value.Get("id").String(), - Description: value.Get("description").String(), - Type: strings.Split(value.Get("type").String(), "/")[0], - Url: strings.ReplaceAll(value.Get("link").String(), "https://i.imgur.com", ""), - } - if coverData.Exists() { - cover = Media{ - Id: coverData.Get("id").String(), - Description: coverData.Get("description").String(), - Type: strings.Split(coverData.Get("type").String(), "/")[0], - Url: strings.ReplaceAll(coverData.Get("link").String(), "https://i.imgur.com", ""), - } - } - - id := value.Get("id").String() - - link := "/a/" + id - if value.Get("in_gallery").Bool() { - link = "/gallery/" + id - } - - submissions = append(submissions, Submission{ - Id: id, - Link: link, - Title: value.Get("title").String(), - Cover: cover, - Points: value.Get("points").Int(), - Upvotes: value.Get("ups").Int(), - Downvotes: value.Get("downs").Int(), - Comments: value.Get("comment_count").Int(), - Views: value.Get("views").Int(), - IsAlbum: value.Get("is_album").Bool(), - }) + submissions = append(submissions, parseSubmission(value)) }() return true @@ -131,6 +98,91 @@ func (client *Client) FetchSubmissions(username string, sort string, page string ) wg.Wait() - client.Cache.Set(username + "-submissions", submissions, 15*time.Minute) + client.Cache.Set(username+"-submissions", submissions, 15*time.Minute) return submissions, nil } + +func (client *Client) FetchUserComments(username string, page string) ([]Comment, error) { + req, err := http.NewRequest("GET", "https://api.imgur.com/comment/v1/comments", nil) + if err != nil { + return []Comment{}, err + } + utils.SetReqHeaders(req) + + q := req.URL.Query() + q.Add("client_id", client.ClientID) + q.Add("filter[account]", "eq:wouldaponybyanyothernamebeasoffencive") + q.Add("include", "account,post") + q.Add("sort", "new") + + req.URL.RawQuery = q.Encode() + + res, err := http.DefaultClient.Do(req) + if err != nil { + return []Comment{}, err + } + + body, err := io.ReadAll(res.Body) + if err != nil { + return []Comment{}, err + } + + data := gjson.Parse(string(body)) + + wg := sync.WaitGroup{} + comments := make([]Comment, 0) + data.Get("data").ForEach( + func(key, value gjson.Result) bool { + wg.Add(1) + + go func() { + defer wg.Done() + comments = append(comments, parseComment(value)) + }() + + return true + }, + ) + wg.Wait() + + client.Cache.Set(username+"-usercomments-"+page, comments, cache.DefaultExpiration) + return comments, nil +} + +func parseSubmission(value gjson.Result) Submission { + coverData := value.Get("images.#(id==\"" + value.Get("cover").String() + "\")") + cover := Media{ + Id: value.Get("id").String(), + Description: value.Get("description").String(), + Type: strings.Split(value.Get("type").String(), "/")[0], + Url: strings.ReplaceAll(value.Get("link").String(), "https://i.imgur.com", ""), + } + if coverData.Exists() { + cover = Media{ + Id: coverData.Get("id").String(), + Description: coverData.Get("description").String(), + Type: strings.Split(coverData.Get("type").String(), "/")[0], + Url: strings.ReplaceAll(coverData.Get("link").String(), "https://i.imgur.com", ""), + } + } + + id := value.Get("id").String() + + link := "/a/" + id + if value.Get("in_gallery").Bool() { + link = "/gallery/" + id + } + + return Submission{ + Id: id, + Link: link, + Title: value.Get("title").String(), + Cover: cover, + Points: value.Get("points").Int(), + Upvotes: value.Get("ups").Int(), + Downvotes: value.Get("downs").Int(), + Comments: value.Get("comment_count").Int(), + Views: value.Get("views").Int(), + IsAlbum: value.Get("is_album").Bool(), + } +} diff --git a/main.go b/main.go index 0a1cd52..881c6dc 100644 --- a/main.go +++ b/main.go @@ -121,8 +121,9 @@ func main() { app.Get("/a/:postID/embed", pages.HandleEmbed) app.Get("/t/:tag", pages.HandleTag) app.Get("/t/:tag/:postID", pages.HandlePost) - app.Get("/user/:userID", pages.HandleUser) app.Get("/r/:sub/:postID", pages.HandlePost) + app.Get("/user/:userID", pages.HandleUser) + app.Get("/user/:userID/comments", pages.HandleUserComments) app.Get("/user/:userID/cover", pages.HandleUserCover) app.Get("/user/:userID/avatar", pages.HandleUserAvatar) app.Get("/gallery/:postID", pages.HandlePost) diff --git a/pages/user.go b/pages/user.go index f38d50a..0a9cc4b 100644 --- a/pages/user.go +++ b/pages/user.go @@ -51,7 +51,56 @@ func HandleUser(c *fiber.Ctx) error { "user": user, "submissions": submissions, "page": page, - "nextPage": pageNumber + 1, - "prevPage": pageNumber - 1, + "nextPage": pageNumber + 1, + "prevPage": pageNumber - 1, + }) +} + +func HandleUserComments(c *fiber.Ctx) error { + utils.SetHeaders(c) + c.Set("X-Frame-Options", "DENY") + c.Set("Cache-Control", "public,max-age=604800") + c.Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'; media-src 'self'; style-src 'unsafe-inline' 'self'; img-src 'self'; manifest-src 'self'; block-all-mixed-content") + + page := "0" + if c.Query("page") != "" { + page = c.Query("page") + } + + pageNumber, err := strconv.Atoi(c.Query("page")) + if err != nil { + pageNumber = 0 + } + + user, err := ApiClient.FetchUser(c.Params("userID")) + if err != nil && err.Error() == "ratelimited by imgur" { + return c.Status(429).Render("errors/429", fiber.Map{ + "path": c.Path(), + }) + } + if err != nil { + return err + } + if user.Username == "" { + return c.Status(404).Render("errors/404", nil) + } + + comments, err := ApiClient.FetchUserComments(c.Params("userID"), page) + if err != nil && err.Error() == "ratelimited by imgur" { + c.Status(429) + return c.Render("errors/429", fiber.Map{ + "path": c.Path(), + }) + } + if err != nil { + return err + } + + return c.Render("userComments", fiber.Map{ + "user": user, + "comments": comments, + "page": page, + "nextPage": pageNumber + 1, + "prevPage": pageNumber - 1, }) } diff --git a/views/partials/contextComment.hbs b/views/partials/contextComment.hbs new file mode 100644 index 0000000..8088271 --- /dev/null +++ b/views/partials/contextComment.hbs @@ -0,0 +1,38 @@ + + +
+
+ {{#noteq this.User.Username "[deleted]"}} + +

+ {{this.User.Username}} + on post title here {{Post.Title}}

+ + {{/noteq}} + {{#equal this.User.Username "[deleted]"}} +

[deleted] + on post title here {{Post.Title}}

+ {{/equal}} +
+
+

{{{this.Comment}}}

+
+ {{this.RelTime}} + {{#if this.DeletedAt}} + (deleted {{this.DeletedAt}}) + {{/if}} + | + Likes + {{this.Upvotes}} + Dislikes + {{this.Downvotes}} +
+
+ {{#if this.Comments}} +
+ {{#each this.Comments}} + {{> partials/comment }} + {{/each}} +
+ {{/if}} +
\ No newline at end of file diff --git a/views/userComments.hbs b/views/userComments.hbs new file mode 100644 index 0000000..1069fd1 --- /dev/null +++ b/views/userComments.hbs @@ -0,0 +1,47 @@ + + + + + {{user.Username}} - rimgo + + {{> partials/head }} + + + + {{> partials/nav }} + +
+ {{> partials/searchBar }} +
+ +
+
+ +
+

{{user.Username}}

+

{{user.Points}} pts ยท {{user.CreatedAt}}

+
+
+

{{user.Bio}}

+
+ +
+
+ {{#each comments}} + {{> partials/contextComment }} + {{/each}} +
+ +
+ {{#equal page "0" }} + {{else}} + Previous page + {{/equal}} + Next page +
+
+ + {{> partials/footer }} + + + \ No newline at end of file