summaryrefslogtreecommitdiff
path: root/internal/processing
diff options
context:
space:
mode:
authorLibravatar Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com>2021-07-09 18:32:48 +0200
committerLibravatar GitHub <noreply@github.com>2021-07-09 18:32:48 +0200
commitc7da64922f8b41daaee1cb8fc2961f7fa1336737 (patch)
treeb1f9c946bd223267f87f2a77a7455974d8d5e5e9 /internal/processing
parentDocs (#94) (diff)
downloadgotosocial-c7da64922f8b41daaee1cb8fc2961f7fa1336737.tar.xz
favourites GET implementation (#95)
Diffstat (limited to 'internal/processing')
-rw-r--r--internal/processing/processor.go4
-rw-r--r--internal/processing/status/fave.go2
-rw-r--r--internal/processing/timeline.go123
3 files changed, 102 insertions, 27 deletions
diff --git a/internal/processing/processor.go b/internal/processing/processor.go
index 302368411..bb4cd2da7 100644
--- a/internal/processing/processor.go
+++ b/internal/processing/processor.go
@@ -151,7 +151,9 @@ type Processor interface {
// HomeTimelineGet returns statuses from the home timeline, with the given filters/parameters.
HomeTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode)
// PublicTimelineGet returns statuses from the public/local timeline, with the given filters/parameters.
- PublicTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) ([]*apimodel.Status, gtserror.WithCode)
+ PublicTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode)
+ // FavedTimelineGet returns faved statuses, with the given filters/parameters.
+ FavedTimelineGet(authed *oauth.Auth, maxID string, minID string, limit int) (*apimodel.StatusTimelineResponse, gtserror.WithCode)
// AuthorizeStreamingRequest returns a gotosocial account in exchange for an access token, or an error if the given token is not valid.
AuthorizeStreamingRequest(accessToken string) (*gtsmodel.Account, error)
diff --git a/internal/processing/status/fave.go b/internal/processing/status/fave.go
index 23f0d2944..0dfee6233 100644
--- a/internal/processing/status/fave.go
+++ b/internal/processing/status/fave.go
@@ -60,7 +60,7 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
}
if newFave {
- thisFaveID, err := id.NewRandomULID()
+ thisFaveID, err := id.NewULID()
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
diff --git a/internal/processing/timeline.go b/internal/processing/timeline.go
index 8f6b1d26b..b5cbf433a 100644
--- a/internal/processing/timeline.go
+++ b/internal/processing/timeline.go
@@ -31,33 +31,27 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
-func (p *processor) HomeTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode) {
+func (p *processor) packageStatusResponse(statuses []*apimodel.Status, path string, nextMaxID string, prevMinID string, limit int) (*apimodel.StatusTimelineResponse, gtserror.WithCode) {
resp := &apimodel.StatusTimelineResponse{
Statuses: []*apimodel.Status{},
}
-
- apiStatuses, err := p.timelineManager.HomeTimeline(authed.Account.ID, maxID, sinceID, minID, limit, local)
- if err != nil {
- return nil, gtserror.NewErrorInternalError(err)
- }
- resp.Statuses = apiStatuses
+ resp.Statuses = statuses
// prepare the next and previous links
- if len(apiStatuses) != 0 {
+ if len(statuses) != 0 {
nextLink := &url.URL{
Scheme: p.config.Protocol,
Host: p.config.Host,
- Path: "/api/v1/timelines/home",
- RawPath: url.PathEscape("api/v1/timelines/home"),
- RawQuery: fmt.Sprintf("limit=%d&max_id=%s", limit, apiStatuses[len(apiStatuses)-1].ID),
+ Path: path,
+ RawQuery: fmt.Sprintf("limit=%d&max_id=%s", limit, nextMaxID),
}
next := fmt.Sprintf("<%s>; rel=\"next\"", nextLink.String())
prevLink := &url.URL{
Scheme: p.config.Protocol,
Host: p.config.Host,
- Path: "/api/v1/timelines/home",
- RawQuery: fmt.Sprintf("limit=%d&min_id=%s", limit, apiStatuses[0].ID),
+ Path: path,
+ RawQuery: fmt.Sprintf("limit=%d&min_id=%s", limit, prevMinID),
}
prev := fmt.Sprintf("<%s>; rel=\"prev\"", prevLink.String())
resp.LinkHeader = fmt.Sprintf("%s, %s", next, prev)
@@ -66,37 +60,116 @@ func (p *processor) HomeTimelineGet(authed *oauth.Auth, maxID string, sinceID st
return resp, nil
}
-func (p *processor) PublicTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) ([]*apimodel.Status, gtserror.WithCode) {
+func (p *processor) HomeTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode) {
+ statuses, err := p.timelineManager.HomeTimeline(authed.Account.ID, maxID, sinceID, minID, limit, local)
+ if err != nil {
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
+ if len(statuses) == 0 {
+ return &apimodel.StatusTimelineResponse{
+ Statuses: []*apimodel.Status{},
+ }, nil
+ }
+
+ return p.packageStatusResponse(statuses, "api/v1/timelines/home", statuses[len(statuses)-1].ID, statuses[0].ID, limit)
+}
+
+func (p *processor) PublicTimelineGet(authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode) {
statuses, err := p.db.GetPublicTimelineForAccount(authed.Account.ID, maxID, sinceID, minID, limit, local)
if err != nil {
+ if _, ok := err.(db.ErrNoEntries); ok {
+ // there are just no entries left
+ return &apimodel.StatusTimelineResponse{
+ Statuses: []*apimodel.Status{},
+ }, nil
+ }
+ // there's an actual error
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
+ s, err := p.filterPublicStatuses(authed, statuses)
+ if err != nil {
+ return nil, gtserror.NewErrorInternalError(err)
+ }
+
+ return p.packageStatusResponse(s, "api/v1/timelines/public", s[len(s)-1].ID, s[0].ID, limit)
+}
+
+func (p *processor) FavedTimelineGet(authed *oauth.Auth, maxID string, minID string, limit int) (*apimodel.StatusTimelineResponse, gtserror.WithCode) {
+ statuses, nextMaxID, prevMinID, err := p.db.GetFavedTimelineForAccount(authed.Account.ID, maxID, minID, limit)
+ if err != nil {
+ if _, ok := err.(db.ErrNoEntries); ok {
+ // there are just no entries left
+ return &apimodel.StatusTimelineResponse{
+ Statuses: []*apimodel.Status{},
+ }, nil
+ }
+ // there's an actual error
return nil, gtserror.NewErrorInternalError(err)
}
- s, err := p.filterStatuses(authed, statuses)
+ s, err := p.filterFavedStatuses(authed, statuses)
if err != nil {
return nil, gtserror.NewErrorInternalError(err)
}
- return s, nil
+ return p.packageStatusResponse(s, "api/v1/favourites", nextMaxID, prevMinID, limit)
}
-func (p *processor) filterStatuses(authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) {
- l := p.log.WithField("func", "filterStatuses")
+func (p *processor) filterPublicStatuses(authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) {
+ l := p.log.WithField("func", "filterPublicStatuses")
apiStatuses := []*apimodel.Status{}
for _, s := range statuses {
targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(s.AccountID, targetAccount); err != nil {
if _, ok := err.(db.ErrNoEntries); ok {
- l.Debugf("skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
+ l.Debugf("filterPublicStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
continue
}
- return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error getting status author: %s", err))
+ return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
}
- timelineable, err := p.filter.StatusHometimelineable(s, authed.Account)
+ timelineable, err := p.filter.StatusPublictimelineable(s, authed.Account)
if err != nil {
- return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking status visibility: %s", err))
+ l.Debugf("filterPublicStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err)
+ continue
+ }
+ if !timelineable {
+ continue
+ }
+
+ apiStatus, err := p.tc.StatusToMasto(s, authed.Account)
+ if err != nil {
+ l.Debugf("filterPublicStatuses: skipping status %s because it couldn't be converted to its mastodon representation: %s", s.ID, err)
+ continue
+ }
+
+ apiStatuses = append(apiStatuses, apiStatus)
+ }
+
+ return apiStatuses, nil
+}
+
+func (p *processor) filterFavedStatuses(authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) {
+ l := p.log.WithField("func", "filterFavedStatuses")
+
+ apiStatuses := []*apimodel.Status{}
+ for _, s := range statuses {
+ targetAccount := &gtsmodel.Account{}
+ if err := p.db.GetByID(s.AccountID, targetAccount); err != nil {
+ if _, ok := err.(db.ErrNoEntries); ok {
+ l.Debugf("filterFavedStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
+ continue
+ }
+ return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
+ }
+
+ timelineable, err := p.filter.StatusVisible(s, authed.Account)
+ if err != nil {
+ l.Debugf("filterFavedStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err)
+ continue
}
if !timelineable {
continue
@@ -104,7 +177,7 @@ func (p *processor) filterStatuses(authed *oauth.Auth, statuses []*gtsmodel.Stat
apiStatus, err := p.tc.StatusToMasto(s, authed.Account)
if err != nil {
- l.Debugf("skipping status %s because it couldn't be converted to its mastodon representation: %s", s.ID, err)
+ l.Debugf("filterFavedStatuses: skipping status %s because it couldn't be converted to its mastodon representation: %s", s.ID, err)
continue
}
@@ -157,7 +230,7 @@ func (p *processor) initTimelineFor(account *gtsmodel.Account, wg *sync.WaitGrou
desiredIndexLength := p.timelineManager.GetDesiredIndexLength()
- statuses, err := p.db.GetStatusesWhereFollowing(account.ID, "", "", "", desiredIndexLength, false)
+ statuses, err := p.db.GetHomeTimelineForAccount(account.ID, "", "", "", desiredIndexLength, false)
if err != nil {
if _, ok := err.(db.ErrNoEntries); !ok {
l.Error(fmt.Errorf("initTimelineFor: error getting statuses: %s", err))
@@ -176,7 +249,7 @@ func (p *processor) initTimelineFor(account *gtsmodel.Account, wg *sync.WaitGrou
}
if rearmostStatusID != "" {
- moreStatuses, err := p.db.GetStatusesWhereFollowing(account.ID, rearmostStatusID, "", "", desiredIndexLength/2, false)
+ moreStatuses, err := p.db.GetHomeTimelineForAccount(account.ID, rearmostStatusID, "", "", desiredIndexLength/2, false)
if err != nil {
l.Error(fmt.Errorf("initTimelineFor: error getting more statuses: %s", err))
return