diff options
author | 2021-08-25 15:34:33 +0200 | |
---|---|---|
committer | 2021-08-25 15:34:33 +0200 | |
commit | 2dc9fc1626507bb54417fc4a1920b847cafb27a2 (patch) | |
tree | 4ddeac479b923db38090aac8bd9209f3646851c1 /internal/processing | |
parent | Manually approves followers (#146) (diff) | |
download | gotosocial-2dc9fc1626507bb54417fc4a1920b847cafb27a2.tar.xz |
Pg to bun (#148)
* start moving to bun
* changing more stuff
* more
* and yet more
* tests passing
* seems stable now
* more big changes
* small fix
* little fixes
Diffstat (limited to 'internal/processing')
59 files changed, 1023 insertions, 690 deletions
diff --git a/internal/processing/account.go b/internal/processing/account.go index f722c88eb..94ba596ac 100644 --- a/internal/processing/account.go +++ b/internal/processing/account.go @@ -19,51 +19,53 @@ package processing import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) AccountCreate(authed *oauth.Auth, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) { - return p.accountProcessor.Create(authed.Token, authed.Application, form) +func (p *processor) AccountCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) { + return p.accountProcessor.Create(ctx, authed.Token, authed.Application, form) } -func (p *processor) AccountGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Account, error) { - return p.accountProcessor.Get(authed.Account, targetAccountID) +func (p *processor) AccountGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Account, error) { + return p.accountProcessor.Get(ctx, authed.Account, targetAccountID) } -func (p *processor) AccountUpdate(authed *oauth.Auth, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) { - return p.accountProcessor.Update(authed.Account, form) +func (p *processor) AccountUpdate(ctx context.Context, authed *oauth.Auth, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) { + return p.accountProcessor.Update(ctx, authed.Account, form) } -func (p *processor) AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinnedOnly bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) { - return p.accountProcessor.StatusesGet(authed.Account, targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly) +func (p *processor) AccountStatusesGet(ctx context.Context, authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinnedOnly bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) { + return p.accountProcessor.StatusesGet(ctx, authed.Account, targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly) } -func (p *processor) AccountFollowersGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { - return p.accountProcessor.FollowersGet(authed.Account, targetAccountID) +func (p *processor) AccountFollowersGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { + return p.accountProcessor.FollowersGet(ctx, authed.Account, targetAccountID) } -func (p *processor) AccountFollowingGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { - return p.accountProcessor.FollowingGet(authed.Account, targetAccountID) +func (p *processor) AccountFollowingGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { + return p.accountProcessor.FollowingGet(ctx, authed.Account, targetAccountID) } -func (p *processor) AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { - return p.accountProcessor.RelationshipGet(authed.Account, targetAccountID) +func (p *processor) AccountRelationshipGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { + return p.accountProcessor.RelationshipGet(ctx, authed.Account, targetAccountID) } -func (p *processor) AccountFollowCreate(authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) { - return p.accountProcessor.FollowCreate(authed.Account, form) +func (p *processor) AccountFollowCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) { + return p.accountProcessor.FollowCreate(ctx, authed.Account, form) } -func (p *processor) AccountFollowRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { - return p.accountProcessor.FollowRemove(authed.Account, targetAccountID) +func (p *processor) AccountFollowRemove(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { + return p.accountProcessor.FollowRemove(ctx, authed.Account, targetAccountID) } -func (p *processor) AccountBlockCreate(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { - return p.accountProcessor.BlockCreate(authed.Account, targetAccountID) +func (p *processor) AccountBlockCreate(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { + return p.accountProcessor.BlockCreate(ctx, authed.Account, targetAccountID) } -func (p *processor) AccountBlockRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { - return p.accountProcessor.BlockRemove(authed.Account, targetAccountID) +func (p *processor) AccountBlockRemove(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { + return p.accountProcessor.BlockRemove(ctx, authed.Account, targetAccountID) } diff --git a/internal/processing/account/account.go b/internal/processing/account/account.go index 7b8910149..81701fd7c 100644 --- a/internal/processing/account/account.go +++ b/internal/processing/account/account.go @@ -19,6 +19,7 @@ package account import ( + "context" "mime/multipart" "github.com/sirupsen/logrus" @@ -38,40 +39,40 @@ import ( // Processor wraps a bunch of functions for processing account actions. type Processor interface { // Create processes the given form for creating a new account, returning an oauth token for that account if successful. - Create(applicationToken oauth2.TokenInfo, application *gtsmodel.Application, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) + Create(ctx context.Context, applicationToken oauth2.TokenInfo, application *gtsmodel.Application, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) // Delete deletes an account, and all of that account's statuses, media, follows, notifications, etc etc etc. // The origin passed here should be either the ID of the account doing the delete (can be itself), or the ID of a domain block. - Delete(account *gtsmodel.Account, origin string) error + Delete(ctx context.Context, account *gtsmodel.Account, origin string) error // Get processes the given request for account information. - Get(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Account, error) + Get(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Account, error) // Update processes the update of an account with the given form - Update(account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) + Update(ctx context.Context, account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) // StatusesGet fetches a number of statuses (in time descending order) from the given account, filtered by visibility for // the account given in authed. - StatusesGet(requestingAccount *gtsmodel.Account, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) + StatusesGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) // FollowersGet fetches a list of the target account's followers. - FollowersGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) + FollowersGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) // FollowingGet fetches a list of the accounts that target account is following. - FollowingGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) + FollowingGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) // RelationshipGet returns a relationship model describing the relationship of the targetAccount to the Authed account. - RelationshipGet(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + RelationshipGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // FollowCreate handles a follow request to an account, either remote or local. - FollowCreate(requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) + FollowCreate(ctx context.Context, requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) // FollowRemove handles the removal of a follow/follow request to an account, either remote or local. - FollowRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + FollowRemove(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // BlockCreate handles the creation of a block from requestingAccount to targetAccountID, either remote or local. - BlockCreate(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + BlockCreate(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // BlockRemove handles the removal of a block from requestingAccount to targetAccountID, either remote or local. - BlockRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + BlockRemove(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // UpdateHeader does the dirty work of checking the header part of an account update form, // parsing and checking the image, and doing the necessary updates in the database for this to become // the account's new header image. - UpdateAvatar(avatar *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) + UpdateAvatar(ctx context.Context, avatar *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) // UpdateAvatar does the dirty work of checking the avatar part of an account update form, // parsing and checking the image, and doing the necessary updates in the database for this to become // the account's new avatar image. - UpdateHeader(header *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) + UpdateHeader(ctx context.Context, header *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) } type processor struct { diff --git a/internal/processing/account/create.go b/internal/processing/account/create.go index 83e76973d..37c742b45 100644 --- a/internal/processing/account/create.go +++ b/internal/processing/account/create.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,16 +28,24 @@ import ( "github.com/superseriousbusiness/oauth2/v4" ) -func (p *processor) Create(applicationToken oauth2.TokenInfo, application *gtsmodel.Application, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) { +func (p *processor) Create(ctx context.Context, applicationToken oauth2.TokenInfo, application *gtsmodel.Application, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) { l := p.log.WithField("func", "accountCreate") - if err := p.db.IsEmailAvailable(form.Email); err != nil { + emailAvailable, err := p.db.IsEmailAvailable(ctx, form.Email) + if err != nil { return nil, err } + if !emailAvailable { + return nil, fmt.Errorf("email address %s in use", form.Email) + } - if err := p.db.IsUsernameAvailable(form.Username); err != nil { + usernameAvailable, err := p.db.IsUsernameAvailable(ctx, form.Username) + if err != nil { return nil, err } + if !usernameAvailable { + return nil, fmt.Errorf("username %s in use", form.Username) + } // don't store a reason if we don't require one reason := form.Reason @@ -45,7 +54,7 @@ func (p *processor) Create(applicationToken oauth2.TokenInfo, application *gtsmo } l.Trace("creating new username and account") - user, err := p.db.NewSignup(form.Username, text.RemoveHTML(reason), p.config.AccountsConfig.RequireApproval, form.Email, form.Password, form.IP, form.Locale, application.ID, false, false) + user, err := p.db.NewSignup(ctx, form.Username, text.RemoveHTML(reason), p.config.AccountsConfig.RequireApproval, form.Email, form.Password, form.IP, form.Locale, application.ID, false, false) if err != nil { return nil, fmt.Errorf("error creating new signup in the database: %s", err) } diff --git a/internal/processing/account/createblock.go b/internal/processing/account/createblock.go index f10a2efa3..06f82b37d 100644 --- a/internal/processing/account/createblock.go +++ b/internal/processing/account/createblock.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -29,18 +30,18 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { +func (p *processor) BlockCreate(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { // make sure the target account actually exists in our db - targetAccount, err := p.db.GetAccountByID(targetAccountID) + targetAccount, err := p.db.GetAccountByID(ctx, targetAccountID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: error getting account %s from the db: %s", targetAccountID, err)) } // if requestingAccount already blocks target account, we don't need to do anything - if blocked, err := p.db.IsBlocked(requestingAccount.ID, targetAccountID, false); err != nil { + if blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, targetAccountID, false); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error checking existence of block: %s", err)) } else if blocked { - return p.RelationshipGet(requestingAccount, targetAccountID) + return p.RelationshipGet(ctx, requestingAccount, targetAccountID) } // make the block @@ -57,18 +58,18 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou block.URI = util.GenerateURIForBlock(requestingAccount.Username, p.config.Protocol, p.config.Host, newBlockID) // whack it in the database - if err := p.db.Put(block); err != nil { + if err := p.db.Put(ctx, block); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error creating block in db: %s", err)) } // clear any follows or follow requests from the blocked account to the target account -- this is a simple delete - if err := p.db.DeleteWhere([]db.Where{ + if err := p.db.DeleteWhere(ctx, []db.Where{ {Key: "account_id", Value: targetAccountID}, {Key: "target_account_id", Value: requestingAccount.ID}, }, >smodel.Follow{}); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error removing follow in db: %s", err)) } - if err := p.db.DeleteWhere([]db.Where{ + if err := p.db.DeleteWhere(ctx, []db.Where{ {Key: "account_id", Value: targetAccountID}, {Key: "target_account_id", Value: requestingAccount.ID}, }, >smodel.FollowRequest{}); err != nil { @@ -82,12 +83,12 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou var frChanged bool var frURI string fr := >smodel.FollowRequest{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "account_id", Value: requestingAccount.ID}, {Key: "target_account_id", Value: targetAccountID}, }, fr); err == nil { frURI = fr.URI - if err := p.db.DeleteByID(fr.ID, fr); err != nil { + if err := p.db.DeleteByID(ctx, fr.ID, fr); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error removing follow request from db: %s", err)) } frChanged = true @@ -97,12 +98,12 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou var fChanged bool var fURI string f := >smodel.Follow{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "account_id", Value: requestingAccount.ID}, {Key: "target_account_id", Value: targetAccountID}, }, f); err == nil { fURI = f.URI - if err := p.db.DeleteByID(f.ID, f); err != nil { + if err := p.db.DeleteByID(ctx, f.ID, f); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockCreate: error removing follow from db: %s", err)) } fChanged = true @@ -147,5 +148,5 @@ func (p *processor) BlockCreate(requestingAccount *gtsmodel.Account, targetAccou TargetAccount: targetAccount, } - return p.RelationshipGet(requestingAccount, targetAccountID) + return p.RelationshipGet(ctx, requestingAccount, targetAccountID) } diff --git a/internal/processing/account/createfollow.go b/internal/processing/account/createfollow.go index 8c856a50e..a7767afea 100644 --- a/internal/processing/account/createfollow.go +++ b/internal/processing/account/createfollow.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -29,16 +30,16 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) { +func (p *processor) FollowCreate(ctx context.Context, requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) { // if there's a block between the accounts we shouldn't create the request ofc - if blocked, err := p.db.IsBlocked(requestingAccount.ID, form.ID, true); err != nil { + if blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, form.ID, true); err != nil { return nil, gtserror.NewErrorInternalError(err) } else if blocked { return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts")) } // make sure the target account actually exists in our db - targetAcct, err := p.db.GetAccountByID(form.ID) + targetAcct, err := p.db.GetAccountByID(ctx, form.ID) if err != nil { if err == db.ErrNoEntries { return nil, gtserror.NewErrorNotFound(fmt.Errorf("accountfollowcreate: account %s not found in the db: %s", form.ID, err)) @@ -47,19 +48,19 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim } // check if a follow exists already - if follows, err := p.db.IsFollowing(requestingAccount, targetAcct); err != nil { + if follows, err := p.db.IsFollowing(ctx, requestingAccount, targetAcct); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow in db: %s", err)) } else if follows { // already follows so just return the relationship - return p.RelationshipGet(requestingAccount, form.ID) + return p.RelationshipGet(ctx, requestingAccount, form.ID) } // check if a follow request exists already - if followRequested, err := p.db.IsFollowRequested(requestingAccount, targetAcct); err != nil { + if followRequested, err := p.db.IsFollowRequested(ctx, requestingAccount, targetAcct); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error checking follow request in db: %s", err)) } else if followRequested { // already follow requested so just return the relationship - return p.RelationshipGet(requestingAccount, form.ID) + return p.RelationshipGet(ctx, requestingAccount, form.ID) } // make the follow request @@ -84,17 +85,17 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim } // whack it in the database - if err := p.db.Put(fr); err != nil { + if err := p.db.Put(ctx, fr); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error creating follow request in db: %s", err)) } // if it's a local account that's not locked we can just straight up accept the follow request if !targetAcct.Locked && targetAcct.Domain == "" { - if _, err := p.db.AcceptFollowRequest(requestingAccount.ID, form.ID); err != nil { + if _, err := p.db.AcceptFollowRequest(ctx, requestingAccount.ID, form.ID); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error accepting folow request for local unlocked account: %s", err)) } // return the new relationship - return p.RelationshipGet(requestingAccount, form.ID) + return p.RelationshipGet(ctx, requestingAccount, form.ID) } // otherwise we leave the follow request as it is and we handle the rest of the process asynchronously @@ -107,5 +108,5 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim } // return whatever relationship results from this - return p.RelationshipGet(requestingAccount, form.ID) + return p.RelationshipGet(ctx, requestingAccount, form.ID) } diff --git a/internal/processing/account/delete.go b/internal/processing/account/delete.go index e8840abae..d97af4d2e 100644 --- a/internal/processing/account/delete.go +++ b/internal/processing/account/delete.go @@ -19,6 +19,7 @@ package account import ( + "context" "time" "github.com/sirupsen/logrus" @@ -48,7 +49,7 @@ import ( // 16. Delete account's user // 17. Delete account's timeline // 18. Delete account itself -func (p *processor) Delete(account *gtsmodel.Account, origin string) error { +func (p *processor) Delete(ctx context.Context, account *gtsmodel.Account, origin string) error { l := p.log.WithFields(logrus.Fields{ "func": "Delete", "username": account.Username, @@ -61,22 +62,22 @@ func (p *processor) Delete(account *gtsmodel.Account, origin string) error { if account.Domain == "" { // see if we can get a user for this account u := >smodel.User{} - if err := p.db.GetWhere([]db.Where{{Key: "account_id", Value: account.ID}}, u); err == nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, u); err == nil { // we got one! select all tokens with the user's ID tokens := []*oauth.Token{} - if err := p.db.GetWhere([]db.Where{{Key: "user_id", Value: u.ID}}, &tokens); err == nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "user_id", Value: u.ID}}, &tokens); err == nil { // we have some tokens to delete for _, t := range tokens { // delete client(s) associated with this token - if err := p.db.DeleteByID(t.ClientID, &oauth.Client{}); err != nil { + if err := p.db.DeleteByID(ctx, t.ClientID, &oauth.Client{}); err != nil { l.Errorf("error deleting oauth client: %s", err) } // delete application(s) associated with this token - if err := p.db.DeleteWhere([]db.Where{{Key: "client_id", Value: t.ClientID}}, >smodel.Application{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "client_id", Value: t.ClientID}}, >smodel.Application{}); err != nil { l.Errorf("error deleting application: %s", err) } // delete the token itself - if err := p.db.DeleteByID(t.ID, t); err != nil { + if err := p.db.DeleteByID(ctx, t.ID, t); err != nil { l.Errorf("error deleting oauth token: %s", err) } } @@ -87,12 +88,12 @@ func (p *processor) Delete(account *gtsmodel.Account, origin string) error { // 2. Delete account's blocks l.Debug("deleting account blocks") // first delete any blocks that this account created - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.Block{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.Block{}); err != nil { l.Errorf("error deleting blocks created by account: %s", err) } // now delete any blocks that target this account - if err := p.db.DeleteWhere([]db.Where{{Key: "target_account_id", Value: account.ID}}, &[]*gtsmodel.Block{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "target_account_id", Value: account.ID}}, &[]*gtsmodel.Block{}); err != nil { l.Errorf("error deleting blocks targeting account: %s", err) } @@ -103,12 +104,12 @@ func (p *processor) Delete(account *gtsmodel.Account, origin string) error { // TODO: federate these if necessary l.Debug("deleting account follow requests") // first delete any follow requests that this account created - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.FollowRequest{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.FollowRequest{}); err != nil { l.Errorf("error deleting follow requests created by account: %s", err) } // now delete any follow requests that target this account - if err := p.db.DeleteWhere([]db.Where{{Key: "target_account_id", Value: account.ID}}, &[]*gtsmodel.FollowRequest{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "target_account_id", Value: account.ID}}, &[]*gtsmodel.FollowRequest{}); err != nil { l.Errorf("error deleting follow requests targeting account: %s", err) } @@ -116,12 +117,12 @@ func (p *processor) Delete(account *gtsmodel.Account, origin string) error { // TODO: federate these if necessary l.Debug("deleting account follows") // first delete any follows that this account created - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.Follow{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.Follow{}); err != nil { l.Errorf("error deleting follows created by account: %s", err) } // now delete any follows that target this account - if err := p.db.DeleteWhere([]db.Where{{Key: "target_account_id", Value: account.ID}}, &[]*gtsmodel.Follow{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "target_account_id", Value: account.ID}}, &[]*gtsmodel.Follow{}); err != nil { l.Errorf("error deleting follows targeting account: %s", err) } @@ -133,7 +134,7 @@ func (p *processor) Delete(account *gtsmodel.Account, origin string) error { var maxID string selectStatusesLoop: for { - statuses, err := p.db.GetAccountStatuses(account.ID, 20, false, maxID, false, false) + statuses, err := p.db.GetAccountStatuses(ctx, account.ID, 20, false, maxID, false, false) if err != nil { if err == db.ErrNoEntries { // no statuses left for this instance so we're done @@ -157,7 +158,7 @@ selectStatusesLoop: TargetAccount: account, } - if err := p.db.DeleteByID(s.ID, s); err != nil { + if err := p.db.DeleteByID(ctx, s.ID, s); err != nil { if err != db.ErrNoEntries { // actual error has occurred l.Errorf("Delete: db error status %s for account %s: %s", s.ID, account.Username, err) @@ -167,7 +168,7 @@ selectStatusesLoop: // if there are any boosts of this status, delete them as well boosts := []*gtsmodel.Status{} - if err := p.db.GetWhere([]db.Where{{Key: "boost_of_id", Value: s.ID}}, &boosts); err != nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "boost_of_id", Value: s.ID}}, &boosts); err != nil { if err != db.ErrNoEntries { // an actual error has occurred l.Errorf("Delete: db error selecting boosts of status %s for account %s: %s", s.ID, account.Username, err) @@ -176,20 +177,24 @@ selectStatusesLoop: } for _, b := range boosts { - oa := >smodel.Account{} - if err := p.db.GetByID(b.AccountID, oa); err == nil { - - l.Debug("putting boost undo in the client api channel") - p.fromClientAPI <- gtsmodel.FromClientAPI{ - APObjectType: gtsmodel.ActivityStreamsAnnounce, - APActivityType: gtsmodel.ActivityStreamsUndo, - GTSModel: s, - OriginAccount: oa, - TargetAccount: account, + if b.Account == nil { + bAccount, err := p.db.GetAccountByID(ctx, b.AccountID) + if err != nil { + continue } + b.Account = bAccount } - if err := p.db.DeleteByID(b.ID, b); err != nil { + l.Debug("putting boost undo in the client api channel") + p.fromClientAPI <- gtsmodel.FromClientAPI{ + APObjectType: gtsmodel.ActivityStreamsAnnounce, + APActivityType: gtsmodel.ActivityStreamsUndo, + GTSModel: s, + OriginAccount: b.Account, + TargetAccount: account, + } + + if err := p.db.DeleteByID(ctx, b.ID, b); err != nil { if err != db.ErrNoEntries { // actual error has occurred l.Errorf("Delete: db error deleting boost with id %s: %s", b.ID, err) @@ -208,26 +213,26 @@ selectStatusesLoop: // 10. Delete account's notifications l.Debug("deleting account notifications") - if err := p.db.DeleteWhere([]db.Where{{Key: "origin_account_id", Value: account.ID}}, &[]*gtsmodel.Notification{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "origin_account_id", Value: account.ID}}, &[]*gtsmodel.Notification{}); err != nil { l.Errorf("error deleting notifications created by account: %s", err) } // 11. Delete account's bookmarks l.Debug("deleting account bookmarks") - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.StatusBookmark{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.StatusBookmark{}); err != nil { l.Errorf("error deleting bookmarks created by account: %s", err) } // 12. Delete account's faves // TODO: federate these if necessary l.Debug("deleting account faves") - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.StatusFave{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.StatusFave{}); err != nil { l.Errorf("error deleting faves created by account: %s", err) } // 13. Delete account's mutes l.Debug("deleting account mutes") - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.StatusMute{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, &[]*gtsmodel.StatusMute{}); err != nil { l.Errorf("error deleting status mutes created by account: %s", err) } @@ -239,7 +244,7 @@ selectStatusesLoop: // 16. Delete account's user l.Debug("deleting account user") - if err := p.db.DeleteWhere([]db.Where{{Key: "account_id", Value: account.ID}}, >smodel.User{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "account_id", Value: account.ID}}, >smodel.User{}); err != nil { return err } @@ -266,7 +271,8 @@ selectStatusesLoop: account.SuspendedAt = time.Now() account.SuspensionOrigin = origin - if err := p.db.UpdateByID(account.ID, account); err != nil { + account, err := p.db.UpdateAccount(ctx, account) + if err != nil { return err } diff --git a/internal/processing/account/get.go b/internal/processing/account/get.go index 3dfc54b51..5f039127c 100644 --- a/internal/processing/account/get.go +++ b/internal/processing/account/get.go @@ -19,6 +19,7 @@ package account import ( + "context" "errors" "fmt" @@ -27,9 +28,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Get(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Account, error) { - targetAccount := >smodel.Account{} - if err := p.db.GetByID(targetAccountID, targetAccount); err != nil { +func (p *processor) Get(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Account, error) { + targetAccount, err := p.db.GetAccountByID(ctx, targetAccountID) + if err != nil { if err == db.ErrNoEntries { return nil, errors.New("account not found") } @@ -37,9 +38,8 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetAccountID str } var blocked bool - var err error if requestingAccount != nil { - blocked, err = p.db.IsBlocked(requestingAccount.ID, targetAccountID, true) + blocked, err = p.db.IsBlocked(ctx, requestingAccount.ID, targetAccountID, true) if err != nil { return nil, fmt.Errorf("error checking account block: %s", err) } @@ -47,7 +47,7 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetAccountID str var mastoAccount *apimodel.Account if blocked { - mastoAccount, err = p.tc.AccountToMastoBlocked(targetAccount) + mastoAccount, err = p.tc.AccountToMastoBlocked(ctx, targetAccount) if err != nil { return nil, fmt.Errorf("error converting account: %s", err) } @@ -56,16 +56,16 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetAccountID str // last-minute check to make sure we have remote account header/avi cached if targetAccount.Domain != "" { - a, err := p.federator.EnrichRemoteAccount(requestingAccount.Username, targetAccount) + a, err := p.federator.EnrichRemoteAccount(ctx, requestingAccount.Username, targetAccount) if err == nil { targetAccount = a } } if requestingAccount != nil && targetAccount.ID == requestingAccount.ID { - mastoAccount, err = p.tc.AccountToMastoSensitive(targetAccount) + mastoAccount, err = p.tc.AccountToMastoSensitive(ctx, targetAccount) } else { - mastoAccount, err = p.tc.AccountToMastoPublic(targetAccount) + mastoAccount, err = p.tc.AccountToMastoPublic(ctx, targetAccount) } if err != nil { return nil, fmt.Errorf("error converting account: %s", err) diff --git a/internal/processing/account/getfollowers.go b/internal/processing/account/getfollowers.go index 4f66b40ee..517467085 100644 --- a/internal/processing/account/getfollowers.go +++ b/internal/processing/account/getfollowers.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,15 +28,15 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { - if blocked, err := p.db.IsBlocked(requestingAccount.ID, targetAccountID, true); err != nil { +func (p *processor) FollowersGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { + if blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, targetAccountID, true); err != nil { return nil, gtserror.NewErrorInternalError(err) } else if blocked { return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts")) } accounts := []apimodel.Account{} - follows, err := p.db.GetAccountFollowedBy(targetAccountID, false) + follows, err := p.db.GetAccountFollowedBy(ctx, targetAccountID, false) if err != nil { if err == db.ErrNoEntries { return accounts, nil @@ -44,7 +45,7 @@ func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAcco } for _, f := range follows { - blocked, err := p.db.IsBlocked(requestingAccount.ID, f.AccountID, true) + blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, f.AccountID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -53,7 +54,7 @@ func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAcco } if f.Account == nil { - a, err := p.db.GetAccountByID(f.AccountID) + a, err := p.db.GetAccountByID(ctx, f.AccountID) if err != nil { if err == db.ErrNoEntries { continue @@ -63,7 +64,7 @@ func (p *processor) FollowersGet(requestingAccount *gtsmodel.Account, targetAcco f.Account = a } - account, err := p.tc.AccountToMastoPublic(f.Account) + account, err := p.tc.AccountToMastoPublic(ctx, f.Account) if err != nil { return nil, gtserror.NewErrorInternalError(err) } diff --git a/internal/processing/account/getfollowing.go b/internal/processing/account/getfollowing.go index c7fb426f9..543213f90 100644 --- a/internal/processing/account/getfollowing.go +++ b/internal/processing/account/getfollowing.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,15 +28,15 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { - if blocked, err := p.db.IsBlocked(requestingAccount.ID, targetAccountID, true); err != nil { +func (p *processor) FollowingGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) { + if blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, targetAccountID, true); err != nil { return nil, gtserror.NewErrorInternalError(err) } else if blocked { return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts")) } accounts := []apimodel.Account{} - follows, err := p.db.GetAccountFollows(targetAccountID) + follows, err := p.db.GetAccountFollows(ctx, targetAccountID) if err != nil { if err == db.ErrNoEntries { return accounts, nil @@ -44,7 +45,7 @@ func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAcco } for _, f := range follows { - blocked, err := p.db.IsBlocked(requestingAccount.ID, f.AccountID, true) + blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, f.AccountID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -53,7 +54,7 @@ func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAcco } if f.TargetAccount == nil { - a, err := p.db.GetAccountByID(f.TargetAccountID) + a, err := p.db.GetAccountByID(ctx, f.TargetAccountID) if err != nil { if err == db.ErrNoEntries { continue @@ -63,7 +64,7 @@ func (p *processor) FollowingGet(requestingAccount *gtsmodel.Account, targetAcco f.TargetAccount = a } - account, err := p.tc.AccountToMastoPublic(f.TargetAccount) + account, err := p.tc.AccountToMastoPublic(ctx, f.TargetAccount) if err != nil { return nil, gtserror.NewErrorInternalError(err) } diff --git a/internal/processing/account/getrelationship.go b/internal/processing/account/getrelationship.go index a0a93a4c2..ebfd9b479 100644 --- a/internal/processing/account/getrelationship.go +++ b/internal/processing/account/getrelationship.go @@ -19,6 +19,7 @@ package account import ( + "context" "errors" "fmt" @@ -27,17 +28,17 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) RelationshipGet(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { +func (p *processor) RelationshipGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { if requestingAccount == nil { return nil, gtserror.NewErrorForbidden(errors.New("not authed")) } - gtsR, err := p.db.GetRelationship(requestingAccount.ID, targetAccountID) + gtsR, err := p.db.GetRelationship(ctx, requestingAccount.ID, targetAccountID) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relationship: %s", err)) } - r, err := p.tc.RelationshipToMasto(gtsR) + r, err := p.tc.RelationshipToMasto(ctx, gtsR) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting relationship: %s", err)) } diff --git a/internal/processing/account/getstatuses.go b/internal/processing/account/getstatuses.go index dc21e7006..dc157e43c 100644 --- a/internal/processing/account/getstatuses.go +++ b/internal/processing/account/getstatuses.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) StatusesGet(requestingAccount *gtsmodel.Account, targetAccountID string, limit int, excludeReplies bool, maxID string, pinnedOnly bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) { - if blocked, err := p.db.IsBlocked(requestingAccount.ID, targetAccountID, true); err != nil { +func (p *processor) StatusesGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string, limit int, excludeReplies bool, maxID string, pinnedOnly bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) { + if blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, targetAccountID, true); err != nil { return nil, gtserror.NewErrorInternalError(err) } else if blocked { return nil, gtserror.NewErrorNotFound(fmt.Errorf("block exists between accounts")) @@ -36,7 +37,7 @@ func (p *processor) StatusesGet(requestingAccount *gtsmodel.Account, targetAccou apiStatuses := []apimodel.Status{} - statuses, err := p.db.GetAccountStatuses(targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly) + statuses, err := p.db.GetAccountStatuses(ctx, targetAccountID, limit, excludeReplies, maxID, pinnedOnly, mediaOnly) if err != nil { if err == db.ErrNoEntries { return apiStatuses, nil @@ -45,12 +46,12 @@ func (p *processor) StatusesGet(requestingAccount *gtsmodel.Account, targetAccou } for _, s := range statuses { - visible, err := p.filter.StatusVisible(s, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, s, requestingAccount) if err != nil || !visible { continue } - apiStatus, err := p.tc.StatusToMasto(s, requestingAccount) + apiStatus, err := p.tc.StatusToMasto(ctx, s, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status to masto: %s", err)) } diff --git a/internal/processing/account/removeblock.go b/internal/processing/account/removeblock.go index 7c1f2bc17..7e3d78076 100644 --- a/internal/processing/account/removeblock.go +++ b/internal/processing/account/removeblock.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,9 +28,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { +func (p *processor) BlockRemove(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { // make sure the target account actually exists in our db - targetAccount, err := p.db.GetAccountByID(targetAccountID) + targetAccount, err := p.db.GetAccountByID(ctx, targetAccountID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("BlockCreate: error getting account %s from the db: %s", targetAccountID, err)) } @@ -37,13 +38,13 @@ func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccou // check if a block exists, and remove it if it does (storing the URI for later) var blockChanged bool block := >smodel.Block{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "account_id", Value: requestingAccount.ID}, {Key: "target_account_id", Value: targetAccountID}, }, block); err == nil { block.Account = requestingAccount block.TargetAccount = targetAccount - if err := p.db.DeleteByID(block.ID, >smodel.Block{}); err != nil { + if err := p.db.DeleteByID(ctx, block.ID, >smodel.Block{}); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("BlockRemove: error removing block from db: %s", err)) } blockChanged = true @@ -61,5 +62,5 @@ func (p *processor) BlockRemove(requestingAccount *gtsmodel.Account, targetAccou } // return whatever relationship results from all this - return p.RelationshipGet(requestingAccount, targetAccountID) + return p.RelationshipGet(ctx, requestingAccount, targetAccountID) } diff --git a/internal/processing/account/removefollow.go b/internal/processing/account/removefollow.go index 6646d694e..6186c550f 100644 --- a/internal/processing/account/removefollow.go +++ b/internal/processing/account/removefollow.go @@ -19,6 +19,7 @@ package account import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,9 +28,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { +func (p *processor) FollowRemove(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) { // if there's a block between the accounts we shouldn't do anything - blocked, err := p.db.IsBlocked(requestingAccount.ID, targetAccountID, true) + blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, targetAccountID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -38,8 +39,8 @@ func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAcco } // make sure the target account actually exists in our db - targetAcct := >smodel.Account{} - if err := p.db.GetByID(targetAccountID, targetAcct); err != nil { + targetAcct, err := p.db.GetAccountByID(ctx, targetAccountID) + if err != nil { if err == db.ErrNoEntries { return nil, gtserror.NewErrorNotFound(fmt.Errorf("AccountFollowRemove: account %s not found in the db: %s", targetAccountID, err)) } @@ -49,12 +50,12 @@ func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAcco var frChanged bool var frURI string fr := >smodel.FollowRequest{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "account_id", Value: requestingAccount.ID}, {Key: "target_account_id", Value: targetAccountID}, }, fr); err == nil { frURI = fr.URI - if err := p.db.DeleteByID(fr.ID, fr); err != nil { + if err := p.db.DeleteByID(ctx, fr.ID, fr); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("AccountFollowRemove: error removing follow request from db: %s", err)) } frChanged = true @@ -64,12 +65,12 @@ func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAcco var fChanged bool var fURI string f := >smodel.Follow{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "account_id", Value: requestingAccount.ID}, {Key: "target_account_id", Value: targetAccountID}, }, f); err == nil { fURI = f.URI - if err := p.db.DeleteByID(f.ID, f); err != nil { + if err := p.db.DeleteByID(ctx, f.ID, f); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("AccountFollowRemove: error removing follow from db: %s", err)) } fChanged = true @@ -106,5 +107,5 @@ func (p *processor) FollowRemove(requestingAccount *gtsmodel.Account, targetAcco } // return whatever relationship results from all this - return p.RelationshipGet(requestingAccount, targetAccountID) + return p.RelationshipGet(ctx, requestingAccount, targetAccountID) } diff --git a/internal/processing/account/update.go b/internal/processing/account/update.go index df842bacd..99ccbf5a0 100644 --- a/internal/processing/account/update.go +++ b/internal/processing/account/update.go @@ -20,6 +20,7 @@ package account import ( "bytes" + "context" "errors" "fmt" "io" @@ -32,17 +33,17 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) { +func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) { l := p.log.WithField("func", "AccountUpdate") if form.Discoverable != nil { - if err := p.db.UpdateOneByID(account.ID, "discoverable", *form.Discoverable, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "discoverable", *form.Discoverable, >smodel.Account{}); err != nil { return nil, fmt.Errorf("error updating discoverable: %s", err) } } if form.Bot != nil { - if err := p.db.UpdateOneByID(account.ID, "bot", *form.Bot, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "bot", *form.Bot, >smodel.Account{}); err != nil { return nil, fmt.Errorf("error updating bot: %s", err) } } @@ -52,7 +53,7 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede return nil, err } displayName := text.RemoveHTML(*form.DisplayName) // no html allowed in display name - if err := p.db.UpdateOneByID(account.ID, "display_name", displayName, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "display_name", displayName, >smodel.Account{}); err != nil { return nil, err } } @@ -62,13 +63,13 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede return nil, err } note := text.SanitizeHTML(*form.Note) // html OK in note but sanitize it - if err := p.db.UpdateOneByID(account.ID, "note", note, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "note", note, >smodel.Account{}); err != nil { return nil, err } } if form.Avatar != nil && form.Avatar.Size != 0 { - avatarInfo, err := p.UpdateAvatar(form.Avatar, account.ID) + avatarInfo, err := p.UpdateAvatar(ctx, form.Avatar, account.ID) if err != nil { return nil, err } @@ -76,7 +77,7 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede } if form.Header != nil && form.Header.Size != 0 { - headerInfo, err := p.UpdateHeader(form.Header, account.ID) + headerInfo, err := p.UpdateHeader(ctx, form.Header, account.ID) if err != nil { return nil, err } @@ -84,7 +85,7 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede } if form.Locked != nil { - if err := p.db.UpdateOneByID(account.ID, "locked", *form.Locked, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "locked", *form.Locked, >smodel.Account{}); err != nil { return nil, err } } @@ -94,13 +95,13 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede if err := util.ValidateLanguage(*form.Source.Language); err != nil { return nil, err } - if err := p.db.UpdateOneByID(account.ID, "language", *form.Source.Language, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "language", *form.Source.Language, >smodel.Account{}); err != nil { return nil, err } } if form.Source.Sensitive != nil { - if err := p.db.UpdateOneByID(account.ID, "locked", *form.Locked, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "locked", *form.Locked, >smodel.Account{}); err != nil { return nil, err } } @@ -109,15 +110,15 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede if err := util.ValidatePrivacy(*form.Source.Privacy); err != nil { return nil, err } - if err := p.db.UpdateOneByID(account.ID, "privacy", *form.Source.Privacy, >smodel.Account{}); err != nil { + if err := p.db.UpdateOneByID(ctx, account.ID, "privacy", *form.Source.Privacy, >smodel.Account{}); err != nil { return nil, err } } } // fetch the account with all updated values set - updatedAccount := >smodel.Account{} - if err := p.db.GetByID(account.ID, updatedAccount); err != nil { + updatedAccount, err := p.db.GetAccountByID(ctx, account.ID) + if err != nil { return nil, fmt.Errorf("could not fetch updated account %s: %s", account.ID, err) } @@ -128,7 +129,7 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede OriginAccount: updatedAccount, } - acctSensitive, err := p.tc.AccountToMastoSensitive(updatedAccount) + acctSensitive, err := p.tc.AccountToMastoSensitive(ctx, updatedAccount) if err != nil { return nil, fmt.Errorf("could not convert account into mastosensitive account: %s", err) } @@ -138,7 +139,7 @@ func (p *processor) Update(account *gtsmodel.Account, form *apimodel.UpdateCrede // UpdateAvatar does the dirty work of checking the avatar part of an account update form, // parsing and checking the image, and doing the necessary updates in the database for this to become // the account's new avatar image. -func (p *processor) UpdateAvatar(avatar *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) { +func (p *processor) UpdateAvatar(ctx context.Context, avatar *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) { var err error if int(avatar.Size) > p.config.MediaConfig.MaxImageSize { err = fmt.Errorf("avatar with size %d exceeded max image size of %d bytes", avatar.Size, p.config.MediaConfig.MaxImageSize) @@ -160,7 +161,7 @@ func (p *processor) UpdateAvatar(avatar *multipart.FileHeader, accountID string) } // do the setting - avatarInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(buf.Bytes(), accountID, media.Avatar, "") + avatarInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(ctx, buf.Bytes(), accountID, media.Avatar, "") if err != nil { return nil, fmt.Errorf("error processing avatar: %s", err) } @@ -171,7 +172,7 @@ func (p *processor) UpdateAvatar(avatar *multipart.FileHeader, accountID string) // UpdateHeader does the dirty work of checking the header part of an account update form, // parsing and checking the image, and doing the necessary updates in the database for this to become // the account's new header image. -func (p *processor) UpdateHeader(header *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) { +func (p *processor) UpdateHeader(ctx context.Context, header *multipart.FileHeader, accountID string) (*gtsmodel.MediaAttachment, error) { var err error if int(header.Size) > p.config.MediaConfig.MaxImageSize { err = fmt.Errorf("header with size %d exceeded max image size of %d bytes", header.Size, p.config.MediaConfig.MaxImageSize) @@ -193,7 +194,7 @@ func (p *processor) UpdateHeader(header *multipart.FileHeader, accountID string) } // do the setting - headerInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(buf.Bytes(), accountID, media.Header, "") + headerInfo, err := p.mediaHandler.ProcessHeaderOrAvatar(ctx, buf.Bytes(), accountID, media.Header, "") if err != nil { return nil, fmt.Errorf("error processing header: %s", err) } diff --git a/internal/processing/admin.go b/internal/processing/admin.go index 9a38f5ec1..48faee986 100644 --- a/internal/processing/admin.go +++ b/internal/processing/admin.go @@ -19,31 +19,33 @@ package processing import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) AdminEmojiCreate(authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) { - return p.adminProcessor.EmojiCreate(authed.Account, authed.User, form) +func (p *processor) AdminEmojiCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) { + return p.adminProcessor.EmojiCreate(ctx, authed.Account, authed.User, form) } -func (p *processor) AdminDomainBlockCreate(authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) (*apimodel.DomainBlock, gtserror.WithCode) { - return p.adminProcessor.DomainBlockCreate(authed.Account, form.Domain, form.Obfuscate, form.PublicComment, form.PrivateComment, "") +func (p *processor) AdminDomainBlockCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) (*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlockCreate(ctx, authed.Account, form.Domain, form.Obfuscate, form.PublicComment, form.PrivateComment, "") } -func (p *processor) AdminDomainBlocksImport(authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) ([]*apimodel.DomainBlock, gtserror.WithCode) { - return p.adminProcessor.DomainBlocksImport(authed.Account, form.Domains) +func (p *processor) AdminDomainBlocksImport(ctx context.Context, authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) ([]*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlocksImport(ctx, authed.Account, form.Domains) } -func (p *processor) AdminDomainBlocksGet(authed *oauth.Auth, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) { - return p.adminProcessor.DomainBlocksGet(authed.Account, export) +func (p *processor) AdminDomainBlocksGet(ctx context.Context, authed *oauth.Auth, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlocksGet(ctx, authed.Account, export) } -func (p *processor) AdminDomainBlockGet(authed *oauth.Auth, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) { - return p.adminProcessor.DomainBlockGet(authed.Account, id, export) +func (p *processor) AdminDomainBlockGet(ctx context.Context, authed *oauth.Auth, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlockGet(ctx, authed.Account, id, export) } -func (p *processor) AdminDomainBlockDelete(authed *oauth.Auth, id string) (*apimodel.DomainBlock, gtserror.WithCode) { - return p.adminProcessor.DomainBlockDelete(authed.Account, id) +func (p *processor) AdminDomainBlockDelete(ctx context.Context, authed *oauth.Auth, id string) (*apimodel.DomainBlock, gtserror.WithCode) { + return p.adminProcessor.DomainBlockDelete(ctx, authed.Account, id) } diff --git a/internal/processing/admin/admin.go b/internal/processing/admin/admin.go index fd63d8a10..de288811b 100644 --- a/internal/processing/admin/admin.go +++ b/internal/processing/admin/admin.go @@ -19,6 +19,7 @@ package admin import ( + "context" "mime/multipart" "github.com/sirupsen/logrus" @@ -33,12 +34,12 @@ import ( // Processor wraps a bunch of functions for processing admin actions. type Processor interface { - DomainBlockCreate(account *gtsmodel.Account, domain string, obfuscate bool, publicComment string, privateComment string, subscriptionID string) (*apimodel.DomainBlock, gtserror.WithCode) - DomainBlocksImport(account *gtsmodel.Account, domains *multipart.FileHeader) ([]*apimodel.DomainBlock, gtserror.WithCode) - DomainBlocksGet(account *gtsmodel.Account, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) - DomainBlockGet(account *gtsmodel.Account, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) - DomainBlockDelete(account *gtsmodel.Account, id string) (*apimodel.DomainBlock, gtserror.WithCode) - EmojiCreate(account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) + DomainBlockCreate(ctx context.Context, account *gtsmodel.Account, domain string, obfuscate bool, publicComment string, privateComment string, subscriptionID string) (*apimodel.DomainBlock, gtserror.WithCode) + DomainBlocksImport(ctx context.Context, account *gtsmodel.Account, domains *multipart.FileHeader) ([]*apimodel.DomainBlock, gtserror.WithCode) + DomainBlocksGet(ctx context.Context, account *gtsmodel.Account, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) + DomainBlockGet(ctx context.Context, account *gtsmodel.Account, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) + DomainBlockDelete(ctx context.Context, account *gtsmodel.Account, id string) (*apimodel.DomainBlock, gtserror.WithCode) + EmojiCreate(ctx context.Context, account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) } type processor struct { diff --git a/internal/processing/admin/createdomainblock.go b/internal/processing/admin/createdomainblock.go index 624f632dc..a34c03a44 100644 --- a/internal/processing/admin/createdomainblock.go +++ b/internal/processing/admin/createdomainblock.go @@ -19,6 +19,7 @@ package admin import ( + "context" "fmt" "time" @@ -31,10 +32,10 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/text" ) -func (p *processor) DomainBlockCreate(account *gtsmodel.Account, domain string, obfuscate bool, publicComment string, privateComment string, subscriptionID string) (*apimodel.DomainBlock, gtserror.WithCode) { +func (p *processor) DomainBlockCreate(ctx context.Context, account *gtsmodel.Account, domain string, obfuscate bool, publicComment string, privateComment string, subscriptionID string) (*apimodel.DomainBlock, gtserror.WithCode) { // first check if we already have a block -- if err == nil we already had a block so we can skip a whole lot of work domainBlock := >smodel.DomainBlock{} - err := p.db.GetWhere([]db.Where{{Key: "domain", Value: domain, CaseInsensitive: true}}, domainBlock) + err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: domain, CaseInsensitive: true}}, domainBlock) if err != nil { if err != db.ErrNoEntries { // something went wrong in the DB @@ -59,7 +60,7 @@ func (p *processor) DomainBlockCreate(account *gtsmodel.Account, domain string, } // put the new block in the database - if err := p.db.Put(domainBlock); err != nil { + if err := p.db.Put(ctx, domainBlock); err != nil { if err != db.ErrNoEntries { // there's a real error creating the block return nil, gtserror.NewErrorInternalError(fmt.Errorf("DomainBlockCreate: db error putting new domain block %s: %s", domain, err)) @@ -67,10 +68,10 @@ func (p *processor) DomainBlockCreate(account *gtsmodel.Account, domain string, } // process the side effects of the domain block asynchronously since it might take a while - go p.initiateDomainBlockSideEffects(account, domainBlock) // TODO: add this to a queuing system so it can retry/resume + go p.initiateDomainBlockSideEffects(ctx, account, domainBlock) // TODO: add this to a queuing system so it can retry/resume } - mastoDomainBlock, err := p.tc.DomainBlockToMasto(domainBlock, false) + mastoDomainBlock, err := p.tc.DomainBlockToMasto(ctx, domainBlock, false) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("DomainBlockCreate: error converting domain block to frontend/masto representation %s: %s", domain, err)) } @@ -83,7 +84,7 @@ func (p *processor) DomainBlockCreate(account *gtsmodel.Account, domain string, // 1. Strip most info away from the instance entry for the domain. // 2. Delete the instance account for that instance if it exists. // 3. Select all accounts from this instance and pass them through the delete functionality of the processor. -func (p *processor) initiateDomainBlockSideEffects(account *gtsmodel.Account, block *gtsmodel.DomainBlock) { +func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account *gtsmodel.Account, block *gtsmodel.DomainBlock) { l := p.log.WithFields(logrus.Fields{ "func": "domainBlockProcessSideEffects", "domain": block.Domain, @@ -93,7 +94,7 @@ func (p *processor) initiateDomainBlockSideEffects(account *gtsmodel.Account, bl // if we have an instance entry for this domain, update it with the new block ID and clear all fields instance := >smodel.Instance{} - if err := p.db.GetWhere([]db.Where{{Key: "domain", Value: block.Domain, CaseInsensitive: true}}, instance); err == nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: block.Domain, CaseInsensitive: true}}, instance); err == nil { instance.Title = "" instance.UpdatedAt = time.Now() instance.SuspendedAt = time.Now() @@ -105,14 +106,14 @@ func (p *processor) initiateDomainBlockSideEffects(account *gtsmodel.Account, bl instance.ContactAccountUsername = "" instance.ContactAccountID = "" instance.Version = "" - if err := p.db.UpdateByID(instance.ID, instance); err != nil { + if err := p.db.UpdateByID(ctx, instance.ID, instance); err != nil { l.Errorf("domainBlockProcessSideEffects: db error updating instance: %s", err) } l.Debug("domainBlockProcessSideEffects: instance entry updated") } // if we have an instance account for this instance, delete it - if err := p.db.DeleteWhere([]db.Where{{Key: "username", Value: block.Domain, CaseInsensitive: true}}, >smodel.Account{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "username", Value: block.Domain, CaseInsensitive: true}}, >smodel.Account{}); err != nil { l.Errorf("domainBlockProcessSideEffects: db error removing instance account: %s", err) } @@ -123,7 +124,7 @@ func (p *processor) initiateDomainBlockSideEffects(account *gtsmodel.Account, bl selectAccountsLoop: for { - accounts, err := p.db.GetInstanceAccounts(block.Domain, maxID, limit) + accounts, err := p.db.GetInstanceAccounts(ctx, block.Domain, maxID, limit) if err != nil { if err == db.ErrNoEntries { // no accounts left for this instance so we're done diff --git a/internal/processing/admin/deletedomainblock.go b/internal/processing/admin/deletedomainblock.go index edb0a58f9..2563b557d 100644 --- a/internal/processing/admin/deletedomainblock.go +++ b/internal/processing/admin/deletedomainblock.go @@ -19,6 +19,7 @@ package admin import ( + "context" "fmt" "time" @@ -28,10 +29,10 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) DomainBlockDelete(account *gtsmodel.Account, id string) (*apimodel.DomainBlock, gtserror.WithCode) { +func (p *processor) DomainBlockDelete(ctx context.Context, account *gtsmodel.Account, id string) (*apimodel.DomainBlock, gtserror.WithCode) { domainBlock := >smodel.DomainBlock{} - if err := p.db.GetByID(id, domainBlock); err != nil { + if err := p.db.GetByID(ctx, id, domainBlock); err != nil { if err != db.ErrNoEntries { // something has gone really wrong return nil, gtserror.NewErrorInternalError(err) @@ -41,39 +42,39 @@ func (p *processor) DomainBlockDelete(account *gtsmodel.Account, id string) (*ap } // prepare the domain block to return - mastoDomainBlock, err := p.tc.DomainBlockToMasto(domainBlock, false) + mastoDomainBlock, err := p.tc.DomainBlockToMasto(ctx, domainBlock, false) if err != nil { return nil, gtserror.NewErrorInternalError(err) } // delete the domain block - if err := p.db.DeleteByID(id, domainBlock); err != nil { + if err := p.db.DeleteByID(ctx, id, domainBlock); err != nil { return nil, gtserror.NewErrorInternalError(err) } // remove the domain block reference from the instance, if we have an entry for it i := >smodel.Instance{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "domain", Value: domainBlock.Domain, CaseInsensitive: true}, {Key: "domain_block_id", Value: id}, }, i); err == nil { i.SuspendedAt = time.Time{} i.DomainBlockID = "" - if err := p.db.UpdateByID(i.ID, i); err != nil { + if err := p.db.UpdateByID(ctx, i.ID, i); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("couldn't update database entry for instance %s: %s", domainBlock.Domain, err)) } } // unsuspend all accounts whose suspension origin was this domain block // 1. remove the 'suspended_at' entry from their accounts - if err := p.db.UpdateWhere([]db.Where{ + if err := p.db.UpdateWhere(ctx, []db.Where{ {Key: "suspension_origin", Value: domainBlock.ID}, }, "suspended_at", nil, &[]*gtsmodel.Account{}); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error removing suspended_at from accounts: %s", err)) } // 2. remove the 'suspension_origin' entry from their accounts - if err := p.db.UpdateWhere([]db.Where{ + if err := p.db.UpdateWhere(ctx, []db.Where{ {Key: "suspension_origin", Value: domainBlock.ID}, }, "suspension_origin", nil, &[]*gtsmodel.Account{}); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error removing suspension_origin from accounts: %s", err)) diff --git a/internal/processing/admin/emoji.go b/internal/processing/admin/emoji.go index f19e173b5..f56bde8e0 100644 --- a/internal/processing/admin/emoji.go +++ b/internal/processing/admin/emoji.go @@ -20,6 +20,7 @@ package admin import ( "bytes" + "context" "errors" "fmt" "io" @@ -29,7 +30,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/id" ) -func (p *processor) EmojiCreate(account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) { +func (p *processor) EmojiCreate(ctx context.Context, account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) { if user.Admin { return nil, fmt.Errorf("user %s not an admin", user.ID) } @@ -49,7 +50,7 @@ func (p *processor) EmojiCreate(account *gtsmodel.Account, user *gtsmodel.User, } // allow the mediaHandler to work its magic of processing the emoji bytes, and putting them in whatever storage backend we're using - emoji, err := p.mediaHandler.ProcessLocalEmoji(buf.Bytes(), form.Shortcode) + emoji, err := p.mediaHandler.ProcessLocalEmoji(ctx, buf.Bytes(), form.Shortcode) if err != nil { return nil, fmt.Errorf("error reading emoji: %s", err) } @@ -60,12 +61,12 @@ func (p *processor) EmojiCreate(account *gtsmodel.Account, user *gtsmodel.User, } emoji.ID = emojiID - mastoEmoji, err := p.tc.EmojiToMasto(emoji) + mastoEmoji, err := p.tc.EmojiToMasto(ctx, emoji) if err != nil { return nil, fmt.Errorf("error converting emoji to mastotype: %s", err) } - if err := p.db.Put(emoji); err != nil { + if err := p.db.Put(ctx, emoji); err != nil { return nil, fmt.Errorf("database error while processing emoji: %s", err) } diff --git a/internal/processing/admin/getdomainblock.go b/internal/processing/admin/getdomainblock.go index f74010627..19bc9fe09 100644 --- a/internal/processing/admin/getdomainblock.go +++ b/internal/processing/admin/getdomainblock.go @@ -19,6 +19,7 @@ package admin import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -27,10 +28,10 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) DomainBlockGet(account *gtsmodel.Account, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) { +func (p *processor) DomainBlockGet(ctx context.Context, account *gtsmodel.Account, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) { domainBlock := >smodel.DomainBlock{} - if err := p.db.GetByID(id, domainBlock); err != nil { + if err := p.db.GetByID(ctx, id, domainBlock); err != nil { if err != db.ErrNoEntries { // something has gone really wrong return nil, gtserror.NewErrorInternalError(err) @@ -39,7 +40,7 @@ func (p *processor) DomainBlockGet(account *gtsmodel.Account, id string, export return nil, gtserror.NewErrorNotFound(fmt.Errorf("no entry for ID %s", id)) } - mastoDomainBlock, err := p.tc.DomainBlockToMasto(domainBlock, export) + mastoDomainBlock, err := p.tc.DomainBlockToMasto(ctx, domainBlock, export) if err != nil { return nil, gtserror.NewErrorInternalError(err) } diff --git a/internal/processing/admin/getdomainblocks.go b/internal/processing/admin/getdomainblocks.go index f827d03fc..0ec33cfff 100644 --- a/internal/processing/admin/getdomainblocks.go +++ b/internal/processing/admin/getdomainblocks.go @@ -19,16 +19,18 @@ package admin import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) DomainBlocksGet(account *gtsmodel.Account, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) { +func (p *processor) DomainBlocksGet(ctx context.Context, account *gtsmodel.Account, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) { domainBlocks := []*gtsmodel.DomainBlock{} - if err := p.db.GetAll(&domainBlocks); err != nil { + if err := p.db.GetAll(ctx, &domainBlocks); err != nil { if err != db.ErrNoEntries { // something has gone really wrong return nil, gtserror.NewErrorInternalError(err) @@ -37,7 +39,7 @@ func (p *processor) DomainBlocksGet(account *gtsmodel.Account, export bool) ([]* mastoDomainBlocks := []*apimodel.DomainBlock{} for _, b := range domainBlocks { - mastoDomainBlock, err := p.tc.DomainBlockToMasto(b, export) + mastoDomainBlock, err := p.tc.DomainBlockToMasto(ctx, b, export) if err != nil { return nil, gtserror.NewErrorInternalError(err) } diff --git a/internal/processing/admin/importdomainblocks.go b/internal/processing/admin/importdomainblocks.go index ab171b712..66326bd62 100644 --- a/internal/processing/admin/importdomainblocks.go +++ b/internal/processing/admin/importdomainblocks.go @@ -20,6 +20,7 @@ package admin import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -32,7 +33,7 @@ import ( ) // DomainBlocksImport handles the import of a bunch of domain blocks at once, by calling the DomainBlockCreate function for each domain in the provided file. -func (p *processor) DomainBlocksImport(account *gtsmodel.Account, domains *multipart.FileHeader) ([]*apimodel.DomainBlock, gtserror.WithCode) { +func (p *processor) DomainBlocksImport(ctx context.Context, account *gtsmodel.Account, domains *multipart.FileHeader) ([]*apimodel.DomainBlock, gtserror.WithCode) { f, err := domains.Open() if err != nil { @@ -54,7 +55,7 @@ func (p *processor) DomainBlocksImport(account *gtsmodel.Account, domains *multi blocks := []*apimodel.DomainBlock{} for _, d := range d { - block, err := p.DomainBlockCreate(account, d.Domain, false, d.PublicComment, "", "") + block, err := p.DomainBlockCreate(ctx, account, d.Domain, false, d.PublicComment, "", "") if err != nil { return nil, err diff --git a/internal/processing/app.go b/internal/processing/app.go index 7da5344ac..4f805572b 100644 --- a/internal/processing/app.go +++ b/internal/processing/app.go @@ -19,6 +19,8 @@ package processing import ( + "context" + "github.com/google/uuid" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" @@ -26,7 +28,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) AppCreate(authed *oauth.Auth, form *apimodel.ApplicationCreateRequest) (*apimodel.Application, error) { +func (p *processor) AppCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.ApplicationCreateRequest) (*apimodel.Application, error) { // set default 'read' for scopes if it's not set, this follows the default of the mastodon api https://docs.joinmastodon.org/methods/apps/ var scopes string if form.Scopes == "" { @@ -61,7 +63,7 @@ func (p *processor) AppCreate(authed *oauth.Auth, form *apimodel.ApplicationCrea } // chuck it in the db - if err := p.db.Put(app); err != nil { + if err := p.db.Put(ctx, app); err != nil { return nil, err } @@ -74,11 +76,11 @@ func (p *processor) AppCreate(authed *oauth.Auth, form *apimodel.ApplicationCrea } // chuck it in the db - if err := p.db.Put(oc); err != nil { + if err := p.db.Put(ctx, oc); err != nil { return nil, err } - mastoApp, err := p.tc.AppToMastoSensitive(app) + mastoApp, err := p.tc.AppToMastoSensitive(ctx, app) if err != nil { return nil, err } diff --git a/internal/processing/blocks.go b/internal/processing/blocks.go index 809cbde8e..7c8371989 100644 --- a/internal/processing/blocks.go +++ b/internal/processing/blocks.go @@ -19,6 +19,7 @@ package processing import ( + "context" "fmt" "net/url" @@ -28,8 +29,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) BlocksGet(authed *oauth.Auth, maxID string, sinceID string, limit int) (*apimodel.BlocksResponse, gtserror.WithCode) { - accounts, nextMaxID, prevMinID, err := p.db.GetAccountBlocks(authed.Account.ID, maxID, sinceID, limit) +func (p *processor) BlocksGet(ctx context.Context, authed *oauth.Auth, maxID string, sinceID string, limit int) (*apimodel.BlocksResponse, gtserror.WithCode) { + accounts, nextMaxID, prevMinID, err := p.db.GetAccountBlocks(ctx, authed.Account.ID, maxID, sinceID, limit) if err != nil { if err == db.ErrNoEntries { // there are just no entries @@ -43,7 +44,7 @@ func (p *processor) BlocksGet(authed *oauth.Auth, maxID string, sinceID string, apiAccounts := []*apimodel.Account{} for _, a := range accounts { - apiAccount, err := p.tc.AccountToMastoBlocked(a) + apiAccount, err := p.tc.AccountToMastoBlocked(ctx, a) if err != nil { continue } diff --git a/internal/processing/federation.go b/internal/processing/federation.go index cea14b4de..352a6ddc2 100644 --- a/internal/processing/federation.go +++ b/internal/processing/federation.go @@ -36,7 +36,7 @@ import ( func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode) { // get the account the request is referring to - requestedAccount, err := p.db.GetLocalAccountByUsername(requestedUsername) + requestedAccount, err := p.db.GetLocalAccountByUsername(ctx, requestedUsername) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) } @@ -44,7 +44,7 @@ func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, r var requestedPerson vocab.ActivityStreamsPerson if util.IsPublicKeyPath(requestURL) { // if it's a public key path, we don't need to authenticate but we'll only serve the bare minimum user profile needed for the public key - requestedPerson, err = p.tc.AccountToASMinimal(requestedAccount) + requestedPerson, err = p.tc.AccountToASMinimal(ctx, requestedAccount) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -56,13 +56,13 @@ func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, r } // if we're not already handshaking/dereferencing a remote account, dereference it now - if !p.federator.Handshaking(requestedUsername, requestingAccountURI) { - requestingAccount, _, err := p.federator.GetRemoteAccount(requestedUsername, requestingAccountURI, false) + if !p.federator.Handshaking(ctx, requestedUsername, requestingAccountURI) { + requestingAccount, _, err := p.federator.GetRemoteAccount(ctx, requestedUsername, requestingAccountURI, false) if err != nil { return nil, gtserror.NewErrorNotAuthorized(err) } - blocked, err := p.db.IsBlocked(requestedAccount.ID, requestingAccount.ID, true) + blocked, err := p.db.IsBlocked(ctx, requestedAccount.ID, requestingAccount.ID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -72,7 +72,7 @@ func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, r } } - requestedPerson, err = p.tc.AccountToAS(requestedAccount) + requestedPerson, err = p.tc.AccountToAS(ctx, requestedAccount) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -90,7 +90,7 @@ func (p *processor) GetFediUser(ctx context.Context, requestedUsername string, r func (p *processor) GetFediFollowers(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode) { // get the account the request is referring to - requestedAccount, err := p.db.GetLocalAccountByUsername(requestedUsername) + requestedAccount, err := p.db.GetLocalAccountByUsername(ctx, requestedUsername) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) } @@ -101,12 +101,12 @@ func (p *processor) GetFediFollowers(ctx context.Context, requestedUsername stri return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized") } - requestingAccount, _, err := p.federator.GetRemoteAccount(requestedUsername, requestingAccountURI, false) + requestingAccount, _, err := p.federator.GetRemoteAccount(ctx, requestedUsername, requestingAccountURI, false) if err != nil { return nil, gtserror.NewErrorNotAuthorized(err) } - blocked, err := p.db.IsBlocked(requestedAccount.ID, requestingAccount.ID, true) + blocked, err := p.db.IsBlocked(ctx, requestedAccount.ID, requestingAccount.ID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -135,7 +135,7 @@ func (p *processor) GetFediFollowers(ctx context.Context, requestedUsername stri func (p *processor) GetFediFollowing(ctx context.Context, requestedUsername string, requestURL *url.URL) (interface{}, gtserror.WithCode) { // get the account the request is referring to - requestedAccount, err := p.db.GetLocalAccountByUsername(requestedUsername) + requestedAccount, err := p.db.GetLocalAccountByUsername(ctx, requestedUsername) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) } @@ -146,12 +146,12 @@ func (p *processor) GetFediFollowing(ctx context.Context, requestedUsername stri return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized") } - requestingAccount, _, err := p.federator.GetRemoteAccount(requestedUsername, requestingAccountURI, false) + requestingAccount, _, err := p.federator.GetRemoteAccount(ctx, requestedUsername, requestingAccountURI, false) if err != nil { return nil, gtserror.NewErrorNotAuthorized(err) } - blocked, err := p.db.IsBlocked(requestedAccount.ID, requestingAccount.ID, true) + blocked, err := p.db.IsBlocked(ctx, requestedAccount.ID, requestingAccount.ID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -180,7 +180,7 @@ func (p *processor) GetFediFollowing(ctx context.Context, requestedUsername stri func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string, requestedStatusID string, requestURL *url.URL) (interface{}, gtserror.WithCode) { // get the account the request is referring to - requestedAccount, err := p.db.GetLocalAccountByUsername(requestedUsername) + requestedAccount, err := p.db.GetLocalAccountByUsername(ctx, requestedUsername) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) } @@ -191,14 +191,14 @@ func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string, return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized") } - requestingAccount, _, err := p.federator.GetRemoteAccount(requestedUsername, requestingAccountURI, false) + requestingAccount, _, err := p.federator.GetRemoteAccount(ctx, requestedUsername, requestingAccountURI, false) if err != nil { return nil, gtserror.NewErrorNotAuthorized(err) } // authorize the request: // 1. check if a block exists between the requester and the requestee - blocked, err := p.db.IsBlocked(requestedAccount.ID, requestingAccount.ID, true) + blocked, err := p.db.IsBlocked(ctx, requestedAccount.ID, requestingAccount.ID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -209,14 +209,14 @@ func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string, // get the status out of the database here s := >smodel.Status{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "id", Value: requestedStatusID}, {Key: "account_id", Value: requestedAccount.ID}, }, s); err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting status with id %s and account id %s: %s", requestedStatusID, requestedAccount.ID, err)) } - visible, err := p.filter.StatusVisible(s, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, s, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -225,7 +225,7 @@ func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string, } // requester is authorized to view the status, so convert it to AP representation and serialize it - asStatus, err := p.tc.StatusToAS(s) + asStatus, err := p.tc.StatusToAS(ctx, s) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -240,7 +240,7 @@ func (p *processor) GetFediStatus(ctx context.Context, requestedUsername string, func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername string, requestedStatusID string, page bool, onlyOtherAccounts bool, minID string, requestURL *url.URL) (interface{}, gtserror.WithCode) { // get the account the request is referring to - requestedAccount, err := p.db.GetLocalAccountByUsername(requestedUsername) + requestedAccount, err := p.db.GetLocalAccountByUsername(ctx, requestedUsername) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) } @@ -251,14 +251,14 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername return nil, gtserror.NewErrorNotAuthorized(errors.New("not authorized"), "not authorized") } - requestingAccount, _, err := p.federator.GetRemoteAccount(requestedUsername, requestingAccountURI, false) + requestingAccount, _, err := p.federator.GetRemoteAccount(ctx, requestedUsername, requestingAccountURI, false) if err != nil { return nil, gtserror.NewErrorNotAuthorized(err) } // authorize the request: // 1. check if a block exists between the requester and the requestee - blocked, err := p.db.IsBlocked(requestedAccount.ID, requestingAccount.ID, true) + blocked, err := p.db.IsBlocked(ctx, requestedAccount.ID, requestingAccount.ID, true) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -269,14 +269,14 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername // get the status out of the database here s := >smodel.Status{} - if err := p.db.GetWhere([]db.Where{ + if err := p.db.GetWhere(ctx, []db.Where{ {Key: "id", Value: requestedStatusID}, {Key: "account_id", Value: requestedAccount.ID}, }, s); err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting status with id %s and account id %s: %s", requestedStatusID, requestedAccount.ID, err)) } - visible, err := p.filter.StatusVisible(s, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, s, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -295,7 +295,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername // scenario 1 // get the collection - collection, err := p.tc.StatusToASRepliesCollection(s, onlyOtherAccounts) + collection, err := p.tc.StatusToASRepliesCollection(ctx, s, onlyOtherAccounts) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -308,7 +308,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername // scenario 2 // get the collection - collection, err := p.tc.StatusToASRepliesCollection(s, onlyOtherAccounts) + collection, err := p.tc.StatusToASRepliesCollection(ctx, s, onlyOtherAccounts) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -320,7 +320,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername } else { // scenario 3 // get immediate children - replies, err := p.db.GetStatusChildren(s, true, minID) + replies, err := p.db.GetStatusChildren(ctx, s, true, minID) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -339,13 +339,13 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername } // only show replies that the status owner can see - visibleToStatusOwner, err := p.filter.StatusVisible(r, requestedAccount) + visibleToStatusOwner, err := p.filter.StatusVisible(ctx, r, requestedAccount) if err != nil || !visibleToStatusOwner { continue } // only show replies that the requester can see - visibleToRequester, err := p.filter.StatusVisible(r, requestingAccount) + visibleToRequester, err := p.filter.StatusVisible(ctx, r, requestingAccount) if err != nil || !visibleToRequester { continue } @@ -358,7 +358,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername replyURIs[r.ID] = rURI } - repliesPage, err := p.tc.StatusURIsToASRepliesPage(s, onlyOtherAccounts, minID, replyURIs) + repliesPage, err := p.tc.StatusURIsToASRepliesPage(ctx, s, onlyOtherAccounts, minID, replyURIs) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -373,7 +373,7 @@ func (p *processor) GetFediStatusReplies(ctx context.Context, requestedUsername func (p *processor) GetWebfingerAccount(ctx context.Context, requestedUsername string, requestURL *url.URL) (*apimodel.WellKnownResponse, gtserror.WithCode) { // get the account the request is referring to - requestedAccount, err := p.db.GetLocalAccountByUsername(requestedUsername) + requestedAccount, err := p.db.GetLocalAccountByUsername(ctx, requestedUsername) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("database error getting account with username %s: %s", requestedUsername, err)) } @@ -400,7 +400,7 @@ func (p *processor) GetWebfingerAccount(ctx context.Context, requestedUsername s }, nil } -func (p *processor) GetNodeInfoRel(request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode) { +func (p *processor) GetNodeInfoRel(ctx context.Context, request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode) { return &apimodel.WellKnownResponse{ Links: []apimodel.Link{ { @@ -411,7 +411,7 @@ func (p *processor) GetNodeInfoRel(request *http.Request) (*apimodel.WellKnownRe }, nil } -func (p *processor) GetNodeInfo(request *http.Request) (*apimodel.Nodeinfo, gtserror.WithCode) { +func (p *processor) GetNodeInfo(ctx context.Context, request *http.Request) (*apimodel.Nodeinfo, gtserror.WithCode) { return &apimodel.Nodeinfo{ Version: "2.0", Software: apimodel.NodeInfoSoftware{ diff --git a/internal/processing/followrequest.go b/internal/processing/followrequest.go index 867725023..3dd6432e2 100644 --- a/internal/processing/followrequest.go +++ b/internal/processing/followrequest.go @@ -19,6 +19,8 @@ package processing import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtserror" @@ -26,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) FollowRequestsGet(auth *oauth.Auth) ([]apimodel.Account, gtserror.WithCode) { - frs, err := p.db.GetAccountFollowRequests(auth.Account.ID) +func (p *processor) FollowRequestsGet(ctx context.Context, auth *oauth.Auth) ([]apimodel.Account, gtserror.WithCode) { + frs, err := p.db.GetAccountFollowRequests(ctx, auth.Account.ID) if err != nil { if err != db.ErrNoEntries { return nil, gtserror.NewErrorInternalError(err) @@ -36,11 +38,15 @@ func (p *processor) FollowRequestsGet(auth *oauth.Auth) ([]apimodel.Account, gts accts := []apimodel.Account{} for _, fr := range frs { - acct := >smodel.Account{} - if err := p.db.GetByID(fr.AccountID, acct); err != nil { - return nil, gtserror.NewErrorInternalError(err) + if fr.Account == nil { + frAcct, err := p.db.GetAccountByID(ctx, fr.AccountID) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + fr.Account = frAcct } - mastoAcct, err := p.tc.AccountToMastoPublic(acct) + + mastoAcct, err := p.tc.AccountToMastoPublic(ctx, fr.Account) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -49,36 +55,42 @@ func (p *processor) FollowRequestsGet(auth *oauth.Auth) ([]apimodel.Account, gts return accts, nil } -func (p *processor) FollowRequestAccept(auth *oauth.Auth, accountID string) (*apimodel.Relationship, gtserror.WithCode) { - follow, err := p.db.AcceptFollowRequest(accountID, auth.Account.ID) +func (p *processor) FollowRequestAccept(ctx context.Context, auth *oauth.Auth, accountID string) (*apimodel.Relationship, gtserror.WithCode) { + follow, err := p.db.AcceptFollowRequest(ctx, accountID, auth.Account.ID) if err != nil { return nil, gtserror.NewErrorNotFound(err) } - originAccount := >smodel.Account{} - if err := p.db.GetByID(follow.AccountID, originAccount); err != nil { - return nil, gtserror.NewErrorInternalError(err) + if follow.Account == nil { + followAccount, err := p.db.GetAccountByID(ctx, follow.AccountID) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + follow.Account = followAccount } - targetAccount := >smodel.Account{} - if err := p.db.GetByID(follow.TargetAccountID, targetAccount); err != nil { - return nil, gtserror.NewErrorInternalError(err) + if follow.TargetAccount == nil { + followTargetAccount, err := p.db.GetAccountByID(ctx, follow.TargetAccountID) + if err != nil { + return nil, gtserror.NewErrorInternalError(err) + } + follow.TargetAccount = followTargetAccount } p.fromClientAPI <- gtsmodel.FromClientAPI{ APObjectType: gtsmodel.ActivityStreamsFollow, APActivityType: gtsmodel.ActivityStreamsAccept, GTSModel: follow, - OriginAccount: originAccount, - TargetAccount: targetAccount, + OriginAccount: follow.Account, + TargetAccount: follow.TargetAccount, } - gtsR, err := p.db.GetRelationship(auth.Account.ID, accountID) + gtsR, err := p.db.GetRelationship(ctx, auth.Account.ID, accountID) if err != nil { return nil, gtserror.NewErrorInternalError(err) } - r, err := p.tc.RelationshipToMasto(gtsR) + r, err := p.tc.RelationshipToMasto(ctx, gtsR) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -86,6 +98,6 @@ func (p *processor) FollowRequestAccept(auth *oauth.Auth, accountID string) (*ap return r, nil } -func (p *processor) FollowRequestDeny(auth *oauth.Auth) gtserror.WithCode { +func (p *processor) FollowRequestDeny(ctx context.Context, auth *oauth.Auth) gtserror.WithCode { return nil } diff --git a/internal/processing/fromclientapi.go b/internal/processing/fromclientapi.go index beed283c1..a6ea0068b 100644 --- a/internal/processing/fromclientapi.go +++ b/internal/processing/fromclientapi.go @@ -29,7 +29,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error { +func (p *processor) processFromClientAPI(ctx context.Context, clientMsg gtsmodel.FromClientAPI) error { switch clientMsg.APActivityType { case gtsmodel.ActivityStreamsCreate: // CREATE @@ -41,16 +41,16 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("note was not parseable as *gtsmodel.Status") } - if err := p.timelineStatus(status); err != nil { + if err := p.timelineStatus(ctx, status); err != nil { return err } - if err := p.notifyStatus(status); err != nil { + if err := p.notifyStatus(ctx, status); err != nil { return err } if status.VisibilityAdvanced != nil && status.VisibilityAdvanced.Federated { - return p.federateStatus(status) + return p.federateStatus(ctx, status) } case gtsmodel.ActivityStreamsFollow: // CREATE FOLLOW REQUEST @@ -59,11 +59,11 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("followrequest was not parseable as *gtsmodel.FollowRequest") } - if err := p.notifyFollowRequest(followRequest, clientMsg.TargetAccount); err != nil { + if err := p.notifyFollowRequest(ctx, followRequest, clientMsg.TargetAccount); err != nil { return err } - return p.federateFollow(followRequest, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateFollow(ctx, followRequest, clientMsg.OriginAccount, clientMsg.TargetAccount) case gtsmodel.ActivityStreamsLike: // CREATE LIKE/FAVE fave, ok := clientMsg.GTSModel.(*gtsmodel.StatusFave) @@ -71,11 +71,11 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("fave was not parseable as *gtsmodel.StatusFave") } - if err := p.notifyFave(fave, clientMsg.TargetAccount); err != nil { + if err := p.notifyFave(ctx, fave, clientMsg.TargetAccount); err != nil { return err } - return p.federateFave(fave, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateFave(ctx, fave, clientMsg.OriginAccount, clientMsg.TargetAccount) case gtsmodel.ActivityStreamsAnnounce: // CREATE BOOST/ANNOUNCE boostWrapperStatus, ok := clientMsg.GTSModel.(*gtsmodel.Status) @@ -83,15 +83,15 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("boost was not parseable as *gtsmodel.Status") } - if err := p.timelineStatus(boostWrapperStatus); err != nil { + if err := p.timelineStatus(ctx, boostWrapperStatus); err != nil { return err } - if err := p.notifyAnnounce(boostWrapperStatus); err != nil { + if err := p.notifyAnnounce(ctx, boostWrapperStatus); err != nil { return err } - return p.federateAnnounce(boostWrapperStatus, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateAnnounce(ctx, boostWrapperStatus, clientMsg.OriginAccount, clientMsg.TargetAccount) case gtsmodel.ActivityStreamsBlock: // CREATE BLOCK block, ok := clientMsg.GTSModel.(*gtsmodel.Block) @@ -100,17 +100,17 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error } // remove any of the blocking account's statuses from the blocked account's timeline, and vice versa - if err := p.timelineManager.WipeStatusesFromAccountID(block.AccountID, block.TargetAccountID); err != nil { + if err := p.timelineManager.WipeStatusesFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { return err } - if err := p.timelineManager.WipeStatusesFromAccountID(block.TargetAccountID, block.AccountID); err != nil { + if err := p.timelineManager.WipeStatusesFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { return err } // TODO: same with notifications // TODO: same with bookmarks - return p.federateBlock(block) + return p.federateBlock(ctx, block) } case gtsmodel.ActivityStreamsUpdate: // UPDATE @@ -122,7 +122,7 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("account was not parseable as *gtsmodel.Account") } - return p.federateAccountUpdate(account, clientMsg.OriginAccount) + return p.federateAccountUpdate(ctx, account, clientMsg.OriginAccount) } case gtsmodel.ActivityStreamsAccept: // ACCEPT @@ -134,11 +134,11 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("accept was not parseable as *gtsmodel.Follow") } - if err := p.notifyFollow(follow, clientMsg.TargetAccount); err != nil { + if err := p.notifyFollow(ctx, follow, clientMsg.TargetAccount); err != nil { return err } - return p.federateAcceptFollowRequest(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateAcceptFollowRequest(ctx, follow, clientMsg.OriginAccount, clientMsg.TargetAccount) } case gtsmodel.ActivityStreamsUndo: // UNDO @@ -149,21 +149,21 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error if !ok { return errors.New("undo was not parseable as *gtsmodel.Follow") } - return p.federateUnfollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateUnfollow(ctx, follow, clientMsg.OriginAccount, clientMsg.TargetAccount) case gtsmodel.ActivityStreamsBlock: // UNDO BLOCK block, ok := clientMsg.GTSModel.(*gtsmodel.Block) if !ok { return errors.New("undo was not parseable as *gtsmodel.Block") } - return p.federateUnblock(block) + return p.federateUnblock(ctx, block) case gtsmodel.ActivityStreamsLike: // UNDO LIKE/FAVE fave, ok := clientMsg.GTSModel.(*gtsmodel.StatusFave) if !ok { return errors.New("undo was not parseable as *gtsmodel.StatusFave") } - return p.federateUnfave(fave, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateUnfave(ctx, fave, clientMsg.OriginAccount, clientMsg.TargetAccount) case gtsmodel.ActivityStreamsAnnounce: // UNDO ANNOUNCE/BOOST boost, ok := clientMsg.GTSModel.(*gtsmodel.Status) @@ -171,11 +171,11 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error return errors.New("undo was not parseable as *gtsmodel.Status") } - if err := p.deleteStatusFromTimelines(boost); err != nil { + if err := p.deleteStatusFromTimelines(ctx, boost); err != nil { return err } - return p.federateUnannounce(boost, clientMsg.OriginAccount, clientMsg.TargetAccount) + return p.federateUnannounce(ctx, boost, clientMsg.OriginAccount, clientMsg.TargetAccount) } case gtsmodel.ActivityStreamsDelete: // DELETE @@ -193,29 +193,29 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error // delete all attachments for this status for _, a := range statusToDelete.AttachmentIDs { - if err := p.mediaProcessor.Delete(a); err != nil { + if err := p.mediaProcessor.Delete(ctx, a); err != nil { return err } } // delete all mentions for this status for _, m := range statusToDelete.MentionIDs { - if err := p.db.DeleteByID(m, >smodel.Mention{}); err != nil { + if err := p.db.DeleteByID(ctx, m, >smodel.Mention{}); err != nil { return err } } // delete all notifications for this status - if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: statusToDelete.ID}}, &[]*gtsmodel.Notification{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "status_id", Value: statusToDelete.ID}}, &[]*gtsmodel.Notification{}); err != nil { return err } // delete this status from any and all timelines - if err := p.deleteStatusFromTimelines(statusToDelete); err != nil { + if err := p.deleteStatusFromTimelines(ctx, statusToDelete); err != nil { return err } - return p.federateStatusDelete(statusToDelete) + return p.federateStatusDelete(ctx, statusToDelete) case gtsmodel.ActivityStreamsProfile, gtsmodel.ActivityStreamsPerson: // DELETE ACCOUNT/PROFILE @@ -228,7 +228,7 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error // origin is whichever account caused this message origin = clientMsg.OriginAccount.ID } - return p.accountProcessor.Delete(clientMsg.TargetAccount, origin) + return p.accountProcessor.Delete(ctx, clientMsg.TargetAccount, origin) } } return nil @@ -236,13 +236,13 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error // TODO: move all the below functions into federation.Federator -func (p *processor) federateStatus(status *gtsmodel.Status) error { +func (p *processor) federateStatus(ctx context.Context, status *gtsmodel.Status) error { if status.Account == nil { - a := >smodel.Account{} - if err := p.db.GetByID(status.AccountID, a); err != nil { + statusAccount, err := p.db.GetAccountByID(ctx, status.AccountID) + if err != nil { return fmt.Errorf("federateStatus: error fetching status author account: %s", err) } - status.Account = a + status.Account = statusAccount } // do nothing if this isn't our status @@ -250,7 +250,7 @@ func (p *processor) federateStatus(status *gtsmodel.Status) error { return nil } - asStatus, err := p.tc.StatusToAS(status) + asStatus, err := p.tc.StatusToAS(ctx, status) if err != nil { return fmt.Errorf("federateStatus: error converting status to as format: %s", err) } @@ -260,17 +260,17 @@ func (p *processor) federateStatus(status *gtsmodel.Status) error { return fmt.Errorf("federateStatus: error parsing outboxURI %s: %s", status.Account.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asStatus) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, asStatus) return err } -func (p *processor) federateStatusDelete(status *gtsmodel.Status) error { +func (p *processor) federateStatusDelete(ctx context.Context, status *gtsmodel.Status) error { if status.Account == nil { - a := >smodel.Account{} - if err := p.db.GetByID(status.AccountID, a); err != nil { - return fmt.Errorf("federateStatus: error fetching status author account: %s", err) + statusAccount, err := p.db.GetAccountByID(ctx, status.AccountID) + if err != nil { + return fmt.Errorf("federateStatusDelete: error fetching status author account: %s", err) } - status.Account = a + status.Account = statusAccount } // do nothing if this isn't our status @@ -278,7 +278,7 @@ func (p *processor) federateStatusDelete(status *gtsmodel.Status) error { return nil } - asStatus, err := p.tc.StatusToAS(status) + asStatus, err := p.tc.StatusToAS(ctx, status) if err != nil { return fmt.Errorf("federateStatusDelete: error converting status to as format: %s", err) } @@ -310,19 +310,19 @@ func (p *processor) federateStatusDelete(status *gtsmodel.Status) error { delete.SetActivityStreamsTo(asStatus.GetActivityStreamsTo()) delete.SetActivityStreamsCc(asStatus.GetActivityStreamsCc()) - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, delete) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, delete) return err } -func (p *processor) federateFollow(followRequest *gtsmodel.FollowRequest, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { +func (p *processor) federateFollow(ctx context.Context, followRequest *gtsmodel.FollowRequest, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { // if both accounts are local there's nothing to do here if originAccount.Domain == "" && targetAccount.Domain == "" { return nil } - follow := p.tc.FollowRequestToFollow(followRequest) + follow := p.tc.FollowRequestToFollow(ctx, followRequest) - asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) + asFollow, err := p.tc.FollowToAS(ctx, follow, originAccount, targetAccount) if err != nil { return fmt.Errorf("federateFollow: error converting follow to as format: %s", err) } @@ -332,18 +332,18 @@ func (p *processor) federateFollow(followRequest *gtsmodel.FollowRequest, origin return fmt.Errorf("federateFollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asFollow) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, asFollow) return err } -func (p *processor) federateUnfollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { +func (p *processor) federateUnfollow(ctx context.Context, follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { // if both accounts are local there's nothing to do here if originAccount.Domain == "" && targetAccount.Domain == "" { return nil } // recreate the follow - asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) + asFollow, err := p.tc.FollowToAS(ctx, follow, originAccount, targetAccount) if err != nil { return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err) } @@ -373,18 +373,18 @@ func (p *processor) federateUnfollow(follow *gtsmodel.Follow, originAccount *gts } // send off the Undo - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, undo) return err } -func (p *processor) federateUnfave(fave *gtsmodel.StatusFave, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { +func (p *processor) federateUnfave(ctx context.Context, fave *gtsmodel.StatusFave, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { // if both accounts are local there's nothing to do here if originAccount.Domain == "" && targetAccount.Domain == "" { return nil } // create the AS fave - asFave, err := p.tc.FaveToAS(fave) + asFave, err := p.tc.FaveToAS(ctx, fave) if err != nil { return fmt.Errorf("federateFave: error converting fave to as format: %s", err) } @@ -412,17 +412,17 @@ func (p *processor) federateUnfave(fave *gtsmodel.StatusFave, originAccount *gts if err != nil { return fmt.Errorf("federateFave: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, undo) return err } -func (p *processor) federateUnannounce(boost *gtsmodel.Status, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { +func (p *processor) federateUnannounce(ctx context.Context, boost *gtsmodel.Status, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { if originAccount.Domain != "" { // nothing to do here return nil } - asAnnounce, err := p.tc.BoostToAS(boost, originAccount, targetAccount) + asAnnounce, err := p.tc.BoostToAS(ctx, boost, originAccount, targetAccount) if err != nil { return fmt.Errorf("federateUnannounce: error converting status to announce: %s", err) } @@ -447,18 +447,18 @@ func (p *processor) federateUnannounce(boost *gtsmodel.Status, originAccount *gt return fmt.Errorf("federateUnannounce: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, undo) return err } -func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { +func (p *processor) federateAcceptFollowRequest(ctx context.Context, follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { // if both accounts are local there's nothing to do here if originAccount.Domain == "" && targetAccount.Domain == "" { return nil } // recreate the AS follow - asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount) + asFollow, err := p.tc.FollowToAS(ctx, follow, originAccount, targetAccount) if err != nil { return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err) } @@ -497,18 +497,18 @@ func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow, originA } // send off the accept using the accepter's outbox - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, accept) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, accept) return err } -func (p *processor) federateFave(fave *gtsmodel.StatusFave, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { +func (p *processor) federateFave(ctx context.Context, fave *gtsmodel.StatusFave, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error { // if both accounts are local there's nothing to do here if originAccount.Domain == "" && targetAccount.Domain == "" { return nil } // create the AS fave - asFave, err := p.tc.FaveToAS(fave) + asFave, err := p.tc.FaveToAS(ctx, fave) if err != nil { return fmt.Errorf("federateFave: error converting fave to as format: %s", err) } @@ -517,12 +517,12 @@ func (p *processor) federateFave(fave *gtsmodel.StatusFave, originAccount *gtsmo if err != nil { return fmt.Errorf("federateFave: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asFave) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, asFave) return err } -func (p *processor) federateAnnounce(boostWrapperStatus *gtsmodel.Status, boostingAccount *gtsmodel.Account, boostedAccount *gtsmodel.Account) error { - announce, err := p.tc.BoostToAS(boostWrapperStatus, boostingAccount, boostedAccount) +func (p *processor) federateAnnounce(ctx context.Context, boostWrapperStatus *gtsmodel.Status, boostingAccount *gtsmodel.Account, boostedAccount *gtsmodel.Account) error { + announce, err := p.tc.BoostToAS(ctx, boostWrapperStatus, boostingAccount, boostedAccount) if err != nil { return fmt.Errorf("federateAnnounce: error converting status to announce: %s", err) } @@ -532,12 +532,12 @@ func (p *processor) federateAnnounce(boostWrapperStatus *gtsmodel.Status, boosti return fmt.Errorf("federateAnnounce: error parsing outboxURI %s: %s", boostingAccount.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, announce) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, announce) return err } -func (p *processor) federateAccountUpdate(updatedAccount *gtsmodel.Account, originAccount *gtsmodel.Account) error { - person, err := p.tc.AccountToAS(updatedAccount) +func (p *processor) federateAccountUpdate(ctx context.Context, updatedAccount *gtsmodel.Account, originAccount *gtsmodel.Account) error { + person, err := p.tc.AccountToAS(ctx, updatedAccount) if err != nil { return fmt.Errorf("federateAccountUpdate: error converting account to person: %s", err) } @@ -552,25 +552,25 @@ func (p *processor) federateAccountUpdate(updatedAccount *gtsmodel.Account, orig return fmt.Errorf("federateAnnounce: error parsing outboxURI %s: %s", originAccount.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, update) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, update) return err } -func (p *processor) federateBlock(block *gtsmodel.Block) error { +func (p *processor) federateBlock(ctx context.Context, block *gtsmodel.Block) error { if block.Account == nil { - a := >smodel.Account{} - if err := p.db.GetByID(block.AccountID, a); err != nil { + blockAccount, err := p.db.GetAccountByID(ctx, block.AccountID) + if err != nil { return fmt.Errorf("federateBlock: error getting block account from database: %s", err) } - block.Account = a + block.Account = blockAccount } if block.TargetAccount == nil { - a := >smodel.Account{} - if err := p.db.GetByID(block.TargetAccountID, a); err != nil { + blockTargetAccount, err := p.db.GetAccountByID(ctx, block.TargetAccountID) + if err != nil { return fmt.Errorf("federateBlock: error getting block target account from database: %s", err) } - block.TargetAccount = a + block.TargetAccount = blockTargetAccount } // if both accounts are local there's nothing to do here @@ -578,7 +578,7 @@ func (p *processor) federateBlock(block *gtsmodel.Block) error { return nil } - asBlock, err := p.tc.BlockToAS(block) + asBlock, err := p.tc.BlockToAS(ctx, block) if err != nil { return fmt.Errorf("federateBlock: error converting block to AS format: %s", err) } @@ -588,25 +588,25 @@ func (p *processor) federateBlock(block *gtsmodel.Block) error { return fmt.Errorf("federateBlock: error parsing outboxURI %s: %s", block.Account.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, asBlock) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, asBlock) return err } -func (p *processor) federateUnblock(block *gtsmodel.Block) error { +func (p *processor) federateUnblock(ctx context.Context, block *gtsmodel.Block) error { if block.Account == nil { - a := >smodel.Account{} - if err := p.db.GetByID(block.AccountID, a); err != nil { + blockAccount, err := p.db.GetAccountByID(ctx, block.AccountID) + if err != nil { return fmt.Errorf("federateUnblock: error getting block account from database: %s", err) } - block.Account = a + block.Account = blockAccount } if block.TargetAccount == nil { - a := >smodel.Account{} - if err := p.db.GetByID(block.TargetAccountID, a); err != nil { + blockTargetAccount, err := p.db.GetAccountByID(ctx, block.TargetAccountID) + if err != nil { return fmt.Errorf("federateUnblock: error getting block target account from database: %s", err) } - block.TargetAccount = a + block.TargetAccount = blockTargetAccount } // if both accounts are local there's nothing to do here @@ -614,7 +614,7 @@ func (p *processor) federateUnblock(block *gtsmodel.Block) error { return nil } - asBlock, err := p.tc.BlockToAS(block) + asBlock, err := p.tc.BlockToAS(ctx, block) if err != nil { return fmt.Errorf("federateUnblock: error converting block to AS format: %s", err) } @@ -642,6 +642,6 @@ func (p *processor) federateUnblock(block *gtsmodel.Block) error { if err != nil { return fmt.Errorf("federateUnblock: error parsing outboxURI %s: %s", block.Account.OutboxURI, err) } - _, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo) + _, err = p.federator.FederatingActor().Send(ctx, outboxIRI, undo) return err } diff --git a/internal/processing/fromcommon.go b/internal/processing/fromcommon.go index 2c2635175..b7a6defc3 100644 --- a/internal/processing/fromcommon.go +++ b/internal/processing/fromcommon.go @@ -19,6 +19,7 @@ package processing import ( + "context" "fmt" "strings" "sync" @@ -28,7 +29,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/id" ) -func (p *processor) notifyStatus(status *gtsmodel.Status) error { +func (p *processor) notifyStatus(ctx context.Context, status *gtsmodel.Status) error { // if there are no mentions in this status then just bail if len(status.MentionIDs) == 0 { return nil @@ -36,7 +37,7 @@ func (p *processor) notifyStatus(status *gtsmodel.Status) error { if status.Mentions == nil { // there are mentions but they're not fully populated on the status yet so do this - menchies, err := p.db.GetMentions(status.MentionIDs) + menchies, err := p.db.GetMentions(ctx, status.MentionIDs) if err != nil { return fmt.Errorf("notifyStatus: error getting mentions for status %s from the db: %s", status.ID, err) } @@ -47,7 +48,7 @@ func (p *processor) notifyStatus(status *gtsmodel.Status) error { for _, m := range status.Mentions { // make sure this is a local account, otherwise we don't need to create a notification for it if m.TargetAccount == nil { - a, err := p.db.GetAccountByID(m.TargetAccountID) + a, err := p.db.GetAccountByID(ctx, m.TargetAccountID) if err != nil { // we don't have the account or there's been an error return fmt.Errorf("notifyStatus: error getting account with id %s from the db: %s", m.TargetAccountID, err) @@ -60,7 +61,7 @@ func (p *processor) notifyStatus(status *gtsmodel.Status) error { } // make sure a notif doesn't already exist for this mention - err := p.db.GetWhere([]db.Where{ + err := p.db.GetWhere(ctx, []db.Where{ {Key: "notification_type", Value: gtsmodel.NotificationMention}, {Key: "target_account_id", Value: m.TargetAccountID}, {Key: "origin_account_id", Value: status.AccountID}, @@ -92,12 +93,12 @@ func (p *processor) notifyStatus(status *gtsmodel.Status) error { Status: status, } - if err := p.db.Put(notif); err != nil { + if err := p.db.Put(ctx, notif); err != nil { return fmt.Errorf("notifyStatus: error putting notification in database: %s", err) } // now stream the notification to the user - mastoNotif, err := p.tc.NotificationToMasto(notif) + mastoNotif, err := p.tc.NotificationToMasto(ctx, notif) if err != nil { return fmt.Errorf("notifyStatus: error converting notification to masto representation: %s", err) } @@ -110,7 +111,7 @@ func (p *processor) notifyStatus(status *gtsmodel.Status) error { return nil } -func (p *processor) notifyFollowRequest(followRequest *gtsmodel.FollowRequest, receivingAccount *gtsmodel.Account) error { +func (p *processor) notifyFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest, receivingAccount *gtsmodel.Account) error { // return if this isn't a local account if receivingAccount.Domain != "" { return nil @@ -128,12 +129,12 @@ func (p *processor) notifyFollowRequest(followRequest *gtsmodel.FollowRequest, r OriginAccountID: followRequest.AccountID, } - if err := p.db.Put(notif); err != nil { + if err := p.db.Put(ctx, notif); err != nil { return fmt.Errorf("notifyFollowRequest: error putting notification in database: %s", err) } // now stream the notification to the user - mastoNotif, err := p.tc.NotificationToMasto(notif) + mastoNotif, err := p.tc.NotificationToMasto(ctx, notif) if err != nil { return fmt.Errorf("notifyStatus: error converting notification to masto representation: %s", err) } @@ -145,14 +146,14 @@ func (p *processor) notifyFollowRequest(followRequest *gtsmodel.FollowRequest, r return nil } -func (p *processor) notifyFollow(follow *gtsmodel.Follow, targetAccount *gtsmodel.Account) error { +func (p *processor) notifyFollow(ctx context.Context, follow *gtsmodel.Follow, targetAccount *gtsmodel.Account) error { // return if this isn't a local account if targetAccount.Domain != "" { return nil } // first remove the follow request notification - if err := p.db.DeleteWhere([]db.Where{ + if err := p.db.DeleteWhere(ctx, []db.Where{ {Key: "notification_type", Value: gtsmodel.NotificationFollowRequest}, {Key: "target_account_id", Value: follow.TargetAccountID}, {Key: "origin_account_id", Value: follow.AccountID}, @@ -174,12 +175,12 @@ func (p *processor) notifyFollow(follow *gtsmodel.Follow, targetAccount *gtsmode OriginAccountID: follow.AccountID, OriginAccount: follow.Account, } - if err := p.db.Put(notif); err != nil { + if err := p.db.Put(ctx, notif); err != nil { return fmt.Errorf("notifyFollow: error putting notification in database: %s", err) } // now stream the notification to the user - mastoNotif, err := p.tc.NotificationToMasto(notif) + mastoNotif, err := p.tc.NotificationToMasto(ctx, notif) if err != nil { return fmt.Errorf("notifyStatus: error converting notification to masto representation: %s", err) } @@ -191,7 +192,7 @@ func (p *processor) notifyFollow(follow *gtsmodel.Follow, targetAccount *gtsmode return nil } -func (p *processor) notifyFave(fave *gtsmodel.StatusFave, targetAccount *gtsmodel.Account) error { +func (p *processor) notifyFave(ctx context.Context, fave *gtsmodel.StatusFave, targetAccount *gtsmodel.Account) error { // return if this isn't a local account if targetAccount.Domain != "" { return nil @@ -213,12 +214,12 @@ func (p *processor) notifyFave(fave *gtsmodel.StatusFave, targetAccount *gtsmode Status: fave.Status, } - if err := p.db.Put(notif); err != nil { + if err := p.db.Put(ctx, notif); err != nil { return fmt.Errorf("notifyFave: error putting notification in database: %s", err) } // now stream the notification to the user - mastoNotif, err := p.tc.NotificationToMasto(notif) + mastoNotif, err := p.tc.NotificationToMasto(ctx, notif) if err != nil { return fmt.Errorf("notifyStatus: error converting notification to masto representation: %s", err) } @@ -230,14 +231,14 @@ func (p *processor) notifyFave(fave *gtsmodel.StatusFave, targetAccount *gtsmode return nil } -func (p *processor) notifyAnnounce(status *gtsmodel.Status) error { +func (p *processor) notifyAnnounce(ctx context.Context, status *gtsmodel.Status) error { if status.BoostOfID == "" { // not a boost, nothing to do return nil } if status.BoostOf == nil { - boostedStatus, err := p.db.GetStatusByID(status.BoostOfID) + boostedStatus, err := p.db.GetStatusByID(ctx, status.BoostOfID) if err != nil { return fmt.Errorf("notifyAnnounce: error getting status with id %s: %s", status.BoostOfID, err) } @@ -245,7 +246,7 @@ func (p *processor) notifyAnnounce(status *gtsmodel.Status) error { } if status.BoostOfAccount == nil { - boostedAcct, err := p.db.GetAccountByID(status.BoostOfAccountID) + boostedAcct, err := p.db.GetAccountByID(ctx, status.BoostOfAccountID) if err != nil { return fmt.Errorf("notifyAnnounce: error getting account with id %s: %s", status.BoostOfAccountID, err) } @@ -264,7 +265,7 @@ func (p *processor) notifyAnnounce(status *gtsmodel.Status) error { } // make sure a notif doesn't already exist for this announce - err := p.db.GetWhere([]db.Where{ + err := p.db.GetWhere(ctx, []db.Where{ {Key: "notification_type", Value: gtsmodel.NotificationReblog}, {Key: "target_account_id", Value: status.BoostOfAccountID}, {Key: "origin_account_id", Value: status.AccountID}, @@ -292,12 +293,12 @@ func (p *processor) notifyAnnounce(status *gtsmodel.Status) error { Status: status, } - if err := p.db.Put(notif); err != nil { + if err := p.db.Put(ctx, notif); err != nil { return fmt.Errorf("notifyAnnounce: error putting notification in database: %s", err) } // now stream the notification to the user - mastoNotif, err := p.tc.NotificationToMasto(notif) + mastoNotif, err := p.tc.NotificationToMasto(ctx, notif) if err != nil { return fmt.Errorf("notifyStatus: error converting notification to masto representation: %s", err) } @@ -309,10 +310,10 @@ func (p *processor) notifyAnnounce(status *gtsmodel.Status) error { return nil } -func (p *processor) timelineStatus(status *gtsmodel.Status) error { +func (p *processor) timelineStatus(ctx context.Context, status *gtsmodel.Status) error { // make sure the author account is pinned onto the status if status.Account == nil { - a, err := p.db.GetAccountByID(status.AccountID) + a, err := p.db.GetAccountByID(ctx, status.AccountID) if err != nil { return fmt.Errorf("timelineStatus: error getting author account with id %s: %s", status.AccountID, err) } @@ -320,7 +321,7 @@ func (p *processor) timelineStatus(status *gtsmodel.Status) error { } // get local followers of the account that posted the status - follows, err := p.db.GetAccountFollowedBy(status.AccountID, true) + follows, err := p.db.GetAccountFollowedBy(ctx, status.AccountID, true) if err != nil { return fmt.Errorf("timelineStatus: error getting followers for account id %s: %s", status.AccountID, err) } @@ -338,7 +339,7 @@ func (p *processor) timelineStatus(status *gtsmodel.Status) error { errors := make(chan error, len(follows)) for _, f := range follows { - go p.timelineStatusForAccount(status, f.AccountID, errors, &wg) + go p.timelineStatusForAccount(ctx, status, f.AccountID, errors, &wg) } // read any errors that come in from the async functions @@ -365,18 +366,18 @@ func (p *processor) timelineStatus(status *gtsmodel.Status) error { return nil } -func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID string, errors chan error, wg *sync.WaitGroup) { +func (p *processor) timelineStatusForAccount(ctx context.Context, status *gtsmodel.Status, accountID string, errors chan error, wg *sync.WaitGroup) { defer wg.Done() // get the timeline owner account - timelineAccount, err := p.db.GetAccountByID(accountID) + timelineAccount, err := p.db.GetAccountByID(ctx, accountID) if err != nil { errors <- fmt.Errorf("timelineStatusForAccount: error getting account for timeline with id %s: %s", accountID, err) return } // make sure the status is timelineable - timelineable, err := p.filter.StatusHometimelineable(status, timelineAccount) + timelineable, err := p.filter.StatusHometimelineable(ctx, status, timelineAccount) if err != nil { errors <- fmt.Errorf("timelineStatusForAccount: error getting timelineability for status for timeline with id %s: %s", accountID, err) return @@ -387,7 +388,7 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID } // stick the status in the timeline for the account and then immediately prepare it so they can see it right away - inserted, err := p.timelineManager.IngestAndPrepare(status, timelineAccount.ID) + inserted, err := p.timelineManager.IngestAndPrepare(ctx, status, timelineAccount.ID) if err != nil { errors <- fmt.Errorf("timelineStatusForAccount: error ingesting status %s: %s", status.ID, err) return @@ -395,7 +396,7 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID // the status was inserted to stream it to the user if inserted { - mastoStatus, err := p.tc.StatusToMasto(status, timelineAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, status, timelineAccount) if err != nil { errors <- fmt.Errorf("timelineStatusForAccount: error converting status %s to frontend representation: %s", status.ID, err) } else { @@ -405,7 +406,7 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID } } - mastoStatus, err := p.tc.StatusToMasto(status, timelineAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, status, timelineAccount) if err != nil { errors <- fmt.Errorf("timelineStatusForAccount: error converting status %s to frontend representation: %s", status.ID, err) } else { @@ -415,8 +416,8 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID } } -func (p *processor) deleteStatusFromTimelines(status *gtsmodel.Status) error { - if err := p.timelineManager.WipeStatusFromAllTimelines(status.ID); err != nil { +func (p *processor) deleteStatusFromTimelines(ctx context.Context, status *gtsmodel.Status) error { + if err := p.timelineManager.WipeStatusFromAllTimelines(ctx, status.ID); err != nil { return err } diff --git a/internal/processing/fromfederator.go b/internal/processing/fromfederator.go index c95c27778..2bb74db34 100644 --- a/internal/processing/fromfederator.go +++ b/internal/processing/fromfederator.go @@ -19,6 +19,7 @@ package processing import ( + "context" "errors" "fmt" "net/url" @@ -29,7 +30,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/id" ) -func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) error { +func (p *processor) processFromFederator(ctx context.Context, federatorMsg gtsmodel.FromFederator) error { l := p.log.WithFields(logrus.Fields{ "func": "processFromFederator", "federatorMsg": fmt.Sprintf("%+v", federatorMsg), @@ -48,16 +49,16 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er return errors.New("note was not parseable as *gtsmodel.Status") } - status, err := p.federator.EnrichRemoteStatus(federatorMsg.ReceivingAccount.Username, incomingStatus) + status, err := p.federator.EnrichRemoteStatus(ctx, federatorMsg.ReceivingAccount.Username, incomingStatus) if err != nil { return err } - if err := p.timelineStatus(status); err != nil { + if err := p.timelineStatus(ctx, status); err != nil { return err } - if err := p.notifyStatus(status); err != nil { + if err := p.notifyStatus(ctx, status); err != nil { return err } case gtsmodel.ActivityStreamsProfile: @@ -70,7 +71,7 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er return errors.New("like was not parseable as *gtsmodel.StatusFave") } - if err := p.notifyFave(incomingFave, federatorMsg.ReceivingAccount); err != nil { + if err := p.notifyFave(ctx, incomingFave, federatorMsg.ReceivingAccount); err != nil { return err } case gtsmodel.ActivityStreamsFollow: @@ -80,7 +81,7 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er return errors.New("incomingFollowRequest was not parseable as *gtsmodel.FollowRequest") } - if err := p.notifyFollowRequest(incomingFollowRequest, federatorMsg.ReceivingAccount); err != nil { + if err := p.notifyFollowRequest(ctx, incomingFollowRequest, federatorMsg.ReceivingAccount); err != nil { return err } case gtsmodel.ActivityStreamsAnnounce: @@ -90,7 +91,7 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er return errors.New("announce was not parseable as *gtsmodel.Status") } - if err := p.federator.DereferenceAnnounce(incomingAnnounce, federatorMsg.ReceivingAccount.Username); err != nil { + if err := p.federator.DereferenceAnnounce(ctx, incomingAnnounce, federatorMsg.ReceivingAccount.Username); err != nil { return fmt.Errorf("error dereferencing announce from federator: %s", err) } @@ -100,17 +101,17 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er } incomingAnnounce.ID = incomingAnnounceID - if err := p.db.PutStatus(incomingAnnounce); err != nil { + if err := p.db.PutStatus(ctx, incomingAnnounce); err != nil { if err != db.ErrNoEntries { return fmt.Errorf("error adding dereferenced announce to the db: %s", err) } } - if err := p.timelineStatus(incomingAnnounce); err != nil { + if err := p.timelineStatus(ctx, incomingAnnounce); err != nil { return err } - if err := p.notifyAnnounce(incomingAnnounce); err != nil { + if err := p.notifyAnnounce(ctx, incomingAnnounce); err != nil { return err } case gtsmodel.ActivityStreamsBlock: @@ -121,10 +122,10 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er } // remove any of the blocking account's statuses from the blocked account's timeline, and vice versa - if err := p.timelineManager.WipeStatusesFromAccountID(block.AccountID, block.TargetAccountID); err != nil { + if err := p.timelineManager.WipeStatusesFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { return err } - if err := p.timelineManager.WipeStatusesFromAccountID(block.TargetAccountID, block.AccountID); err != nil { + if err := p.timelineManager.WipeStatusesFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { return err } // TODO: same with notifications @@ -145,7 +146,7 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er return err } - if _, _, err := p.federator.GetRemoteAccount(federatorMsg.ReceivingAccount.Username, incomingAccountURI, true); err != nil { + if _, _, err := p.federator.GetRemoteAccount(ctx, federatorMsg.ReceivingAccount.Username, incomingAccountURI, true); err != nil { return fmt.Errorf("error dereferencing account from federator: %s", err) } } @@ -165,25 +166,25 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er // delete all attachments for this status for _, a := range statusToDelete.AttachmentIDs { - if err := p.mediaProcessor.Delete(a); err != nil { + if err := p.mediaProcessor.Delete(ctx, a); err != nil { return err } } // delete all mentions for this status for _, m := range statusToDelete.MentionIDs { - if err := p.db.DeleteByID(m, >smodel.Mention{}); err != nil { + if err := p.db.DeleteByID(ctx, m, >smodel.Mention{}); err != nil { return err } } // delete all notifications for this status - if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: statusToDelete.ID}}, &[]*gtsmodel.Notification{}); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "status_id", Value: statusToDelete.ID}}, &[]*gtsmodel.Notification{}); err != nil { return err } // remove this status from any and all timelines - return p.deleteStatusFromTimelines(statusToDelete) + return p.deleteStatusFromTimelines(ctx, statusToDelete) case gtsmodel.ActivityStreamsProfile: // DELETE A PROFILE/ACCOUNT // TODO: handle side effects of account deletion here: delete all objects, statuses, media etc associated with account @@ -198,7 +199,7 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er return errors.New("follow was not parseable as *gtsmodel.Follow") } - if err := p.notifyFollow(follow, federatorMsg.ReceivingAccount); err != nil { + if err := p.notifyFollow(ctx, follow, federatorMsg.ReceivingAccount); err != nil { return err } } diff --git a/internal/processing/instance.go b/internal/processing/instance.go index b151744ef..ced798c2e 100644 --- a/internal/processing/instance.go +++ b/internal/processing/instance.go @@ -19,6 +19,7 @@ package processing import ( + "context" "fmt" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" @@ -29,13 +30,13 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) InstanceGet(domain string) (*apimodel.Instance, gtserror.WithCode) { +func (p *processor) InstanceGet(ctx context.Context, domain string) (*apimodel.Instance, gtserror.WithCode) { i := >smodel.Instance{} - if err := p.db.GetWhere([]db.Where{{Key: "domain", Value: domain}}, i); err != nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: domain}}, i); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error fetching instance %s: %s", p.config.Host, err)) } - ai, err := p.tc.InstanceToMasto(i) + ai, err := p.tc.InstanceToMasto(ctx, i) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting instance to api representation: %s", err)) } @@ -43,15 +44,15 @@ func (p *processor) InstanceGet(domain string) (*apimodel.Instance, gtserror.Wit return ai, nil } -func (p *processor) InstancePatch(form *apimodel.InstanceSettingsUpdateRequest) (*apimodel.Instance, gtserror.WithCode) { +func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSettingsUpdateRequest) (*apimodel.Instance, gtserror.WithCode) { // fetch the instance entry from the db for processing i := >smodel.Instance{} - if err := p.db.GetWhere([]db.Where{{Key: "domain", Value: p.config.Host}}, i); err != nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: p.config.Host}}, i); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error fetching instance %s: %s", p.config.Host, err)) } // fetch the instance account from the db for processing - ia, err := p.db.GetInstanceAccount("") + ia, err := p.db.GetInstanceAccount(ctx, "") if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error fetching instance account %s: %s", p.config.Host, err)) } @@ -67,13 +68,13 @@ func (p *processor) InstancePatch(form *apimodel.InstanceSettingsUpdateRequest) // validate & update site contact account if it's set on the form if form.ContactUsername != nil { // make sure the account with the given username exists in the db - contactAccount, err := p.db.GetLocalAccountByUsername(*form.ContactUsername) + contactAccount, err := p.db.GetLocalAccountByUsername(ctx, *form.ContactUsername) if err != nil { return nil, gtserror.NewErrorBadRequest(err, fmt.Sprintf("account with username %s not retrievable", *form.ContactUsername)) } // make sure it has a user associated with it contactUser := >smodel.User{} - if err := p.db.GetWhere([]db.Where{{Key: "account_id", Value: contactAccount.ID}}, contactUser); err != nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "account_id", Value: contactAccount.ID}}, contactUser); err != nil { return nil, gtserror.NewErrorBadRequest(err, fmt.Sprintf("user for account with username %s not retrievable", *form.ContactUsername)) } // suspended accounts cannot be contact accounts @@ -132,7 +133,7 @@ func (p *processor) InstancePatch(form *apimodel.InstanceSettingsUpdateRequest) // process avatar if provided if form.Avatar != nil && form.Avatar.Size != 0 { - _, err := p.accountProcessor.UpdateAvatar(form.Avatar, ia.ID) + _, err := p.accountProcessor.UpdateAvatar(ctx, form.Avatar, ia.ID) if err != nil { return nil, gtserror.NewErrorBadRequest(err, "error processing avatar") } @@ -140,17 +141,17 @@ func (p *processor) InstancePatch(form *apimodel.InstanceSettingsUpdateRequest) // process header if provided if form.Header != nil && form.Header.Size != 0 { - _, err := p.accountProcessor.UpdateHeader(form.Header, ia.ID) + _, err := p.accountProcessor.UpdateHeader(ctx, form.Header, ia.ID) if err != nil { return nil, gtserror.NewErrorBadRequest(err, "error processing header") } } - if err := p.db.UpdateByID(i.ID, i); err != nil { + if err := p.db.UpdateByID(ctx, i.ID, i); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error updating instance %s: %s", p.config.Host, err)) } - ai, err := p.tc.InstanceToMasto(i) + ai, err := p.tc.InstanceToMasto(ctx, i) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting instance to api representation: %s", err)) } diff --git a/internal/processing/media.go b/internal/processing/media.go index 6ca0eda5b..0b2443893 100644 --- a/internal/processing/media.go +++ b/internal/processing/media.go @@ -19,23 +19,25 @@ package processing import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) MediaCreate(authed *oauth.Auth, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) { - return p.mediaProcessor.Create(authed.Account, form) +func (p *processor) MediaCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) { + return p.mediaProcessor.Create(ctx, authed.Account, form) } -func (p *processor) MediaGet(authed *oauth.Auth, mediaAttachmentID string) (*apimodel.Attachment, gtserror.WithCode) { - return p.mediaProcessor.GetMedia(authed.Account, mediaAttachmentID) +func (p *processor) MediaGet(ctx context.Context, authed *oauth.Auth, mediaAttachmentID string) (*apimodel.Attachment, gtserror.WithCode) { + return p.mediaProcessor.GetMedia(ctx, authed.Account, mediaAttachmentID) } -func (p *processor) MediaUpdate(authed *oauth.Auth, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) { - return p.mediaProcessor.Update(authed.Account, mediaAttachmentID, form) +func (p *processor) MediaUpdate(ctx context.Context, authed *oauth.Auth, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) { + return p.mediaProcessor.Update(ctx, authed.Account, mediaAttachmentID, form) } -func (p *processor) FileGet(authed *oauth.Auth, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) { - return p.mediaProcessor.GetFile(authed.Account, form) +func (p *processor) FileGet(ctx context.Context, authed *oauth.Auth, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) { + return p.mediaProcessor.GetFile(ctx, authed.Account, form) } diff --git a/internal/processing/media/create.go b/internal/processing/media/create.go index 5b8cdf604..648e4d46a 100644 --- a/internal/processing/media/create.go +++ b/internal/processing/media/create.go @@ -20,6 +20,7 @@ package media import ( "bytes" + "context" "errors" "fmt" "io" @@ -29,7 +30,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/text" ) -func (p *processor) Create(account *gtsmodel.Account, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) { +func (p *processor) Create(ctx context.Context, account *gtsmodel.Account, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) { // open the attachment and extract the bytes from it f, err := form.File.Open() if err != nil { @@ -45,7 +46,7 @@ func (p *processor) Create(account *gtsmodel.Account, form *apimodel.AttachmentR } // allow the mediaHandler to work its magic of processing the attachment bytes, and putting them in whatever storage backend we're using - attachment, err := p.mediaHandler.ProcessAttachment(buf.Bytes(), account.ID, "") + attachment, err := p.mediaHandler.ProcessAttachment(ctx, buf.Bytes(), account.ID, "") if err != nil { return nil, fmt.Errorf("error reading attachment: %s", err) } @@ -66,13 +67,13 @@ func (p *processor) Create(account *gtsmodel.Account, form *apimodel.AttachmentR // prepare the frontend representation now -- if there are any errors here at least we can bail without // having already put something in the database and then having to clean it up again (eugh) - mastoAttachment, err := p.tc.AttachmentToMasto(attachment) + mastoAttachment, err := p.tc.AttachmentToMasto(ctx, attachment) if err != nil { return nil, fmt.Errorf("error parsing media attachment to frontend type: %s", err) } // now we can confidently put the attachment in the database - if err := p.db.Put(attachment); err != nil { + if err := p.db.Put(ctx, attachment); err != nil { return nil, fmt.Errorf("error storing media attachment in db: %s", err) } diff --git a/internal/processing/media/delete.go b/internal/processing/media/delete.go index b5ea8c806..281ddba03 100644 --- a/internal/processing/media/delete.go +++ b/internal/processing/media/delete.go @@ -1,17 +1,17 @@ package media import ( + "context" "fmt" "strings" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/gtserror" - "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Delete(mediaAttachmentID string) gtserror.WithCode { - a := >smodel.MediaAttachment{} - if err := p.db.GetByID(mediaAttachmentID, a); err != nil { +func (p *processor) Delete(ctx context.Context, mediaAttachmentID string) gtserror.WithCode { + attachment, err := p.db.GetAttachmentByID(ctx, mediaAttachmentID) + if err != nil { if err == db.ErrNoEntries { // attachment already gone return nil @@ -23,21 +23,21 @@ func (p *processor) Delete(mediaAttachmentID string) gtserror.WithCode { errs := []string{} // delete the thumbnail from storage - if a.Thumbnail.Path != "" { - if err := p.storage.RemoveFileAt(a.Thumbnail.Path); err != nil { - errs = append(errs, fmt.Sprintf("remove thumbnail at path %s: %s", a.Thumbnail.Path, err)) + if attachment.Thumbnail.Path != "" { + if err := p.storage.RemoveFileAt(attachment.Thumbnail.Path); err != nil { + errs = append(errs, fmt.Sprintf("remove thumbnail at path %s: %s", attachment.Thumbnail.Path, err)) } } // delete the file from storage - if a.File.Path != "" { - if err := p.storage.RemoveFileAt(a.File.Path); err != nil { - errs = append(errs, fmt.Sprintf("remove file at path %s: %s", a.File.Path, err)) + if attachment.File.Path != "" { + if err := p.storage.RemoveFileAt(attachment.File.Path); err != nil { + errs = append(errs, fmt.Sprintf("remove file at path %s: %s", attachment.File.Path, err)) } } // delete the attachment - if err := p.db.DeleteByID(mediaAttachmentID, a); err != nil { + if err := p.db.DeleteByID(ctx, mediaAttachmentID, attachment); err != nil { if err != db.ErrNoEntries { errs = append(errs, fmt.Sprintf("remove attachment: %s", err)) } diff --git a/internal/processing/media/getfile.go b/internal/processing/media/getfile.go index 01288c56d..c9c9b556d 100644 --- a/internal/processing/media/getfile.go +++ b/internal/processing/media/getfile.go @@ -19,6 +19,7 @@ package media import ( + "context" "fmt" "strings" @@ -28,7 +29,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/media" ) -func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) { +func (p *processor) GetFile(ctx context.Context, account *gtsmodel.Account, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) { // parse the form fields mediaSize, err := media.ParseMediaSize(form.MediaSize) if err != nil { @@ -47,8 +48,8 @@ func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContent wantedMediaID := spl[0] // get the account that owns the media and make sure it's not suspended - acct := >smodel.Account{} - if err := p.db.GetByID(form.AccountID, acct); err != nil { + acct, err := p.db.GetAccountByID(ctx, form.AccountID) + if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("account with id %s could not be selected from the db: %s", form.AccountID, err)) } if !acct.SuspendedAt.IsZero() { @@ -57,7 +58,7 @@ func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContent // make sure the requesting account and the media account don't block each other if account != nil { - blocked, err := p.db.IsBlocked(account.ID, form.AccountID, true) + blocked, err := p.db.IsBlocked(ctx, account.ID, form.AccountID, true) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("block status could not be established between accounts %s and %s: %s", form.AccountID, account.ID, err)) } @@ -73,7 +74,7 @@ func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContent switch mediaType { case media.Emoji: e := >smodel.Emoji{} - if err := p.db.GetByID(wantedMediaID, e); err != nil { + if err := p.db.GetByID(ctx, wantedMediaID, e); err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("emoji %s could not be taken from the db: %s", wantedMediaID, err)) } if e.Disabled { @@ -90,8 +91,8 @@ func (p *processor) GetFile(account *gtsmodel.Account, form *apimodel.GetContent return nil, gtserror.NewErrorNotFound(fmt.Errorf("media size %s not recognized for emoji", mediaSize)) } case media.Attachment, media.Header, media.Avatar: - a := >smodel.MediaAttachment{} - if err := p.db.GetByID(wantedMediaID, a); err != nil { + a, err := p.db.GetAttachmentByID(ctx, wantedMediaID) + if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("attachment %s could not be taken from the db: %s", wantedMediaID, err)) } if a.AccountID != form.AccountID { diff --git a/internal/processing/media/getmedia.go b/internal/processing/media/getmedia.go index 380a54cc2..91608e90d 100644 --- a/internal/processing/media/getmedia.go +++ b/internal/processing/media/getmedia.go @@ -19,6 +19,7 @@ package media import ( + "context" "errors" "fmt" @@ -28,9 +29,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) GetMedia(account *gtsmodel.Account, mediaAttachmentID string) (*apimodel.Attachment, gtserror.WithCode) { - attachment := >smodel.MediaAttachment{} - if err := p.db.GetByID(mediaAttachmentID, attachment); err != nil { +func (p *processor) GetMedia(ctx context.Context, account *gtsmodel.Account, mediaAttachmentID string) (*apimodel.Attachment, gtserror.WithCode) { + attachment, err := p.db.GetAttachmentByID(ctx, mediaAttachmentID) + if err != nil { if err == db.ErrNoEntries { // attachment doesn't exist return nil, gtserror.NewErrorNotFound(errors.New("attachment doesn't exist in the db")) @@ -42,7 +43,7 @@ func (p *processor) GetMedia(account *gtsmodel.Account, mediaAttachmentID string return nil, gtserror.NewErrorNotFound(errors.New("attachment not owned by requesting account")) } - a, err := p.tc.AttachmentToMasto(attachment) + a, err := p.tc.AttachmentToMasto(ctx, attachment) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error converting attachment: %s", err)) } diff --git a/internal/processing/media/media.go b/internal/processing/media/media.go index 79c9a7e18..6b88143e2 100644 --- a/internal/processing/media/media.go +++ b/internal/processing/media/media.go @@ -19,6 +19,8 @@ package media import ( + "context" + "github.com/sirupsen/logrus" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/blob" @@ -33,12 +35,12 @@ import ( // Processor wraps a bunch of functions for processing media actions. type Processor interface { // Create creates a new media attachment belonging to the given account, using the request form. - Create(account *gtsmodel.Account, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) + Create(ctx context.Context, account *gtsmodel.Account, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) // Delete deletes the media attachment with the given ID, including all files pertaining to that attachment. - Delete(mediaAttachmentID string) gtserror.WithCode - GetFile(account *gtsmodel.Account, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) - GetMedia(account *gtsmodel.Account, mediaAttachmentID string) (*apimodel.Attachment, gtserror.WithCode) - Update(account *gtsmodel.Account, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) + Delete(ctx context.Context, mediaAttachmentID string) gtserror.WithCode + GetFile(ctx context.Context, account *gtsmodel.Account, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) + GetMedia(ctx context.Context, account *gtsmodel.Account, mediaAttachmentID string) (*apimodel.Attachment, gtserror.WithCode) + Update(ctx context.Context, account *gtsmodel.Account, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) } type processor struct { diff --git a/internal/processing/media/update.go b/internal/processing/media/update.go index 89ed08ac1..6f15f2ace 100644 --- a/internal/processing/media/update.go +++ b/internal/processing/media/update.go @@ -19,6 +19,7 @@ package media import ( + "context" "errors" "fmt" @@ -29,9 +30,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/text" ) -func (p *processor) Update(account *gtsmodel.Account, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) { - attachment := >smodel.MediaAttachment{} - if err := p.db.GetByID(mediaAttachmentID, attachment); err != nil { +func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, mediaAttachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) { + attachment, err := p.db.GetAttachmentByID(ctx, mediaAttachmentID) + if err != nil { if err == db.ErrNoEntries { // attachment doesn't exist return nil, gtserror.NewErrorNotFound(errors.New("attachment doesn't exist in the db")) @@ -45,7 +46,7 @@ func (p *processor) Update(account *gtsmodel.Account, mediaAttachmentID string, if form.Description != nil { attachment.Description = text.RemoveHTML(*form.Description) - if err := p.db.UpdateByID(mediaAttachmentID, attachment); err != nil { + if err := p.db.UpdateByID(ctx, mediaAttachmentID, attachment); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error updating description: %s", err)) } } @@ -57,12 +58,12 @@ func (p *processor) Update(account *gtsmodel.Account, mediaAttachmentID string, } attachment.FileMeta.Focus.X = focusx attachment.FileMeta.Focus.Y = focusy - if err := p.db.UpdateByID(mediaAttachmentID, attachment); err != nil { + if err := p.db.UpdateByID(ctx, mediaAttachmentID, attachment); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error updating focus: %s", err)) } } - a, err := p.tc.AttachmentToMasto(attachment) + a, err := p.tc.AttachmentToMasto(ctx, attachment) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error converting attachment: %s", err)) } diff --git a/internal/processing/notification.go b/internal/processing/notification.go index 7af74b04f..f91d2f2cd 100644 --- a/internal/processing/notification.go +++ b/internal/processing/notification.go @@ -19,22 +19,24 @@ package processing import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) NotificationsGet(authed *oauth.Auth, limit int, maxID string, sinceID string) ([]*apimodel.Notification, gtserror.WithCode) { +func (p *processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, limit int, maxID string, sinceID string) ([]*apimodel.Notification, gtserror.WithCode) { l := p.log.WithField("func", "NotificationsGet") - notifs, err := p.db.GetNotifications(authed.Account.ID, limit, maxID, sinceID) + notifs, err := p.db.GetNotifications(ctx, authed.Account.ID, limit, maxID, sinceID) if err != nil { return nil, gtserror.NewErrorInternalError(err) } mastoNotifs := []*apimodel.Notification{} for _, n := range notifs { - mastoNotif, err := p.tc.NotificationToMasto(n) + mastoNotif, err := p.tc.NotificationToMasto(ctx, n) if err != nil { l.Debugf("got an error converting a notification to masto, will skip it: %s", err) continue diff --git a/internal/processing/processor.go b/internal/processing/processor.go index 48ed2a35f..8df464ce0 100644 --- a/internal/processing/processor.go +++ b/internal/processing/processor.go @@ -51,7 +51,7 @@ import ( // for clean distribution of messages without slowing down the client API and harming the user experience. type Processor interface { // Start starts the Processor, reading from its channels and passing messages back and forth. - Start() error + Start(ctx context.Context) error // Stop stops the processor cleanly, finishing handling any remaining messages before closing down. Stop() error @@ -64,108 +64,108 @@ type Processor interface { */ // AccountCreate processes the given form for creating a new account, returning an oauth token for that account if successful. - AccountCreate(authed *oauth.Auth, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) + AccountCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AccountCreateRequest) (*apimodel.Token, error) // AccountGet processes the given request for account information. - AccountGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Account, error) + AccountGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Account, error) // AccountUpdate processes the update of an account with the given form - AccountUpdate(authed *oauth.Auth, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) + AccountUpdate(ctx context.Context, authed *oauth.Auth, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, error) // AccountStatusesGet fetches a number of statuses (in time descending order) from the given account, filtered by visibility for // the account given in authed. - AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) + AccountStatusesGet(ctx context.Context, authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, gtserror.WithCode) // AccountFollowersGet fetches a list of the target account's followers. - AccountFollowersGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) + AccountFollowersGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) // AccountFollowingGet fetches a list of the accounts that target account is following. - AccountFollowingGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) + AccountFollowingGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, gtserror.WithCode) // AccountRelationshipGet returns a relationship model describing the relationship of the targetAccount to the Authed account. - AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + AccountRelationshipGet(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // AccountFollowCreate handles a follow request to an account, either remote or local. - AccountFollowCreate(authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) + AccountFollowCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) // AccountFollowRemove handles the removal of a follow/follow request to an account, either remote or local. - AccountFollowRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + AccountFollowRemove(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // AccountBlockCreate handles the creation of a block from authed account to target account, either remote or local. - AccountBlockCreate(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + AccountBlockCreate(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // AccountBlockRemove handles the removal of a block from authed account to target account, either remote or local. - AccountBlockRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) + AccountBlockRemove(ctx context.Context, authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, gtserror.WithCode) // AdminEmojiCreate handles the creation of a new instance emoji by an admin, using the given form. - AdminEmojiCreate(authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) + AdminEmojiCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error) // AdminDomainBlockCreate handles the creation of a new domain block by an admin, using the given form. - AdminDomainBlockCreate(authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) (*apimodel.DomainBlock, gtserror.WithCode) + AdminDomainBlockCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) (*apimodel.DomainBlock, gtserror.WithCode) // AdminDomainBlocksImport handles the import of multiple domain blocks by an admin, using the given form. - AdminDomainBlocksImport(authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) ([]*apimodel.DomainBlock, gtserror.WithCode) + AdminDomainBlocksImport(ctx context.Context, authed *oauth.Auth, form *apimodel.DomainBlockCreateRequest) ([]*apimodel.DomainBlock, gtserror.WithCode) // AdminDomainBlocksGet returns a list of currently blocked domains. - AdminDomainBlocksGet(authed *oauth.Auth, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) + AdminDomainBlocksGet(ctx context.Context, authed *oauth.Auth, export bool) ([]*apimodel.DomainBlock, gtserror.WithCode) // AdminDomainBlockGet returns one domain block, specified by ID. - AdminDomainBlockGet(authed *oauth.Auth, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) + AdminDomainBlockGet(ctx context.Context, authed *oauth.Auth, id string, export bool) (*apimodel.DomainBlock, gtserror.WithCode) // AdminDomainBlockDelete deletes one domain block, specified by ID, returning the deleted domain block. - AdminDomainBlockDelete(authed *oauth.Auth, id string) (*apimodel.DomainBlock, gtserror.WithCode) + AdminDomainBlockDelete(ctx context.Context, authed *oauth.Auth, id string) (*apimodel.DomainBlock, gtserror.WithCode) // AppCreate processes the creation of a new API application - AppCreate(authed *oauth.Auth, form *apimodel.ApplicationCreateRequest) (*apimodel.Application, error) + AppCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.ApplicationCreateRequest) (*apimodel.Application, error) // BlocksGet returns a list of accounts blocked by the requesting account. - BlocksGet(authed *oauth.Auth, maxID string, sinceID string, limit int) (*apimodel.BlocksResponse, gtserror.WithCode) + BlocksGet(ctx context.Context, authed *oauth.Auth, maxID string, sinceID string, limit int) (*apimodel.BlocksResponse, gtserror.WithCode) // FileGet handles the fetching of a media attachment file via the fileserver. - FileGet(authed *oauth.Auth, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) + FileGet(ctx context.Context, authed *oauth.Auth, form *apimodel.GetContentRequestForm) (*apimodel.Content, error) // FollowRequestsGet handles the getting of the authed account's incoming follow requests - FollowRequestsGet(auth *oauth.Auth) ([]apimodel.Account, gtserror.WithCode) + FollowRequestsGet(ctx context.Context, auth *oauth.Auth) ([]apimodel.Account, gtserror.WithCode) // FollowRequestAccept handles the acceptance of a follow request from the given account ID - FollowRequestAccept(auth *oauth.Auth, accountID string) (*apimodel.Relationship, gtserror.WithCode) + FollowRequestAccept(ctx context.Context, auth *oauth.Auth, accountID string) (*apimodel.Relationship, gtserror.WithCode) // InstanceGet retrieves instance information for serving at api/v1/instance - InstanceGet(domain string) (*apimodel.Instance, gtserror.WithCode) + InstanceGet(ctx context.Context, domain string) (*apimodel.Instance, gtserror.WithCode) // InstancePatch updates this instance according to the given form. // // It should already be ascertained that the requesting account is authenticated and an admin. - InstancePatch(form *apimodel.InstanceSettingsUpdateRequest) (*apimodel.Instance, gtserror.WithCode) + InstancePatch(ctx context.Context, form *apimodel.InstanceSettingsUpdateRequest) (*apimodel.Instance, gtserror.WithCode) // MediaCreate handles the creation of a media attachment, using the given form. - MediaCreate(authed *oauth.Auth, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) + MediaCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AttachmentRequest) (*apimodel.Attachment, error) // MediaGet handles the GET of a media attachment with the given ID - MediaGet(authed *oauth.Auth, attachmentID string) (*apimodel.Attachment, gtserror.WithCode) + MediaGet(ctx context.Context, authed *oauth.Auth, attachmentID string) (*apimodel.Attachment, gtserror.WithCode) // MediaUpdate handles the PUT of a media attachment with the given ID and form - MediaUpdate(authed *oauth.Auth, attachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) + MediaUpdate(ctx context.Context, authed *oauth.Auth, attachmentID string, form *apimodel.AttachmentUpdateRequest) (*apimodel.Attachment, gtserror.WithCode) // NotificationsGet - NotificationsGet(authed *oauth.Auth, limit int, maxID string, sinceID string) ([]*apimodel.Notification, gtserror.WithCode) + NotificationsGet(ctx context.Context, authed *oauth.Auth, limit int, maxID string, sinceID string) ([]*apimodel.Notification, gtserror.WithCode) // SearchGet performs a search with the given params, resolving/dereferencing remotely as desired - SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQuery) (*apimodel.SearchResult, gtserror.WithCode) + SearchGet(ctx context.Context, authed *oauth.Auth, searchQuery *apimodel.SearchQuery) (*apimodel.SearchResult, gtserror.WithCode) // StatusCreate processes the given form to create a new status, returning the api model representation of that status if it's OK. - StatusCreate(authed *oauth.Auth, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, error) + StatusCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, error) // StatusDelete processes the delete of a given status, returning the deleted status if the delete goes through. - StatusDelete(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) + StatusDelete(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) // StatusFave processes the faving of a given status, returning the updated status if the fave goes through. - StatusFave(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) + StatusFave(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) // StatusBoost processes the boost/reblog of a given status, returning the newly-created boost if all is well. - StatusBoost(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + StatusBoost(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // StatusUnboost processes the unboost/unreblog of a given status, returning the status if all is well. - StatusUnboost(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + StatusUnboost(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // StatusBoostedBy returns a slice of accounts that have boosted the given status, filtered according to privacy settings. - StatusBoostedBy(authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) + StatusBoostedBy(ctx context.Context, authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) // StatusFavedBy returns a slice of accounts that have liked the given status, filtered according to privacy settings. - StatusFavedBy(authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, error) + StatusFavedBy(ctx context.Context, authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, error) // StatusGet gets the given status, taking account of privacy settings and blocks etc. - StatusGet(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) + StatusGet(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) // StatusUnfave processes the unfaving of a given status, returning the updated status if the fave goes through. - StatusUnfave(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) + StatusUnfave(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) // StatusGetContext returns the context (previous and following posts) from the given status ID - StatusGetContext(authed *oauth.Auth, targetStatusID string) (*apimodel.Context, gtserror.WithCode) + StatusGetContext(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Context, gtserror.WithCode) // 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) + HomeTimelineGet(ctx context.Context, 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.StatusTimelineResponse, gtserror.WithCode) + PublicTimelineGet(ctx context.Context, 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) + FavedTimelineGet(ctx context.Context, 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) + AuthorizeStreamingRequest(ctx context.Context, accessToken string) (*gtsmodel.Account, error) // OpenStreamForAccount opens a new stream for the given account, with the given stream type. - OpenStreamForAccount(account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) + OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) /* FEDERATION API-FACING PROCESSING FUNCTIONS @@ -199,10 +199,10 @@ type Processor interface { GetWebfingerAccount(ctx context.Context, requestedUsername string, requestURL *url.URL) (*apimodel.WellKnownResponse, gtserror.WithCode) // GetNodeInfoRel returns a well known response giving the path to node info. - GetNodeInfoRel(request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode) + GetNodeInfoRel(ctx context.Context, request *http.Request) (*apimodel.WellKnownResponse, gtserror.WithCode) // GetNodeInfo returns a node info struct in response to a node info request. - GetNodeInfo(request *http.Request) (*apimodel.Nodeinfo, gtserror.WithCode) + GetNodeInfo(ctx context.Context, request *http.Request) (*apimodel.Nodeinfo, gtserror.WithCode) // InboxPost handles POST requests to a user's inbox for new activitypub messages. // @@ -280,7 +280,7 @@ func NewProcessor(config *config.Config, tc typeutils.TypeConverter, federator f } // Start starts the Processor, reading from its channels and passing messages back and forth. -func (p *processor) Start() error { +func (p *processor) Start(ctx context.Context) error { go func() { DistLoop: for { @@ -288,14 +288,14 @@ func (p *processor) Start() error { case clientMsg := <-p.fromClientAPI: p.log.Tracef("received message FROM client API: %+v", clientMsg) go func() { - if err := p.processFromClientAPI(clientMsg); err != nil { + if err := p.processFromClientAPI(ctx, clientMsg); err != nil { p.log.Error(err) } }() case federatorMsg := <-p.fromFederator: p.log.Tracef("received message FROM federator: %+v", federatorMsg) go func() { - if err := p.processFromFederator(federatorMsg); err != nil { + if err := p.processFromFederator(ctx, federatorMsg); err != nil { p.log.Error(err) } }() diff --git a/internal/processing/search.go b/internal/processing/search.go index f2ae721ae..768fceacd 100644 --- a/internal/processing/search.go +++ b/internal/processing/search.go @@ -19,6 +19,7 @@ package processing import ( + "context" "fmt" "net/url" "strings" @@ -32,7 +33,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQuery) (*apimodel.SearchResult, gtserror.WithCode) { +func (p *processor) SearchGet(ctx context.Context, authed *oauth.Auth, searchQuery *apimodel.SearchQuery) (*apimodel.SearchResult, gtserror.WithCode) { l := p.log.WithFields(logrus.Fields{ "func": "SearchGet", "query": searchQuery.Query, @@ -54,7 +55,7 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu // check if the query is something like @whatever_username@example.org -- this means it's a remote account if !foundOne && util.IsMention(searchQuery.Query) { l.Debug("search term is a mention, looking it up...") - foundAccount, err := p.searchAccountByMention(authed, searchQuery.Query, searchQuery.Resolve) + foundAccount, err := p.searchAccountByMention(ctx, authed, searchQuery.Query, searchQuery.Resolve) if err == nil && foundAccount != nil { foundAccounts = append(foundAccounts, foundAccount) foundOne = true @@ -65,14 +66,14 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu // check if the query is a URI and just do a lookup for that, straight up if uri, err := url.Parse(query); err == nil && !foundOne { // 1. check if it's a status - if foundStatus, err := p.searchStatusByURI(authed, uri, searchQuery.Resolve); err == nil && foundStatus != nil { + if foundStatus, err := p.searchStatusByURI(ctx, authed, uri, searchQuery.Resolve); err == nil && foundStatus != nil { foundStatuses = append(foundStatuses, foundStatus) foundOne = true l.Debug("got a status by searching by URI") } // 2. check if it's an account - if foundAccount, err := p.searchAccountByURI(authed, uri, searchQuery.Resolve); err == nil && foundAccount != nil { + if foundAccount, err := p.searchAccountByURI(ctx, authed, uri, searchQuery.Resolve); err == nil && foundAccount != nil { foundAccounts = append(foundAccounts, foundAccount) foundOne = true l.Debug("got an account by searching by URI") @@ -90,20 +91,20 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu */ for _, foundAccount := range foundAccounts { // make sure there's no block in either direction between the account and the requester - if blocked, err := p.db.IsBlocked(authed.Account.ID, foundAccount.ID, true); err == nil && !blocked { + if blocked, err := p.db.IsBlocked(ctx, authed.Account.ID, foundAccount.ID, true); err == nil && !blocked { // all good, convert it and add it to the results - if acctMasto, err := p.tc.AccountToMastoPublic(foundAccount); err == nil && acctMasto != nil { + if acctMasto, err := p.tc.AccountToMastoPublic(ctx, foundAccount); err == nil && acctMasto != nil { results.Accounts = append(results.Accounts, *acctMasto) } } } for _, foundStatus := range foundStatuses { - if visible, err := p.filter.StatusVisible(foundStatus, authed.Account); !visible || err != nil { + if visible, err := p.filter.StatusVisible(ctx, foundStatus, authed.Account); !visible || err != nil { continue } - statusMasto, err := p.tc.StatusToMasto(foundStatus, authed.Account) + statusMasto, err := p.tc.StatusToMasto(ctx, foundStatus, authed.Account) if err != nil { continue } @@ -114,24 +115,24 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu return results, nil } -func (p *processor) searchStatusByURI(authed *oauth.Auth, uri *url.URL, resolve bool) (*gtsmodel.Status, error) { +func (p *processor) searchStatusByURI(ctx context.Context, authed *oauth.Auth, uri *url.URL, resolve bool) (*gtsmodel.Status, error) { l := p.log.WithFields(logrus.Fields{ "func": "searchStatusByURI", "uri": uri.String(), "resolve": resolve, }) - if maybeStatus, err := p.db.GetStatusByURI(uri.String()); err == nil { + if maybeStatus, err := p.db.GetStatusByURI(ctx, uri.String()); err == nil { return maybeStatus, nil - } else if maybeStatus, err := p.db.GetStatusByURL(uri.String()); err == nil { + } else if maybeStatus, err := p.db.GetStatusByURL(ctx, uri.String()); err == nil { return maybeStatus, nil } // we don't have it locally so dereference it if we're allowed to if resolve { - status, _, _, err := p.federator.GetRemoteStatus(authed.Account.Username, uri, true) + status, _, _, err := p.federator.GetRemoteStatus(ctx, authed.Account.Username, uri, true) if err == nil { - if err := p.federator.DereferenceRemoteThread(authed.Account.Username, uri); err != nil { + if err := p.federator.DereferenceRemoteThread(ctx, authed.Account.Username, uri); err != nil { // try to deref the thread while we're here l.Debugf("searchStatusByURI: error dereferencing remote thread: %s", err) } @@ -141,16 +142,16 @@ func (p *processor) searchStatusByURI(authed *oauth.Auth, uri *url.URL, resolve return nil, nil } -func (p *processor) searchAccountByURI(authed *oauth.Auth, uri *url.URL, resolve bool) (*gtsmodel.Account, error) { - if maybeAccount, err := p.db.GetAccountByURI(uri.String()); err == nil { +func (p *processor) searchAccountByURI(ctx context.Context, authed *oauth.Auth, uri *url.URL, resolve bool) (*gtsmodel.Account, error) { + if maybeAccount, err := p.db.GetAccountByURI(ctx, uri.String()); err == nil { return maybeAccount, nil - } else if maybeAccount, err := p.db.GetAccountByURL(uri.String()); err == nil { + } else if maybeAccount, err := p.db.GetAccountByURL(ctx, uri.String()); err == nil { return maybeAccount, nil } if resolve { // we don't have it locally so try and dereference it - account, _, err := p.federator.GetRemoteAccount(authed.Account.Username, uri, true) + account, _, err := p.federator.GetRemoteAccount(ctx, authed.Account.Username, uri, true) if err != nil { return nil, fmt.Errorf("searchAccountByURI: error dereferencing account with uri %s: %s", uri.String(), err) } @@ -159,7 +160,7 @@ func (p *processor) searchAccountByURI(authed *oauth.Auth, uri *url.URL, resolve return nil, nil } -func (p *processor) searchAccountByMention(authed *oauth.Auth, mention string, resolve bool) (*gtsmodel.Account, error) { +func (p *processor) searchAccountByMention(ctx context.Context, authed *oauth.Auth, mention string, resolve bool) (*gtsmodel.Account, error) { // query is for a remote account username, domain, err := util.ExtractMentionParts(mention) if err != nil { @@ -169,7 +170,7 @@ func (p *processor) searchAccountByMention(authed *oauth.Auth, mention string, r // if it's a local account we can skip a whole bunch of stuff maybeAcct := >smodel.Account{} if domain == p.config.Host { - maybeAcct, err = p.db.GetLocalAccountByUsername(username) + maybeAcct, err = p.db.GetLocalAccountByUsername(ctx, username) if err != nil { return nil, fmt.Errorf("searchAccountByMention: error getting local account by username: %s", err) } @@ -181,7 +182,7 @@ func (p *processor) searchAccountByMention(authed *oauth.Auth, mention string, r {Key: "username", Value: username, CaseInsensitive: true}, {Key: "domain", Value: domain, CaseInsensitive: true}, } - err = p.db.GetWhere(where, maybeAcct) + err = p.db.GetWhere(ctx, where, maybeAcct) if err == nil { // we've got it stored locally already! return maybeAcct, nil @@ -197,14 +198,14 @@ func (p *processor) searchAccountByMention(authed *oauth.Auth, mention string, r // we're allowed to resolve it so let's try // first we need to webfinger the remote account to convert the username and domain into the activitypub URI for the account - acctURI, err := p.federator.FingerRemoteAccount(authed.Account.Username, username, domain) + acctURI, err := p.federator.FingerRemoteAccount(ctx, authed.Account.Username, username, domain) if err != nil { // something went wrong doing the webfinger lookup so we can't process the request return nil, fmt.Errorf("searchAccountByMention: error fingering remote account with username %s and domain %s: %s", username, domain, err) } // we don't have it locally so try and dereference it - account, _, err := p.federator.GetRemoteAccount(authed.Account.Username, acctURI, true) + account, _, err := p.federator.GetRemoteAccount(ctx, authed.Account.Username, acctURI, true) if err != nil { return nil, fmt.Errorf("searchAccountByMention: error dereferencing account with uri %s: %s", acctURI.String(), err) } diff --git a/internal/processing/status.go b/internal/processing/status.go index ab3843ded..c31c20628 100644 --- a/internal/processing/status.go +++ b/internal/processing/status.go @@ -19,47 +19,49 @@ package processing import ( + "context" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -func (p *processor) StatusCreate(authed *oauth.Auth, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, error) { - return p.statusProcessor.Create(authed.Account, authed.Application, form) +func (p *processor) StatusCreate(ctx context.Context, authed *oauth.Auth, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, error) { + return p.statusProcessor.Create(ctx, authed.Account, authed.Application, form) } -func (p *processor) StatusDelete(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { - return p.statusProcessor.Delete(authed.Account, targetStatusID) +func (p *processor) StatusDelete(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { + return p.statusProcessor.Delete(ctx, authed.Account, targetStatusID) } -func (p *processor) StatusFave(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { - return p.statusProcessor.Fave(authed.Account, targetStatusID) +func (p *processor) StatusFave(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { + return p.statusProcessor.Fave(ctx, authed.Account, targetStatusID) } -func (p *processor) StatusBoost(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - return p.statusProcessor.Boost(authed.Account, authed.Application, targetStatusID) +func (p *processor) StatusBoost(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + return p.statusProcessor.Boost(ctx, authed.Account, authed.Application, targetStatusID) } -func (p *processor) StatusUnboost(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - return p.statusProcessor.Unboost(authed.Account, authed.Application, targetStatusID) +func (p *processor) StatusUnboost(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + return p.statusProcessor.Unboost(ctx, authed.Account, authed.Application, targetStatusID) } -func (p *processor) StatusBoostedBy(authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) { - return p.statusProcessor.BoostedBy(authed.Account, targetStatusID) +func (p *processor) StatusBoostedBy(ctx context.Context, authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) { + return p.statusProcessor.BoostedBy(ctx, authed.Account, targetStatusID) } -func (p *processor) StatusFavedBy(authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, error) { - return p.statusProcessor.FavedBy(authed.Account, targetStatusID) +func (p *processor) StatusFavedBy(ctx context.Context, authed *oauth.Auth, targetStatusID string) ([]*apimodel.Account, error) { + return p.statusProcessor.FavedBy(ctx, authed.Account, targetStatusID) } -func (p *processor) StatusGet(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { - return p.statusProcessor.Get(authed.Account, targetStatusID) +func (p *processor) StatusGet(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { + return p.statusProcessor.Get(ctx, authed.Account, targetStatusID) } -func (p *processor) StatusUnfave(authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { - return p.statusProcessor.Unfave(authed.Account, targetStatusID) +func (p *processor) StatusUnfave(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Status, error) { + return p.statusProcessor.Unfave(ctx, authed.Account, targetStatusID) } -func (p *processor) StatusGetContext(authed *oauth.Auth, targetStatusID string) (*apimodel.Context, gtserror.WithCode) { - return p.statusProcessor.Context(authed.Account, targetStatusID) +func (p *processor) StatusGetContext(ctx context.Context, authed *oauth.Auth, targetStatusID string) (*apimodel.Context, gtserror.WithCode) { + return p.statusProcessor.Context(ctx, authed.Account, targetStatusID) } diff --git a/internal/processing/status/boost.go b/internal/processing/status/boost.go index d7a62beb1..948d57a48 100644 --- a/internal/processing/status/boost.go +++ b/internal/processing/status/boost.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -9,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Boost(ctx context.Context, requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -18,7 +37,7 @@ func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsm return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -32,7 +51,7 @@ func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsm } // it's visible! it's boostable! so let's boost the FUCK out of it - boostWrapperStatus, err := p.tc.StatusToBoost(targetStatus, requestingAccount) + boostWrapperStatus, err := p.tc.StatusToBoost(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -41,7 +60,7 @@ func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsm boostWrapperStatus.BoostOfAccount = targetStatus.Account // put the boost in the database - if err := p.db.PutStatus(boostWrapperStatus); err != nil { + if err := p.db.PutStatus(ctx, boostWrapperStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -55,7 +74,7 @@ func (p *processor) Boost(requestingAccount *gtsmodel.Account, application *gtsm } // return the frontend representation of the new status to the submitter - mastoStatus, err := p.tc.StatusToMasto(boostWrapperStatus, requestingAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, boostWrapperStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } diff --git a/internal/processing/status/boostedby.go b/internal/processing/status/boostedby.go index 1bde6b5ae..46f41039f 100644 --- a/internal/processing/status/boostedby.go +++ b/internal/processing/status/boostedby.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -9,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) BoostedBy(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -18,7 +37,7 @@ func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusI return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -26,7 +45,7 @@ func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusI return nil, gtserror.NewErrorNotFound(errors.New("status is not visible")) } - statusReblogs, err := p.db.GetStatusReblogs(targetStatus) + statusReblogs, err := p.db.GetStatusReblogs(ctx, targetStatus) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error seeing who boosted status: %s", err)) } @@ -34,7 +53,7 @@ func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusI // filter the list so the user doesn't see accounts they blocked or which blocked them filteredAccounts := []*gtsmodel.Account{} for _, s := range statusReblogs { - blocked, err := p.db.IsBlocked(requestingAccount.ID, s.AccountID, true) + blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, s.AccountID, true) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error checking blocks: %s", err)) } @@ -48,7 +67,7 @@ func (p *processor) BoostedBy(requestingAccount *gtsmodel.Account, targetStatusI // now we can return the masto representation of those accounts mastoAccounts := []*apimodel.Account{} for _, acc := range filteredAccounts { - mastoAccount, err := p.tc.AccountToMastoPublic(acc) + mastoAccount, err := p.tc.AccountToMastoPublic(ctx, acc) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusFavedBy: error converting account to api model: %s", err)) } diff --git a/internal/processing/status/context.go b/internal/processing/status/context.go index 43002545e..3e8e93d09 100644 --- a/internal/processing/status/context.go +++ b/internal/processing/status/context.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" "sort" @@ -10,8 +29,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Context(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Context, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Context(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Context, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -19,7 +38,7 @@ func (p *processor) Context(requestingAccount *gtsmodel.Account, targetStatusID return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -32,14 +51,14 @@ func (p *processor) Context(requestingAccount *gtsmodel.Account, targetStatusID Descendants: []apimodel.Status{}, } - parents, err := p.db.GetStatusParents(targetStatus, false) + parents, err := p.db.GetStatusParents(ctx, targetStatus, false) if err != nil { return nil, gtserror.NewErrorInternalError(err) } for _, status := range parents { - if v, err := p.filter.StatusVisible(status, requestingAccount); err == nil && v { - mastoStatus, err := p.tc.StatusToMasto(status, requestingAccount) + if v, err := p.filter.StatusVisible(ctx, status, requestingAccount); err == nil && v { + mastoStatus, err := p.tc.StatusToMasto(ctx, status, requestingAccount) if err == nil { context.Ancestors = append(context.Ancestors, *mastoStatus) } @@ -50,14 +69,14 @@ func (p *processor) Context(requestingAccount *gtsmodel.Account, targetStatusID return context.Ancestors[i].ID < context.Ancestors[j].ID }) - children, err := p.db.GetStatusChildren(targetStatus, false, "") + children, err := p.db.GetStatusChildren(ctx, targetStatus, false, "") if err != nil { return nil, gtserror.NewErrorInternalError(err) } for _, status := range children { - if v, err := p.filter.StatusVisible(status, requestingAccount); err == nil && v { - mastoStatus, err := p.tc.StatusToMasto(status, requestingAccount) + if v, err := p.filter.StatusVisible(ctx, status, requestingAccount); err == nil && v { + mastoStatus, err := p.tc.StatusToMasto(ctx, status, requestingAccount) if err == nil { context.Descendants = append(context.Descendants, *mastoStatus) } diff --git a/internal/processing/status/create.go b/internal/processing/status/create.go index fc112ed8b..2e0b30ad8 100644 --- a/internal/processing/status/create.go +++ b/internal/processing/status/create.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "fmt" "time" @@ -12,7 +31,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) Create(account *gtsmodel.Account, application *gtsmodel.Application, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, gtserror.WithCode) { +func (p *processor) Create(ctx context.Context, account *gtsmodel.Account, application *gtsmodel.Application, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, gtserror.WithCode) { uris := util.GenerateURIsForAccount(account.Username, p.config.Protocol, p.config.Host) thisStatusID, err := id.NewULID() if err != nil { @@ -38,40 +57,40 @@ func (p *processor) Create(account *gtsmodel.Account, application *gtsmodel.Appl Text: form.Status, } - if err := p.ProcessReplyToID(form, account.ID, newStatus); err != nil { + if err := p.ProcessReplyToID(ctx, form, account.ID, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessMediaIDs(form, account.ID, newStatus); err != nil { + if err := p.ProcessMediaIDs(ctx, form, account.ID, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessVisibility(form, account.Privacy, newStatus); err != nil { + if err := p.ProcessVisibility(ctx, form, account.Privacy, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessLanguage(form, account.Language, newStatus); err != nil { + if err := p.ProcessLanguage(ctx, form, account.Language, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessMentions(form, account.ID, newStatus); err != nil { + if err := p.ProcessMentions(ctx, form, account.ID, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessTags(form, account.ID, newStatus); err != nil { + if err := p.ProcessTags(ctx, form, account.ID, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessEmojis(form, account.ID, newStatus); err != nil { + if err := p.ProcessEmojis(ctx, form, account.ID, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } - if err := p.ProcessContent(form, account.ID, newStatus); err != nil { + if err := p.ProcessContent(ctx, form, account.ID, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } // put the new status in the database - if err := p.db.PutStatus(newStatus); err != nil { + if err := p.db.PutStatus(ctx, newStatus); err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -84,7 +103,7 @@ func (p *processor) Create(account *gtsmodel.Account, application *gtsmodel.Appl } // return the frontend representation of the new status to the submitter - mastoStatus, err := p.tc.StatusToMasto(newStatus, account) + mastoStatus, err := p.tc.StatusToMasto(ctx, newStatus, account) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", newStatus.ID, err)) } diff --git a/internal/processing/status/delete.go b/internal/processing/status/delete.go index 4c5dfd744..daa7a934f 100644 --- a/internal/processing/status/delete.go +++ b/internal/processing/status/delete.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -9,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Delete(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Delete(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -22,12 +41,12 @@ func (p *processor) Delete(requestingAccount *gtsmodel.Account, targetStatusID s return nil, gtserror.NewErrorForbidden(errors.New("status doesn't belong to requesting account")) } - mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } - if err := p.db.DeleteByID(targetStatus.ID, >smodel.Status{}); err != nil { + if err := p.db.DeleteByID(ctx, targetStatus.ID, >smodel.Status{}); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error deleting status from the database: %s", err)) } diff --git a/internal/processing/status/fave.go b/internal/processing/status/fave.go index 7ba8c8fe8..2badf83b3 100644 --- a/internal/processing/status/fave.go +++ b/internal/processing/status/fave.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -12,8 +31,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Fave(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -21,7 +40,7 @@ func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID str return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -37,7 +56,7 @@ func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID str // first check if the status is already faved, if so we don't need to do anything newFave := true gtsFave := >smodel.StatusFave{} - if err := p.db.GetWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave); err == nil { + if err := p.db.GetWhere(ctx, []db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave); err == nil { // we already have a fave for this status newFave = false } @@ -60,7 +79,7 @@ func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID str URI: util.GenerateURIForLike(requestingAccount.Username, p.config.Protocol, p.config.Host, thisFaveID), } - if err := p.db.Put(gtsFave); err != nil { + if err := p.db.Put(ctx, gtsFave); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error putting fave in database: %s", err)) } @@ -75,7 +94,7 @@ func (p *processor) Fave(requestingAccount *gtsmodel.Account, targetStatusID str } // return the mastodon representation of the target status - mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } diff --git a/internal/processing/status/favedby.go b/internal/processing/status/favedby.go index dffe6bba9..227fb669d 100644 --- a/internal/processing/status/favedby.go +++ b/internal/processing/status/favedby.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -9,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) FavedBy(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -18,7 +37,7 @@ func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -26,7 +45,7 @@ func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID return nil, gtserror.NewErrorNotFound(errors.New("status is not visible")) } - statusFaves, err := p.db.GetStatusFaves(targetStatus) + statusFaves, err := p.db.GetStatusFaves(ctx, targetStatus) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing who faved status: %s", err)) } @@ -34,7 +53,7 @@ func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID // filter the list so the user doesn't see accounts they blocked or which blocked them filteredAccounts := []*gtsmodel.Account{} for _, fave := range statusFaves { - blocked, err := p.db.IsBlocked(requestingAccount.ID, fave.AccountID, true) + blocked, err := p.db.IsBlocked(ctx, requestingAccount.ID, fave.AccountID, true) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking blocks: %s", err)) } @@ -46,7 +65,7 @@ func (p *processor) FavedBy(requestingAccount *gtsmodel.Account, targetStatusID // now we can return the masto representation of those accounts mastoAccounts := []*apimodel.Account{} for _, acc := range filteredAccounts { - mastoAccount, err := p.tc.AccountToMastoPublic(acc) + mastoAccount, err := p.tc.AccountToMastoPublic(ctx, acc) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } diff --git a/internal/processing/status/get.go b/internal/processing/status/get.go index 9d403b901..258210faf 100644 --- a/internal/processing/status/get.go +++ b/internal/processing/status/get.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -9,8 +28,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Get(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Get(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -18,7 +37,7 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetStatusID stri return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -26,7 +45,7 @@ func (p *processor) Get(requestingAccount *gtsmodel.Account, targetStatusID stri return nil, gtserror.NewErrorNotFound(errors.New("status is not visible")) } - mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } diff --git a/internal/processing/status/status.go b/internal/processing/status/status.go index 038ca005e..37790d062 100644 --- a/internal/processing/status/status.go +++ b/internal/processing/status/status.go @@ -1,6 +1,26 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" + "github.com/sirupsen/logrus" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/config" @@ -15,38 +35,38 @@ import ( // Processor wraps a bunch of functions for processing statuses. type Processor interface { // Create processes the given form to create a new status, returning the api model representation of that status if it's OK. - Create(account *gtsmodel.Account, application *gtsmodel.Application, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, gtserror.WithCode) + Create(ctx context.Context, account *gtsmodel.Account, application *gtsmodel.Application, form *apimodel.AdvancedStatusCreateForm) (*apimodel.Status, gtserror.WithCode) // Delete processes the delete of a given status, returning the deleted status if the delete goes through. - Delete(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + Delete(ctx context.Context, account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // Fave processes the faving of a given status, returning the updated status if the fave goes through. - Fave(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + Fave(ctx context.Context, account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // Boost processes the boost/reblog of a given status, returning the newly-created boost if all is well. - Boost(account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + Boost(ctx context.Context, account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // Unboost processes the unboost/unreblog of a given status, returning the status if all is well. - Unboost(account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + Unboost(ctx context.Context, account *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // BoostedBy returns a slice of accounts that have boosted the given status, filtered according to privacy settings. - BoostedBy(account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) + BoostedBy(ctx context.Context, account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) // FavedBy returns a slice of accounts that have liked the given status, filtered according to privacy settings. - FavedBy(account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) + FavedBy(ctx context.Context, account *gtsmodel.Account, targetStatusID string) ([]*apimodel.Account, gtserror.WithCode) // Get gets the given status, taking account of privacy settings and blocks etc. - Get(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + Get(ctx context.Context, account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // Unfave processes the unfaving of a given status, returning the updated status if the fave goes through. - Unfave(account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) + Unfave(ctx context.Context, account *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) // Context returns the context (previous and following posts) from the given status ID - Context(account *gtsmodel.Account, targetStatusID string) (*apimodel.Context, gtserror.WithCode) + Context(ctx context.Context, account *gtsmodel.Account, targetStatusID string) (*apimodel.Context, gtserror.WithCode) /* PROCESSING UTILS */ - ProcessVisibility(form *apimodel.AdvancedStatusCreateForm, accountDefaultVis gtsmodel.Visibility, status *gtsmodel.Status) error - ProcessReplyToID(form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error - ProcessMediaIDs(form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error - ProcessLanguage(form *apimodel.AdvancedStatusCreateForm, accountDefaultLanguage string, status *gtsmodel.Status) error - ProcessMentions(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error - ProcessTags(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error - ProcessEmojis(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error - ProcessContent(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error + ProcessVisibility(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountDefaultVis gtsmodel.Visibility, status *gtsmodel.Status) error + ProcessReplyToID(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error + ProcessMediaIDs(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error + ProcessLanguage(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountDefaultLanguage string, status *gtsmodel.Status) error + ProcessMentions(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error + ProcessTags(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error + ProcessEmojis(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error + ProcessContent(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error } type processor struct { diff --git a/internal/processing/status/unboost.go b/internal/processing/status/unboost.go index 254cfe11f..c3c667a71 100644 --- a/internal/processing/status/unboost.go +++ b/internal/processing/status/unboost.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -10,8 +29,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Unboost(ctx context.Context, requestingAccount *gtsmodel.Account, application *gtsmodel.Application, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -19,7 +38,7 @@ func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gt return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -41,7 +60,7 @@ func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gt Value: requestingAccount.ID, }, } - err = p.db.GetWhere(where, gtsBoost) + err = p.db.GetWhere(ctx, where, gtsBoost) if err == nil { // we have a boost toUnboost = true @@ -58,7 +77,7 @@ func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gt if toUnboost { // we had a boost, so take some action to get rid of it - if err := p.db.DeleteWhere(where, >smodel.Status{}); err != nil { + if err := p.db.DeleteWhere(ctx, where, >smodel.Status{}); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error unboosting status: %s", err)) } @@ -79,7 +98,7 @@ func (p *processor) Unboost(requestingAccount *gtsmodel.Account, application *gt } } - mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } diff --git a/internal/processing/status/unfave.go b/internal/processing/status/unfave.go index d6e5320db..3d079e2ff 100644 --- a/internal/processing/status/unfave.go +++ b/internal/processing/status/unfave.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -10,8 +29,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { - targetStatus, err := p.db.GetStatusByID(targetStatusID) +func (p *processor) Unfave(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { + targetStatus, err := p.db.GetStatusByID(ctx, targetStatusID) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err)) } @@ -19,7 +38,7 @@ func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID s return nil, gtserror.NewErrorNotFound(fmt.Errorf("no status owner for status %s", targetStatusID)) } - visible, err := p.filter.StatusVisible(targetStatus, requestingAccount) + visible, err := p.filter.StatusVisible(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err)) } @@ -31,7 +50,7 @@ func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID s var toUnfave bool gtsFave := >smodel.StatusFave{} - err = p.db.GetWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave) + err = p.db.GetWhere(ctx, []db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave) if err == nil { // we have a fave toUnfave = true @@ -47,7 +66,7 @@ func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID s if toUnfave { // we had a fave, so take some action to get rid of it - if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave); err != nil { + if err := p.db.DeleteWhere(ctx, []db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: requestingAccount.ID}}, gtsFave); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error unfaveing status: %s", err)) } @@ -61,7 +80,7 @@ func (p *processor) Unfave(requestingAccount *gtsmodel.Account, targetStatusID s } } - mastoStatus, err := p.tc.StatusToMasto(targetStatus, requestingAccount) + mastoStatus, err := p.tc.StatusToMasto(ctx, targetStatus, requestingAccount) if err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err)) } diff --git a/internal/processing/status/util.go b/internal/processing/status/util.go index 025607f4a..26ee5d4f7 100644 --- a/internal/processing/status/util.go +++ b/internal/processing/status/util.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status import ( + "context" "errors" "fmt" @@ -12,7 +31,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -func (p *processor) ProcessVisibility(form *apimodel.AdvancedStatusCreateForm, accountDefaultVis gtsmodel.Visibility, status *gtsmodel.Status) error { +func (p *processor) ProcessVisibility(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountDefaultVis gtsmodel.Visibility, status *gtsmodel.Status) error { // by default all flags are set to true gtsAdvancedVis := >smodel.VisibilityAdvanced{ Federated: true, @@ -83,7 +102,7 @@ func (p *processor) ProcessVisibility(form *apimodel.AdvancedStatusCreateForm, a return nil } -func (p *processor) ProcessReplyToID(form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error { +func (p *processor) ProcessReplyToID(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error { if form.InReplyToID == "" { return nil } @@ -98,7 +117,7 @@ func (p *processor) ProcessReplyToID(form *apimodel.AdvancedStatusCreateForm, th repliedStatus := >smodel.Status{} repliedAccount := >smodel.Account{} // check replied status exists + is replyable - if err := p.db.GetByID(form.InReplyToID, repliedStatus); err != nil { + if err := p.db.GetByID(ctx, form.InReplyToID, repliedStatus); err != nil { if err == db.ErrNoEntries { return fmt.Errorf("status with id %s not replyable because it doesn't exist", form.InReplyToID) } @@ -112,14 +131,14 @@ func (p *processor) ProcessReplyToID(form *apimodel.AdvancedStatusCreateForm, th } // check replied account is known to us - if err := p.db.GetByID(repliedStatus.AccountID, repliedAccount); err != nil { + if err := p.db.GetByID(ctx, repliedStatus.AccountID, repliedAccount); err != nil { if err == db.ErrNoEntries { return fmt.Errorf("status with id %s not replyable because account id %s is not known", form.InReplyToID, repliedStatus.AccountID) } return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err) } // check if a block exists - if blocked, err := p.db.IsBlocked(thisAccountID, repliedAccount.ID, true); err != nil { + if blocked, err := p.db.IsBlocked(ctx, thisAccountID, repliedAccount.ID, true); err != nil { if err != db.ErrNoEntries { return fmt.Errorf("status with id %s not replyable: %s", form.InReplyToID, err) } @@ -132,7 +151,7 @@ func (p *processor) ProcessReplyToID(form *apimodel.AdvancedStatusCreateForm, th return nil } -func (p *processor) ProcessMediaIDs(form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error { +func (p *processor) ProcessMediaIDs(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, thisAccountID string, status *gtsmodel.Status) error { if form.MediaIDs == nil { return nil } @@ -142,7 +161,7 @@ func (p *processor) ProcessMediaIDs(form *apimodel.AdvancedStatusCreateForm, thi for _, mediaID := range form.MediaIDs { // check these attachments exist a := >smodel.MediaAttachment{} - if err := p.db.GetByID(mediaID, a); err != nil { + if err := p.db.GetByID(ctx, mediaID, a); err != nil { return fmt.Errorf("invalid media type or media not found for media id %s", mediaID) } // check they belong to the requesting account id @@ -161,7 +180,7 @@ func (p *processor) ProcessMediaIDs(form *apimodel.AdvancedStatusCreateForm, thi return nil } -func (p *processor) ProcessLanguage(form *apimodel.AdvancedStatusCreateForm, accountDefaultLanguage string, status *gtsmodel.Status) error { +func (p *processor) ProcessLanguage(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountDefaultLanguage string, status *gtsmodel.Status) error { if form.Language != "" { status.Language = form.Language } else { @@ -173,9 +192,9 @@ func (p *processor) ProcessLanguage(form *apimodel.AdvancedStatusCreateForm, acc return nil } -func (p *processor) ProcessMentions(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { +func (p *processor) ProcessMentions(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { menchies := []string{} - gtsMenchies, err := p.db.MentionStringsToMentions(util.DeriveMentionsFromStatus(form.Status), accountID, status.ID) + gtsMenchies, err := p.db.MentionStringsToMentions(ctx, util.DeriveMentionsFromStatus(form.Status), accountID, status.ID) if err != nil { return fmt.Errorf("error generating mentions from status: %s", err) } @@ -186,7 +205,7 @@ func (p *processor) ProcessMentions(form *apimodel.AdvancedStatusCreateForm, acc } menchie.ID = menchieID - if err := p.db.Put(menchie); err != nil { + if err := p.db.Put(ctx, menchie); err != nil { return fmt.Errorf("error putting mentions in db: %s", err) } menchies = append(menchies, menchie.ID) @@ -198,14 +217,14 @@ func (p *processor) ProcessMentions(form *apimodel.AdvancedStatusCreateForm, acc return nil } -func (p *processor) ProcessTags(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { +func (p *processor) ProcessTags(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { tags := []string{} - gtsTags, err := p.db.TagStringsToTags(util.DeriveHashtagsFromStatus(form.Status), accountID, status.ID) + gtsTags, err := p.db.TagStringsToTags(ctx, util.DeriveHashtagsFromStatus(form.Status), accountID, status.ID) if err != nil { return fmt.Errorf("error generating hashtags from status: %s", err) } for _, tag := range gtsTags { - if err := p.db.Upsert(tag, "name"); err != nil { + if err := p.db.Put(ctx, tag); err != nil && err != db.ErrAlreadyExists { return fmt.Errorf("error putting tags in db: %s", err) } tags = append(tags, tag.ID) @@ -217,9 +236,9 @@ func (p *processor) ProcessTags(form *apimodel.AdvancedStatusCreateForm, account return nil } -func (p *processor) ProcessEmojis(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { +func (p *processor) ProcessEmojis(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { emojis := []string{} - gtsEmojis, err := p.db.EmojiStringsToEmojis(util.DeriveEmojisFromStatus(form.Status), accountID, status.ID) + gtsEmojis, err := p.db.EmojiStringsToEmojis(ctx, util.DeriveEmojisFromStatus(form.Status), accountID, status.ID) if err != nil { return fmt.Errorf("error generating emojis from status: %s", err) } @@ -233,7 +252,7 @@ func (p *processor) ProcessEmojis(form *apimodel.AdvancedStatusCreateForm, accou return nil } -func (p *processor) ProcessContent(form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { +func (p *processor) ProcessContent(ctx context.Context, form *apimodel.AdvancedStatusCreateForm, accountID string, status *gtsmodel.Status) error { // if there's nothing in the status at all we can just return early if form.Status == "" { status.Content = "" @@ -252,9 +271,9 @@ func (p *processor) ProcessContent(form *apimodel.AdvancedStatusCreateForm, acco var formatted string switch form.Format { case apimodel.StatusFormatPlain: - formatted = p.formatter.FromPlain(content, status.Mentions, status.Tags) + formatted = p.formatter.FromPlain(ctx, content, status.Mentions, status.Tags) case apimodel.StatusFormatMarkdown: - formatted = p.formatter.FromMarkdown(content, status.Mentions, status.Tags) + formatted = p.formatter.FromMarkdown(ctx, content, status.Mentions, status.Tags) default: return fmt.Errorf("format %s not recognised as a valid status format", form.Format) } diff --git a/internal/processing/status/util_test.go b/internal/processing/status/util_test.go index 9c282eb52..1ec2076b1 100644 --- a/internal/processing/status/util_test.go +++ b/internal/processing/status/util_test.go @@ -1,6 +1,25 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + package status_test import ( + "context" "fmt" "testing" @@ -88,7 +107,7 @@ func (suite *UtilTestSuite) TestProcessMentions1() { ID: "01FCTDD78JJMX3K9KPXQ7ZQ8BJ", } - err := suite.status.ProcessMentions(form, creatingAccount.ID, status) + err := suite.status.ProcessMentions(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Len(suite.T(), status.Mentions, 1) @@ -138,11 +157,11 @@ func (suite *UtilTestSuite) TestProcessContentFull1() { ID: "01FCTDD78JJMX3K9KPXQ7ZQ8BJ", } - err := suite.status.ProcessMentions(form, creatingAccount.ID, status) + err := suite.status.ProcessMentions(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Empty(suite.T(), status.Content) // shouldn't be set yet - err = suite.status.ProcessTags(form, creatingAccount.ID, status) + err = suite.status.ProcessTags(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Empty(suite.T(), status.Content) // shouldn't be set yet @@ -150,7 +169,7 @@ func (suite *UtilTestSuite) TestProcessContentFull1() { ACTUAL TEST */ - err = suite.status.ProcessContent(form, creatingAccount.ID, status) + err = suite.status.ProcessContent(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Equal(suite.T(), statusText1ExpectedFull, status.Content) } @@ -187,7 +206,7 @@ func (suite *UtilTestSuite) TestProcessContentPartial1() { ID: "01FCTDD78JJMX3K9KPXQ7ZQ8BJ", } - err := suite.status.ProcessMentions(form, creatingAccount.ID, status) + err := suite.status.ProcessMentions(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Empty(suite.T(), status.Content) // shouldn't be set yet @@ -195,7 +214,7 @@ func (suite *UtilTestSuite) TestProcessContentPartial1() { ACTUAL TEST */ - err = suite.status.ProcessContent(form, creatingAccount.ID, status) + err = suite.status.ProcessContent(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Equal(suite.T(), statusText1ExpectedPartial, status.Content) } @@ -229,7 +248,7 @@ func (suite *UtilTestSuite) TestProcessMentions2() { ID: "01FCTDD78JJMX3K9KPXQ7ZQ8BJ", } - err := suite.status.ProcessMentions(form, creatingAccount.ID, status) + err := suite.status.ProcessMentions(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Len(suite.T(), status.Mentions, 1) @@ -279,11 +298,11 @@ func (suite *UtilTestSuite) TestProcessContentFull2() { ID: "01FCTDD78JJMX3K9KPXQ7ZQ8BJ", } - err := suite.status.ProcessMentions(form, creatingAccount.ID, status) + err := suite.status.ProcessMentions(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Empty(suite.T(), status.Content) // shouldn't be set yet - err = suite.status.ProcessTags(form, creatingAccount.ID, status) + err = suite.status.ProcessTags(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Empty(suite.T(), status.Content) // shouldn't be set yet @@ -291,7 +310,7 @@ func (suite *UtilTestSuite) TestProcessContentFull2() { ACTUAL TEST */ - err = suite.status.ProcessContent(form, creatingAccount.ID, status) + err = suite.status.ProcessContent(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Equal(suite.T(), status2TextExpectedFull, status.Content) @@ -329,7 +348,7 @@ func (suite *UtilTestSuite) TestProcessContentPartial2() { ID: "01FCTDD78JJMX3K9KPXQ7ZQ8BJ", } - err := suite.status.ProcessMentions(form, creatingAccount.ID, status) + err := suite.status.ProcessMentions(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) assert.Empty(suite.T(), status.Content) // shouldn't be set yet @@ -337,7 +356,7 @@ func (suite *UtilTestSuite) TestProcessContentPartial2() { ACTUAL TEST */ - err = suite.status.ProcessContent(form, creatingAccount.ID, status) + err = suite.status.ProcessContent(context.Background(), form, creatingAccount.ID, status) assert.NoError(suite.T(), err) fmt.Println(status.Content) diff --git a/internal/processing/streaming.go b/internal/processing/streaming.go index 457db0576..e1c134d00 100644 --- a/internal/processing/streaming.go +++ b/internal/processing/streaming.go @@ -19,14 +19,16 @@ package processing import ( + "context" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) AuthorizeStreamingRequest(accessToken string) (*gtsmodel.Account, error) { - return p.streamingProcessor.AuthorizeStreamingRequest(accessToken) +func (p *processor) AuthorizeStreamingRequest(ctx context.Context, accessToken string) (*gtsmodel.Account, error) { + return p.streamingProcessor.AuthorizeStreamingRequest(ctx, accessToken) } -func (p *processor) OpenStreamForAccount(account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) { - return p.streamingProcessor.OpenStreamForAccount(account, streamType) +func (p *processor) OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) { + return p.streamingProcessor.OpenStreamForAccount(ctx, account, streamType) } diff --git a/internal/processing/streaming/authorize.go b/internal/processing/streaming/authorize.go index 8bbf1856d..f938a0c0c 100644 --- a/internal/processing/streaming/authorize.go +++ b/internal/processing/streaming/authorize.go @@ -7,7 +7,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" ) -func (p *processor) AuthorizeStreamingRequest(accessToken string) (*gtsmodel.Account, error) { +func (p *processor) AuthorizeStreamingRequest(ctx context.Context, accessToken string) (*gtsmodel.Account, error) { ti, err := p.oauthServer.LoadAccessToken(context.Background(), accessToken) if err != nil { return nil, fmt.Errorf("AuthorizeStreamingRequest: error loading access token: %s", err) @@ -20,12 +20,12 @@ func (p *processor) AuthorizeStreamingRequest(accessToken string) (*gtsmodel.Acc // fetch user's and account for this user id user := >smodel.User{} - if err := p.db.GetByID(uid, user); err != nil || user == nil { + if err := p.db.GetByID(ctx, uid, user); err != nil || user == nil { return nil, fmt.Errorf("AuthorizeStreamingRequest: no user found for validated uid %s", uid) } - acct := >smodel.Account{} - if err := p.db.GetByID(user.AccountID, acct); err != nil || acct == nil { + acct, err := p.db.GetAccountByID(ctx, user.AccountID) + if err != nil || acct == nil { return nil, fmt.Errorf("AuthorizeStreamingRequest: no account retrieved for user with id %s", uid) } diff --git a/internal/processing/streaming/openstream.go b/internal/processing/streaming/openstream.go index 68446bac6..dfad5398e 100644 --- a/internal/processing/streaming/openstream.go +++ b/internal/processing/streaming/openstream.go @@ -1,6 +1,7 @@ package streaming import ( + "context" "errors" "fmt" @@ -10,7 +11,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/id" ) -func (p *processor) OpenStreamForAccount(account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) { +func (p *processor) OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) { l := p.log.WithFields(logrus.Fields{ "func": "OpenStreamForAccount", "account": account.ID, diff --git a/internal/processing/streaming/streaming.go b/internal/processing/streaming/streaming.go index de75b8f27..f349a655a 100644 --- a/internal/processing/streaming/streaming.go +++ b/internal/processing/streaming/streaming.go @@ -1,6 +1,7 @@ package streaming import ( + "context" "sync" "github.com/sirupsen/logrus" @@ -17,9 +18,9 @@ import ( // Processor wraps a bunch of functions for processing streaming. type Processor interface { // AuthorizeStreamingRequest returns an oauth2 token info in response to an access token query from the streaming API - AuthorizeStreamingRequest(accessToken string) (*gtsmodel.Account, error) + AuthorizeStreamingRequest(ctx context.Context, accessToken string) (*gtsmodel.Account, error) // OpenStreamForAccount returns a new Stream for the given account, which will contain a channel for passing messages back to the caller. - OpenStreamForAccount(account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) + OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamType string) (*gtsmodel.Stream, gtserror.WithCode) // StreamStatusToAccount streams the given status to any open, appropriate streams belonging to the given account. StreamStatusToAccount(s *apimodel.Status, account *gtsmodel.Account) error // StreamNotificationToAccount streams the given notification to any open, appropriate streams belonging to the given account. diff --git a/internal/processing/timeline.go b/internal/processing/timeline.go index afddd3e6c..6a409a6cc 100644 --- a/internal/processing/timeline.go +++ b/internal/processing/timeline.go @@ -19,6 +19,7 @@ package processing import ( + "context" "fmt" "net/url" @@ -58,8 +59,8 @@ func (p *processor) packageStatusResponse(statuses []*apimodel.Status, path stri return resp, nil } -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) +func (p *processor) HomeTimelineGet(ctx context.Context, authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode) { + statuses, err := p.timelineManager.HomeTimeline(ctx, authed.Account.ID, maxID, sinceID, minID, limit, local) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -73,8 +74,8 @@ func (p *processor) HomeTimelineGet(authed *oauth.Auth, maxID string, sinceID st 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.GetPublicTimeline(authed.Account.ID, maxID, sinceID, minID, limit, local) +func (p *processor) PublicTimelineGet(ctx context.Context, authed *oauth.Auth, maxID string, sinceID string, minID string, limit int, local bool) (*apimodel.StatusTimelineResponse, gtserror.WithCode) { + statuses, err := p.db.GetPublicTimeline(ctx, authed.Account.ID, maxID, sinceID, minID, limit, local) if err != nil { if err == db.ErrNoEntries { // there are just no entries left @@ -86,16 +87,22 @@ func (p *processor) PublicTimelineGet(authed *oauth.Auth, maxID string, sinceID return nil, gtserror.NewErrorInternalError(err) } - s, err := p.filterPublicStatuses(authed, statuses) + s, err := p.filterPublicStatuses(ctx, authed, statuses) if err != nil { return nil, gtserror.NewErrorInternalError(err) } + if len(s) == 0 { + return &apimodel.StatusTimelineResponse{ + Statuses: []*apimodel.Status{}, + }, nil + } + 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.GetFavedTimeline(authed.Account.ID, maxID, minID, limit) +func (p *processor) FavedTimelineGet(ctx context.Context, authed *oauth.Auth, maxID string, minID string, limit int) (*apimodel.StatusTimelineResponse, gtserror.WithCode) { + statuses, nextMaxID, prevMinID, err := p.db.GetFavedTimeline(ctx, authed.Account.ID, maxID, minID, limit) if err != nil { if err == db.ErrNoEntries { // there are just no entries left @@ -107,21 +114,27 @@ func (p *processor) FavedTimelineGet(authed *oauth.Auth, maxID string, minID str return nil, gtserror.NewErrorInternalError(err) } - s, err := p.filterFavedStatuses(authed, statuses) + s, err := p.filterFavedStatuses(ctx, authed, statuses) if err != nil { return nil, gtserror.NewErrorInternalError(err) } + if len(s) == 0 { + return &apimodel.StatusTimelineResponse{ + Statuses: []*apimodel.Status{}, + }, nil + } + return p.packageStatusResponse(s, "api/v1/favourites", nextMaxID, prevMinID, limit) } -func (p *processor) filterPublicStatuses(authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) { +func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) { l := p.log.WithField("func", "filterPublicStatuses") apiStatuses := []*apimodel.Status{} for _, s := range statuses { targetAccount := >smodel.Account{} - if err := p.db.GetByID(s.AccountID, targetAccount); err != nil { + if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil { if err == db.ErrNoEntries { l.Debugf("filterPublicStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID) continue @@ -129,7 +142,7 @@ func (p *processor) filterPublicStatuses(authed *oauth.Auth, statuses []*gtsmode return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err)) } - timelineable, err := p.filter.StatusPublictimelineable(s, authed.Account) + timelineable, err := p.filter.StatusPublictimelineable(ctx, s, authed.Account) if err != nil { l.Debugf("filterPublicStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err) continue @@ -138,7 +151,7 @@ func (p *processor) filterPublicStatuses(authed *oauth.Auth, statuses []*gtsmode continue } - apiStatus, err := p.tc.StatusToMasto(s, authed.Account) + apiStatus, err := p.tc.StatusToMasto(ctx, 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 @@ -150,13 +163,13 @@ func (p *processor) filterPublicStatuses(authed *oauth.Auth, statuses []*gtsmode return apiStatuses, nil } -func (p *processor) filterFavedStatuses(authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) { +func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth, statuses []*gtsmodel.Status) ([]*apimodel.Status, error) { l := p.log.WithField("func", "filterFavedStatuses") apiStatuses := []*apimodel.Status{} for _, s := range statuses { targetAccount := >smodel.Account{} - if err := p.db.GetByID(s.AccountID, targetAccount); err != nil { + if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil { if err == db.ErrNoEntries { l.Debugf("filterFavedStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID) continue @@ -164,7 +177,7 @@ func (p *processor) filterFavedStatuses(authed *oauth.Auth, statuses []*gtsmodel return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err)) } - timelineable, err := p.filter.StatusVisible(s, authed.Account) + timelineable, err := p.filter.StatusVisible(ctx, s, authed.Account) if err != nil { l.Debugf("filterFavedStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err) continue @@ -173,7 +186,7 @@ func (p *processor) filterFavedStatuses(authed *oauth.Auth, statuses []*gtsmodel continue } - apiStatus, err := p.tc.StatusToMasto(s, authed.Account) + apiStatus, err := p.tc.StatusToMasto(ctx, s, authed.Account) if err != nil { l.Debugf("filterFavedStatuses: skipping status %s because it couldn't be converted to its mastodon representation: %s", s.ID, err) continue |