2023-06-30 19:41:35 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
_ "embed"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"mime/multipart"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2023-07-16 02:07:19 +00:00
|
|
|
"os"
|
|
|
|
"regexp"
|
2023-06-30 19:41:35 +00:00
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/rystaf/go-lemmy"
|
|
|
|
"github.com/rystaf/go-lemmy/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Comment struct {
|
|
|
|
P types.CommentView
|
|
|
|
C []Comment
|
|
|
|
Selected bool
|
|
|
|
State *State
|
|
|
|
Op string
|
|
|
|
ChildCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Comment) Submitter() bool {
|
|
|
|
return c.P.Comment.CreatorID == c.P.Post.CreatorID
|
|
|
|
}
|
|
|
|
|
2023-07-13 13:45:51 +00:00
|
|
|
func (c *Comment) ParentID() int {
|
|
|
|
path := strings.Split(c.P.Comment.Path, ".")
|
|
|
|
id, _ := strconv.Atoi(path[len(path)-2])
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
2023-06-30 19:41:35 +00:00
|
|
|
type Person struct {
|
|
|
|
types.PersonViewSafe
|
|
|
|
}
|
|
|
|
|
|
|
|
type Activity struct {
|
|
|
|
Timestamp time.Time
|
|
|
|
Comment *Comment
|
|
|
|
Post *Post
|
|
|
|
Message *types.PrivateMessageView
|
|
|
|
}
|
|
|
|
|
|
|
|
type Post struct {
|
|
|
|
types.PostView
|
|
|
|
Rank int
|
|
|
|
State *State
|
|
|
|
}
|
|
|
|
|
|
|
|
type Session struct {
|
2023-07-24 02:12:01 +00:00
|
|
|
UserName string
|
|
|
|
UserID int
|
|
|
|
Communities []types.CommunityView
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type State struct {
|
2023-07-26 20:53:06 +00:00
|
|
|
Watch bool
|
2023-07-23 22:19:53 +00:00
|
|
|
Version string
|
2023-07-14 13:55:42 +00:00
|
|
|
Client *lemmy.Client
|
|
|
|
HTTPClient *http.Client
|
|
|
|
Session *Session
|
|
|
|
Status int
|
|
|
|
Error error
|
|
|
|
Alert string
|
|
|
|
Host string
|
|
|
|
CommunityName string
|
|
|
|
Community *types.GetCommunityResponse
|
|
|
|
TopCommunities []types.CommunityView
|
|
|
|
Communities []types.CommunityView
|
|
|
|
UnreadCount int64
|
|
|
|
Sort string
|
|
|
|
CommentSort string
|
|
|
|
Listing string
|
|
|
|
Page int
|
|
|
|
Parts []string
|
|
|
|
Posts []Post
|
|
|
|
Comments []Comment
|
|
|
|
Activities []Activity
|
|
|
|
CommentCount int
|
|
|
|
PostID int
|
|
|
|
CommentID int
|
|
|
|
Context int
|
|
|
|
UserName string
|
|
|
|
User *types.GetPersonDetailsResponse
|
|
|
|
Now int64
|
|
|
|
XHR bool
|
|
|
|
Op string
|
|
|
|
Site *types.GetSiteResponse
|
|
|
|
Query string
|
|
|
|
SearchType string
|
|
|
|
Captcha *types.CaptchaResponse
|
|
|
|
Dark bool
|
|
|
|
ShowNSFW bool
|
|
|
|
HideInstanceNames bool
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
|
2023-07-16 02:07:19 +00:00
|
|
|
func (s State) Unknown() string {
|
|
|
|
fmt.Println(fmt.Sprintf("%v", s.Error))
|
|
|
|
re := regexp.MustCompile(`(.*?)@(.*?)@`)
|
|
|
|
if strings.Contains(fmt.Sprintf("%v", s.Error), "couldnt_find_community") {
|
|
|
|
matches := re.FindAllStringSubmatch(s.CommunityName+"@", -1)
|
|
|
|
if len(matches) < 1 || len(matches[0]) < 3 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if matches[0][2] != s.Host {
|
|
|
|
remote := "/" + matches[0][2] + "/c/" + matches[0][1]
|
|
|
|
if os.Getenv("LEMMY_DOMAIN") != "" {
|
|
|
|
remote = "https:/" + remote
|
|
|
|
}
|
|
|
|
return remote
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if strings.Contains(fmt.Sprintf("%v", s.Error), "couldnt_find_that_username_or_email") {
|
|
|
|
matches := re.FindAllStringSubmatch(s.UserName+"@", -1)
|
|
|
|
if len(matches) < 1 || len(matches[0]) < 3 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if matches[0][2] != s.Host {
|
|
|
|
remote := "/" + matches[0][2] + "/u/" + matches[0][1]
|
|
|
|
if os.Getenv("LEMMY_DOMAIN") != "" {
|
|
|
|
remote = "https:/" + remote
|
|
|
|
}
|
|
|
|
return remote
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
2023-06-30 19:41:35 +00:00
|
|
|
func (p State) SortBy(v string) string {
|
|
|
|
var q string
|
|
|
|
if p.Query != "" || p.SearchType == "Communities" {
|
|
|
|
q = "q=" + p.Query + "&communityname=" + p.CommunityName + "&username=" + p.UserName + "&searchtype=" + p.SearchType + "&"
|
|
|
|
}
|
|
|
|
return "?" + q + "sort=" + v + "&listingType=" + p.Listing
|
|
|
|
}
|
|
|
|
func (p State) ListBy(v string) string {
|
|
|
|
var q string
|
|
|
|
if p.Query != "" || p.SearchType == "Communities" {
|
|
|
|
q = "q=" + p.Query + "&communityname=" + p.CommunityName + "&username=" + p.UserName + "&searchtype=" + p.SearchType + "&"
|
|
|
|
}
|
|
|
|
return "?" + q + "sort=" + p.Sort + "&listingType=" + v
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p State) PrevPage() string {
|
|
|
|
var listing string
|
|
|
|
if p.Listing != "All" {
|
|
|
|
listing = "&listingType=" + p.Listing
|
|
|
|
}
|
|
|
|
var q string
|
|
|
|
if p.Query != "" || p.SearchType == "Communities" {
|
|
|
|
q = "q=" + p.Query + "&communityname=" + p.CommunityName + "&username=" + p.UserName + "&searchtype=" + p.SearchType + "&"
|
|
|
|
}
|
|
|
|
page := strconv.Itoa(p.Page - 1)
|
|
|
|
return "?" + q + "sort=" + p.Sort + listing + "&page=" + page
|
|
|
|
}
|
|
|
|
func (p State) NextPage() string {
|
|
|
|
var listing string
|
|
|
|
if p.Listing != "All" {
|
|
|
|
listing = "&listingType=" + p.Listing
|
|
|
|
}
|
|
|
|
var q string
|
|
|
|
if p.Query != "" || p.SearchType == "Communities" {
|
|
|
|
q = "q=" + p.Query + "&communityname=" + p.CommunityName + "&username=" + p.UserName + "&searchtype=" + p.SearchType + "&"
|
|
|
|
}
|
|
|
|
page := strconv.Itoa(p.Page + 1)
|
|
|
|
return "?" + q + "sort=" + p.Sort + listing + "&page=" + page
|
|
|
|
}
|
|
|
|
func (p State) Rank(v int) int {
|
|
|
|
return ((p.Page - 1) * 25) + v + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *Person) FullUserName() string {
|
|
|
|
if u.Person.Local {
|
|
|
|
return u.Person.Name
|
|
|
|
}
|
|
|
|
l, err := url.Parse(u.Person.ActorID)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return u.Person.Name
|
|
|
|
}
|
|
|
|
return u.Person.Name + "@" + l.Host
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) ParseQuery(RawQuery string) {
|
|
|
|
if RawQuery == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
m, _ := url.ParseQuery(RawQuery)
|
|
|
|
if len(m["listingType"]) > 0 {
|
|
|
|
state.Listing = m["listingType"][0]
|
|
|
|
}
|
|
|
|
if len(m["sort"]) > 0 {
|
|
|
|
state.Sort = m["sort"][0]
|
2023-07-14 13:55:42 +00:00
|
|
|
state.CommentSort = m["sort"][0]
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
if len(m["communityname"]) > 0 {
|
|
|
|
state.CommunityName = m["communityname"][0]
|
|
|
|
}
|
|
|
|
if len(m["username"]) > 0 {
|
|
|
|
state.UserName = m["username"][0]
|
|
|
|
}
|
|
|
|
if len(m["q"]) > 0 {
|
|
|
|
state.Query = m["q"][0]
|
|
|
|
}
|
|
|
|
if len(m["xhr"]) > 0 {
|
|
|
|
state.XHR = true
|
|
|
|
}
|
2023-07-05 14:20:07 +00:00
|
|
|
if len(m["view"]) > 0 {
|
|
|
|
if m["view"][0] == "Saved" {
|
|
|
|
state.Op = "Saved"
|
|
|
|
}
|
|
|
|
}
|
2023-06-30 19:41:35 +00:00
|
|
|
//if len(m["op"]) > 0 {
|
|
|
|
// state.Op = m["op"][0]
|
|
|
|
//}
|
|
|
|
if len(m["page"]) > 0 {
|
|
|
|
i, _ := strconv.Atoi(m["page"][0])
|
|
|
|
state.Page = i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-01 14:57:04 +00:00
|
|
|
func (state *State) LemmyError(domain string) error {
|
|
|
|
var nodeInfo NodeInfo
|
|
|
|
res, err := state.HTTPClient.Get("https://" + domain + "/nodeinfo/2.0.json")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
|
|
return fmt.Errorf("Status Code: %v", res.StatusCode)
|
|
|
|
}
|
|
|
|
err = json.NewDecoder(res.Body).Decode(&nodeInfo)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if nodeInfo.Software.Name == "lemmy" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errors.New("Not a lemmy instance")
|
|
|
|
}
|
|
|
|
|
2023-06-30 19:41:35 +00:00
|
|
|
func (state *State) GetCaptcha() {
|
|
|
|
resp, err := state.Client.Captcha(context.Background(), types.GetCaptcha{})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Get %v %v", err, resp)
|
|
|
|
} else {
|
|
|
|
captcha, _ := resp.Ok.Value()
|
|
|
|
if resp.Ok.IsValid() {
|
|
|
|
state.Captcha = &captcha
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func (state *State) GetSite() {
|
|
|
|
resp, err := state.Client.Site(context.Background(), types.GetSite{})
|
|
|
|
if err != nil {
|
2023-07-20 23:35:42 +00:00
|
|
|
fmt.Println(err)
|
2023-06-30 19:41:35 +00:00
|
|
|
state.Status = http.StatusInternalServerError
|
2023-07-11 14:21:57 +00:00
|
|
|
state.Host = "."
|
2023-07-20 23:35:42 +00:00
|
|
|
state.Error = errors.New("unable to retrieve site")
|
2023-06-30 19:41:35 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
state.Site = resp
|
2023-07-24 02:12:01 +00:00
|
|
|
if !state.Site.MyUser.IsValid() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, c := range state.Site.MyUser.MustValue().Follows {
|
|
|
|
state.Session.Communities = append(state.Session.Communities, types.CommunityView{
|
|
|
|
Community: c.Community,
|
|
|
|
Subscribed: "Subscribed",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
sort.Slice(state.Session.Communities, func(a, b int) bool {
|
|
|
|
return state.Session.Communities[a].Community.Name < state.Session.Communities[b].Community.Name
|
|
|
|
})
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetComment(commentid int) {
|
2023-07-02 21:29:35 +00:00
|
|
|
if state.Sort != "Hot" && state.Sort != "Top" && state.Sort != "Old" && state.Sort != "New" {
|
|
|
|
state.Sort = "Hot"
|
|
|
|
}
|
2023-06-30 19:41:35 +00:00
|
|
|
state.CommentID = commentid
|
|
|
|
cresp, err := state.Client.Comments(context.Background(), types.GetComments{
|
|
|
|
ParentID: types.NewOptional(state.CommentID),
|
2023-07-14 13:55:42 +00:00
|
|
|
Sort: types.NewOptional(types.CommentSortType(state.CommentSort)),
|
2023-06-30 19:41:35 +00:00
|
|
|
Type: types.NewOptional(types.ListingType("All")),
|
2023-07-05 22:34:46 +00:00
|
|
|
Limit: types.NewOptional(int64(50)),
|
2023-06-30 19:41:35 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
}
|
|
|
|
state.CommentCount = len(cresp.Comments)
|
|
|
|
for _, c := range cresp.Comments {
|
|
|
|
if c.Comment.ID == state.CommentID {
|
|
|
|
state.PostID = c.Comment.PostID
|
|
|
|
//if state.Session != nil && state.Session.UserID
|
|
|
|
comment := Comment{
|
|
|
|
P: c,
|
|
|
|
Selected: !state.XHR,
|
|
|
|
State: state,
|
|
|
|
Op: state.Op,
|
|
|
|
}
|
|
|
|
getChildren(&comment, cresp.Comments, c.Post.CreatorID)
|
|
|
|
state.Comments = append(state.Comments, comment)
|
|
|
|
}
|
|
|
|
}
|
2023-07-13 13:45:51 +00:00
|
|
|
ctx, err := state.GetContext(state.Context, state.Comments[0])
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
} else {
|
|
|
|
state.Comments = []Comment{ctx}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func (state *State) GetContext(depth int, comment Comment) (ctx Comment, err error) {
|
|
|
|
if depth < 1 || comment.ParentID() == 0 {
|
|
|
|
return comment, nil
|
|
|
|
}
|
|
|
|
cresp, err := state.Client.Comment(context.Background(), types.GetComment{
|
|
|
|
ID: comment.ParentID(),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx, err = state.GetContext(depth-1, Comment{
|
|
|
|
P: cresp.CommentView,
|
|
|
|
State: state,
|
|
|
|
C: []Comment{comment},
|
|
|
|
ChildCount: comment.ChildCount + 1,
|
|
|
|
})
|
|
|
|
return
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
func (state *State) GetComments() {
|
2023-07-02 21:29:35 +00:00
|
|
|
if state.Sort != "Hot" && state.Sort != "Top" && state.Sort != "Old" && state.Sort != "New" {
|
|
|
|
state.Sort = "Hot"
|
|
|
|
}
|
2023-06-30 19:41:35 +00:00
|
|
|
cresp, err := state.Client.Comments(context.Background(), types.GetComments{
|
|
|
|
PostID: types.NewOptional(state.PostID),
|
2023-07-14 13:55:42 +00:00
|
|
|
Sort: types.NewOptional(types.CommentSortType(state.CommentSort)),
|
2023-06-30 19:41:35 +00:00
|
|
|
Type: types.NewOptional(types.ListingType("All")),
|
2023-07-05 22:34:46 +00:00
|
|
|
Limit: types.NewOptional(int64(50)),
|
2023-06-30 19:41:35 +00:00
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
state.Status = http.StatusInternalServerError
|
2023-07-02 21:29:35 +00:00
|
|
|
fmt.Println(err)
|
2023-06-30 19:41:35 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
state.CommentCount = len(cresp.Comments)
|
|
|
|
for _, c := range cresp.Comments {
|
|
|
|
levels := strings.Split(c.Comment.Path, ".")
|
|
|
|
if len(levels) != 2 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
comment := Comment{P: c, State: state}
|
|
|
|
var postCreatorID int
|
|
|
|
if len(state.Posts) > 0 {
|
|
|
|
postCreatorID = state.Posts[0].Post.CreatorID
|
|
|
|
}
|
|
|
|
getChildren(&comment, cresp.Comments, postCreatorID)
|
|
|
|
state.Comments = append(state.Comments, comment)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetMessages() {
|
|
|
|
if resp, err := state.Client.PrivateMessages(context.Background(), types.GetPrivateMessages{
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
}); err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
for _, m := range resp.PrivateMessages {
|
|
|
|
message := m
|
|
|
|
state.Activities = append(state.Activities, Activity{
|
|
|
|
Timestamp: m.PrivateMessage.Published.Time,
|
|
|
|
Message: &message,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if resp, err := state.Client.PersonMentions(context.Background(), types.GetPersonMentions{
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
}); err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
for _, m := range resp.Mentions {
|
|
|
|
var unread string
|
|
|
|
if !m.PersonMention.Read {
|
|
|
|
unread = "unread"
|
|
|
|
}
|
|
|
|
comment := Comment{
|
|
|
|
P: types.CommentView{
|
|
|
|
Comment: m.Comment,
|
|
|
|
},
|
|
|
|
Op: unread,
|
|
|
|
State: state,
|
|
|
|
}
|
|
|
|
state.Activities = append(state.Activities, Activity{
|
|
|
|
Timestamp: m.Comment.Published.Time,
|
|
|
|
Comment: &comment,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if resp, err := state.Client.Replies(context.Background(), types.GetReplies{
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
}); err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
for _, m := range resp.Replies {
|
|
|
|
var unread string
|
|
|
|
if !m.CommentReply.Read {
|
|
|
|
unread = "unread"
|
|
|
|
}
|
|
|
|
comment := Comment{
|
|
|
|
P: types.CommentView{
|
|
|
|
Comment: m.Comment,
|
|
|
|
Post: m.Post,
|
|
|
|
Creator: m.Creator,
|
|
|
|
Community: m.Community,
|
2023-07-08 15:26:41 +00:00
|
|
|
Counts: m.Counts,
|
2023-06-30 19:41:35 +00:00
|
|
|
},
|
|
|
|
Op: unread,
|
|
|
|
State: state,
|
|
|
|
}
|
|
|
|
state.Activities = append(state.Activities, Activity{
|
|
|
|
Timestamp: m.Comment.Published.Time,
|
|
|
|
Comment: &comment,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetUser(username string) {
|
|
|
|
state.UserName = username
|
|
|
|
limit := 12
|
|
|
|
if state.Op == "send_message" {
|
|
|
|
limit = 1
|
|
|
|
}
|
|
|
|
resp, err := state.Client.PersonDetails(context.Background(), types.GetPersonDetails{
|
2023-07-05 14:20:07 +00:00
|
|
|
Username: types.NewOptional(state.UserName),
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
Limit: types.NewOptional(int64(limit)),
|
|
|
|
SavedOnly: types.NewOptional(state.Op == "Saved"),
|
2023-06-30 19:41:35 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
2023-07-16 02:07:19 +00:00
|
|
|
state.Error = err
|
2023-06-30 19:41:35 +00:00
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
}
|
|
|
|
state.User = resp
|
|
|
|
if state.Query != "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for i, p := range resp.Posts {
|
|
|
|
post := Post{
|
|
|
|
PostView: resp.Posts[i],
|
|
|
|
Rank: -1,
|
|
|
|
State: state,
|
|
|
|
}
|
|
|
|
state.Activities = append(state.Activities, Activity{
|
|
|
|
Timestamp: p.Post.Published.Time,
|
|
|
|
Post: &post,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, c := range resp.Comments {
|
|
|
|
comment := Comment{P: c, State: state}
|
|
|
|
state.Activities = append(state.Activities, Activity{
|
|
|
|
Timestamp: c.Comment.Published.Time,
|
|
|
|
Comment: &comment,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
sort.Slice(state.Activities, func(i, j int) bool {
|
|
|
|
return state.Activities[i].Timestamp.After(state.Activities[j].Timestamp)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetUnreadCount() {
|
|
|
|
resp, err := state.Client.UnreadCount(context.Background(), types.GetUnreadCount{})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
state.UnreadCount = resp.PrivateMessages + resp.Mentions + resp.Replies
|
|
|
|
}
|
|
|
|
func (state *State) GetCommunities() {
|
|
|
|
resp, err := state.Client.Communities(context.Background(), types.ListCommunities{
|
|
|
|
Sort: types.NewOptional(types.SortType("TopAll")),
|
|
|
|
Limit: types.NewOptional(int64(20)),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
state.TopCommunities = resp.Communities
|
|
|
|
}
|
|
|
|
func (state *State) MarkAllAsRead() {
|
|
|
|
_, err := state.Client.MarkAllAsRead(context.Background(), types.MarkAllAsRead{})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetPosts() {
|
2023-07-05 20:59:23 +00:00
|
|
|
posts := types.GetPosts{
|
|
|
|
Sort: types.NewOptional(types.SortType(state.Sort)),
|
|
|
|
Type: types.NewOptional(types.ListingType(state.Listing)),
|
|
|
|
Limit: types.NewOptional(int64(25)),
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
}
|
|
|
|
if state.CommunityName != "" {
|
|
|
|
posts.CommunityName = types.NewOptional(state.CommunityName)
|
|
|
|
}
|
|
|
|
resp, err := state.Client.Posts(context.Background(), posts)
|
2023-06-30 19:41:35 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
for i, p := range resp.Posts {
|
|
|
|
state.Posts = append(state.Posts, Post{
|
|
|
|
PostView: p,
|
|
|
|
Rank: (state.Page-1)*25 + i + 1,
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) Search(searchtype string) {
|
|
|
|
if state.Query == "" && searchtype == "Communities" {
|
2023-07-23 17:53:02 +00:00
|
|
|
if state.Listing == "Subscribed" {
|
|
|
|
if state.Page > 1 {
|
|
|
|
return
|
|
|
|
}
|
2023-07-24 02:12:01 +00:00
|
|
|
if state.Site == nil {
|
|
|
|
state.GetSite()
|
2023-07-23 17:53:02 +00:00
|
|
|
}
|
2023-07-24 02:12:01 +00:00
|
|
|
state.Communities = state.Session.Communities
|
2023-07-23 17:53:02 +00:00
|
|
|
return
|
|
|
|
}
|
2023-06-30 19:41:35 +00:00
|
|
|
resp, err := state.Client.Communities(context.Background(), types.ListCommunities{
|
2023-07-23 17:53:02 +00:00
|
|
|
Type: types.NewOptional(types.ListingType(state.Listing)),
|
2023-06-30 19:41:35 +00:00
|
|
|
Sort: types.NewOptional(types.SortType(state.Sort)),
|
|
|
|
Limit: types.NewOptional(int64(25)),
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
state.Communities = resp.Communities
|
|
|
|
return
|
|
|
|
}
|
|
|
|
search := types.Search{
|
|
|
|
Q: state.Query,
|
|
|
|
Sort: types.NewOptional(types.SortType(state.Sort)),
|
2023-07-16 17:45:40 +00:00
|
|
|
ListingType: types.NewOptional(types.ListingType(state.Listing)),
|
2023-06-30 19:41:35 +00:00
|
|
|
Type: types.NewOptional(types.SearchType(searchtype)),
|
|
|
|
Limit: types.NewOptional(int64(25)),
|
|
|
|
Page: types.NewOptional(int64(state.Page)),
|
|
|
|
}
|
|
|
|
|
|
|
|
if state.CommunityName != "" {
|
|
|
|
search.CommunityName = types.NewOptional(state.CommunityName)
|
|
|
|
}
|
|
|
|
|
|
|
|
if state.User != nil {
|
|
|
|
search.CreatorID = types.NewOptional(state.User.PersonView.Person.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := state.Client.Search(context.Background(), search)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
state.Status = http.StatusInternalServerError
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
for i, p := range resp.Posts {
|
|
|
|
state.Posts = append(state.Posts, Post{
|
|
|
|
PostView: p,
|
|
|
|
Rank: (state.Page-1)*25 + i + 1,
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, c := range resp.Comments {
|
2023-07-13 13:45:51 +00:00
|
|
|
comment := Comment{
|
2023-06-30 19:41:35 +00:00
|
|
|
P: c,
|
|
|
|
State: state,
|
2023-07-13 13:45:51 +00:00
|
|
|
}
|
|
|
|
state.Activities = append(state.Activities, Activity{
|
|
|
|
Timestamp: c.Comment.Published.Time,
|
|
|
|
Comment: &comment,
|
2023-06-30 19:41:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
state.Communities = resp.Communities
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetPost(postid int) {
|
|
|
|
if postid == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
state.PostID = postid
|
|
|
|
// get post
|
|
|
|
resp, err := state.Client.Post(context.Background(), types.GetPost{
|
|
|
|
ID: types.NewOptional(state.PostID),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
state.Status = http.StatusInternalServerError
|
2023-07-16 13:00:49 +00:00
|
|
|
state.Error = err
|
2023-06-30 19:41:35 +00:00
|
|
|
return
|
|
|
|
}
|
2023-07-16 13:00:49 +00:00
|
|
|
state.Posts = []Post{Post{
|
|
|
|
PostView: resp.PostView,
|
|
|
|
State: state,
|
|
|
|
}}
|
|
|
|
if state.CommentID > 0 && len(state.Posts) > 0 {
|
|
|
|
state.Posts[0].Rank = -1
|
|
|
|
}
|
|
|
|
state.CommunityName = resp.PostView.Community.Name
|
|
|
|
cresp := types.GetCommunityResponse{
|
|
|
|
CommunityView: resp.CommunityView,
|
|
|
|
Moderators: resp.Moderators,
|
|
|
|
}
|
|
|
|
state.Community = &cresp
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) GetCommunity(communityName string) {
|
|
|
|
if communityName != "" {
|
|
|
|
state.CommunityName = communityName
|
|
|
|
}
|
|
|
|
if state.CommunityName == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
resp, err := state.Client.Community(context.Background(), types.GetCommunity{
|
|
|
|
Name: types.NewOptional(state.CommunityName),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
state.Error = err
|
|
|
|
} else {
|
|
|
|
state.Community = resp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (state *State) UploadImage(file multipart.File, header *multipart.FileHeader) (*PictrsResponse, error) {
|
|
|
|
defer file.Close()
|
|
|
|
body := new(bytes.Buffer)
|
|
|
|
writer := multipart.NewWriter(body)
|
|
|
|
part, err := writer.CreateFormFile("images[]", header.Filename)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
io.Copy(part, file)
|
|
|
|
writer.Close()
|
|
|
|
req, err := http.NewRequest("POST", "https://"+state.Host+"/pictrs/image", body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
req.Header.Set("Cookie", "jwt="+state.Client.Token)
|
|
|
|
res, err := state.HTTPClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
var pres PictrsResponse
|
|
|
|
if err := json.NewDecoder(res.Body).Decode(&pres); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if pres.Message != "ok" {
|
|
|
|
return &pres, errors.New(pres.Message)
|
|
|
|
}
|
|
|
|
return &pres, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getChildren(parent *Comment, pool []types.CommentView, postCreatorID int) {
|
|
|
|
var children []Comment
|
2023-07-13 22:24:03 +00:00
|
|
|
total := int32(0)
|
2023-06-30 19:41:35 +00:00
|
|
|
for _, c := range pool {
|
|
|
|
levels := strings.Split(c.Comment.Path, ".")
|
|
|
|
for i, l := range levels {
|
|
|
|
id, _ := strconv.Atoi(l)
|
|
|
|
if id == parent.P.Comment.ID {
|
|
|
|
if i == (len(levels) - 2) {
|
|
|
|
children = append(children, Comment{
|
|
|
|
P: c,
|
|
|
|
C: children,
|
|
|
|
State: parent.State,
|
|
|
|
})
|
2023-07-13 22:24:03 +00:00
|
|
|
total += c.Counts.ChildCount
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i, _ := range children {
|
|
|
|
getChildren(&children[i], pool, postCreatorID)
|
2023-07-13 22:24:03 +00:00
|
|
|
parent.ChildCount += 1
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|
|
|
|
parent.C = children
|
2023-07-13 22:24:03 +00:00
|
|
|
parent.P.Counts.ChildCount -= total
|
2023-06-30 19:41:35 +00:00
|
|
|
}
|