mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-18 17:17:29 -06:00
unfollows from gts => remote now working
This commit is contained in:
parent
6c7b7659f8
commit
3623205fd7
21 changed files with 368 additions and 47 deletions
|
|
@ -17,12 +17,12 @@
|
||||||
* [x] /api/v1/accounts/:id GET (Get account information)
|
* [x] /api/v1/accounts/:id GET (Get account information)
|
||||||
* [x] /api/v1/accounts/:id/statuses GET (Get an account's statuses)
|
* [x] /api/v1/accounts/:id/statuses GET (Get an account's statuses)
|
||||||
* [x] /api/v1/accounts/:id/followers GET (Get an account's followers)
|
* [x] /api/v1/accounts/:id/followers GET (Get an account's followers)
|
||||||
* [ ] /api/v1/accounts/:id/following GET (Get an account's following)
|
* [x] /api/v1/accounts/:id/following GET (Get an account's following)
|
||||||
* [ ] /api/v1/accounts/:id/featured_tags GET (Get an account's featured tags)
|
* [ ] /api/v1/accounts/:id/featured_tags GET (Get an account's featured tags)
|
||||||
* [ ] /api/v1/accounts/:id/lists GET (Get lists containing this account)
|
* [ ] /api/v1/accounts/:id/lists GET (Get lists containing this account)
|
||||||
* [ ] /api/v1/accounts/:id/identity_proofs GET (Get identity proofs for this account)
|
* [ ] /api/v1/accounts/:id/identity_proofs GET (Get identity proofs for this account)
|
||||||
* [ ] /api/v1/accounts/:id/follow POST (Follow this account)
|
* [x] /api/v1/accounts/:id/follow POST (Follow this account)
|
||||||
* [ ] /api/v1/accounts/:id/unfollow POST (Unfollow this account)
|
* [x] /api/v1/accounts/:id/unfollow POST (Unfollow this account)
|
||||||
* [ ] /api/v1/accounts/:id/block POST (Block this account)
|
* [ ] /api/v1/accounts/:id/block POST (Block this account)
|
||||||
* [ ] /api/v1/accounts/:id/unblock POST (Unblock this account)
|
* [ ] /api/v1/accounts/:id/unblock POST (Unblock this account)
|
||||||
* [ ] /api/v1/accounts/:id/mute POST (Mute this account)
|
* [ ] /api/v1/accounts/:id/mute POST (Mute this account)
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,14 @@ const (
|
||||||
GetStatusesPath = BasePathWithID + "/statuses"
|
GetStatusesPath = BasePathWithID + "/statuses"
|
||||||
// GetFollowersPath is for showing an account's followers
|
// GetFollowersPath is for showing an account's followers
|
||||||
GetFollowersPath = BasePathWithID + "/followers"
|
GetFollowersPath = BasePathWithID + "/followers"
|
||||||
|
// GetFollowingPath is for showing account's that an account follows.
|
||||||
|
GetFollowingPath = BasePathWithID + "/following"
|
||||||
// GetRelationshipsPath is for showing an account's relationship with other accounts
|
// GetRelationshipsPath is for showing an account's relationship with other accounts
|
||||||
GetRelationshipsPath = BasePath + "/relationships"
|
GetRelationshipsPath = BasePath + "/relationships"
|
||||||
// FollowPath is for POSTing new follows to, and updating existing follows
|
// FollowPath is for POSTing new follows to, and updating existing follows
|
||||||
PostFollowPath = BasePathWithID + "/follow"
|
PostFollowPath = BasePathWithID + "/follow"
|
||||||
|
// PostUnfollowPath is for POSTing an unfollow
|
||||||
|
PostUnfollowPath = BasePathWithID + "/unfollow"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Module implements the ClientAPIModule interface for account-related actions
|
// Module implements the ClientAPIModule interface for account-related actions
|
||||||
|
|
@ -86,8 +90,10 @@ func (m *Module) Route(r router.Router) error {
|
||||||
r.AttachHandler(http.MethodPatch, BasePathWithID, m.muxHandler)
|
r.AttachHandler(http.MethodPatch, BasePathWithID, m.muxHandler)
|
||||||
r.AttachHandler(http.MethodGet, GetStatusesPath, m.AccountStatusesGETHandler)
|
r.AttachHandler(http.MethodGet, GetStatusesPath, m.AccountStatusesGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, GetFollowersPath, m.AccountFollowersGETHandler)
|
r.AttachHandler(http.MethodGet, GetFollowersPath, m.AccountFollowersGETHandler)
|
||||||
|
r.AttachHandler(http.MethodGet, GetFollowingPath, m.AccountFollowingGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, GetRelationshipsPath, m.AccountRelationshipsGETHandler)
|
r.AttachHandler(http.MethodGet, GetRelationshipsPath, m.AccountRelationshipsGETHandler)
|
||||||
r.AttachHandler(http.MethodPost, PostFollowPath, m.AccountFollowPOSTHandler)
|
r.AttachHandler(http.MethodPost, PostFollowPath, m.AccountFollowPOSTHandler)
|
||||||
|
r.AttachHandler(http.MethodPost, PostUnfollowPath, m.AccountUnfollowPOSTHandler)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
49
internal/api/client/account/following.go
Normal file
49
internal/api/client/account/following.go
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
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 account
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountFollowersGETHandler serves the followers of the requested account, if they're visible to the requester.
|
||||||
|
func (m *Module) AccountFollowingGETHandler(c *gin.Context) {
|
||||||
|
authed, err := oauth.Authed(c, true, true, true, true)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targetAcctID := c.Param(IDKey)
|
||||||
|
if targetAcctID == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
following, errWithCode := m.processor.AccountFollowingGet(authed, targetAcctID)
|
||||||
|
if errWithCode != nil {
|
||||||
|
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, following)
|
||||||
|
}
|
||||||
53
internal/api/client/account/unfollow.go
Normal file
53
internal/api/client/account/unfollow.go
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
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 account
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountUnfollowPOSTHandler is the endpoint for removing a follow and/or follow request to the target account
|
||||||
|
func (m *Module) AccountUnfollowPOSTHandler(c *gin.Context) {
|
||||||
|
l := m.log.WithField("func", "AccountUnfollowPOSTHandler")
|
||||||
|
authed, err := oauth.Authed(c, true, true, true, true)
|
||||||
|
if err != nil {
|
||||||
|
l.Debug(err)
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targetAcctID := c.Param(IDKey)
|
||||||
|
if targetAcctID == "" {
|
||||||
|
l.Debug(err)
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
relationship, errWithCode := m.processor.AccountFollowRemove(authed, targetAcctID)
|
||||||
|
if errWithCode != nil {
|
||||||
|
l.Debug(errWithCode.Error())
|
||||||
|
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, relationship)
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/api/model"
|
"github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -60,7 +61,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
|
||||||
app := >smodel.Application{
|
app := >smodel.Application{
|
||||||
ClientID: clientID,
|
ClientID: clientID,
|
||||||
}
|
}
|
||||||
if err := m.db.GetWhere("client_id", app.ClientID, app); err != nil {
|
if err := m.db.GetWhere([]db.Where{{Key: "client_id", Value: app.ClientID}}, app); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("no application found for client id %s", clientID)})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("no application found for client id %s", clientID)})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||||
)
|
)
|
||||||
|
|
@ -68,7 +69,7 @@ func (m *Module) OauthTokenMiddleware(c *gin.Context) {
|
||||||
if cid := ti.GetClientID(); cid != "" {
|
if cid := ti.GetClientID(); cid != "" {
|
||||||
l.Tracef("authenticated client %s with bearer token, scope is %s", cid, ti.GetScope())
|
l.Tracef("authenticated client %s with bearer token, scope is %s", cid, ti.GetScope())
|
||||||
app := >smodel.Application{}
|
app := >smodel.Application{}
|
||||||
if err := m.db.GetWhere("client_id", cid, app); err != nil {
|
if err := m.db.GetWhere([]db.Where{{Key: "client_id",Value: cid}}, app); err != nil {
|
||||||
l.Tracef("no app found for client %s", cid)
|
l.Tracef("no app found for client %s", cid)
|
||||||
}
|
}
|
||||||
c.Set(oauth.SessionAuthorizedApplication, app)
|
c.Set(oauth.SessionAuthorizedApplication, app)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
|
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
@ -87,7 +88,7 @@ func (m *Module) ValidatePassword(email string, password string) (userid string,
|
||||||
// first we select the user from the database based on email address, bail if no user found for that email
|
// first we select the user from the database based on email address, bail if no user found for that email
|
||||||
gtsUser := >smodel.User{}
|
gtsUser := >smodel.User{}
|
||||||
|
|
||||||
if err := m.db.GetWhere("email", email, gtsUser); err != nil {
|
if err := m.db.GetWhere([]db.Where{{Key: "email", Value: email}}, gtsUser); err != nil {
|
||||||
l.Debugf("user %s was not retrievable from db during oauth authorization attempt: %s", email, err)
|
l.Debugf("user %s was not retrievable from db during oauth authorization attempt: %s", email, err)
|
||||||
return incorrectPassword()
|
return incorrectPassword()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
|
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/api/model"
|
"github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||||
|
|
@ -118,7 +119,7 @@ func (suite *StatusCreateTestSuite) TestPostNewStatus() {
|
||||||
}, statusReply.Tags[0])
|
}, statusReply.Tags[0])
|
||||||
|
|
||||||
gtsTag := >smodel.Tag{}
|
gtsTag := >smodel.Tag{}
|
||||||
err = suite.db.GetWhere("name", "helloworld", gtsTag)
|
err = suite.db.GetWhere([]db.Where{{Key: "name", Value: "helloworld"}}, gtsTag)
|
||||||
assert.NoError(suite.T(), err)
|
assert.NoError(suite.T(), err)
|
||||||
assert.Equal(suite.T(), statusReply.Account.ID, gtsTag.FirstSeenFromAccountID)
|
assert.Equal(suite.T(), statusReply.Account.ID, gtsTag.FirstSeenFromAccountID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,10 @@ func (e ErrAlreadyExists) Error() string {
|
||||||
return "already exists"
|
return "already exists"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Where struct {
|
||||||
|
Key string
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// DB provides methods for interacting with an underlying database or other storage mechanism (for now, just postgres).
|
// DB provides methods for interacting with an underlying database or other storage mechanism (for now, just postgres).
|
||||||
// Note that in all of the functions below, the passed interface should be a pointer or a slice, which will then be populated
|
// Note that in all of the functions below, the passed interface should be a pointer or a slice, which will then be populated
|
||||||
|
|
@ -80,7 +84,7 @@ type DB interface {
|
||||||
// name of the key to select from.
|
// name of the key to select from.
|
||||||
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
|
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
|
||||||
// In case of no entries, a 'no entries' error will be returned
|
// In case of no entries, a 'no entries' error will be returned
|
||||||
GetWhere(key string, value interface{}, i interface{}) error
|
GetWhere(where []Where, i interface{}) error
|
||||||
|
|
||||||
// // GetWhereMany gets one entry where key = value for *ALL* parameters passed as "where".
|
// // GetWhereMany gets one entry where key = value for *ALL* parameters passed as "where".
|
||||||
// // That is, if you pass 2 'where' entries, with 1 being Key username and Value test, and the second
|
// // That is, if you pass 2 'where' entries, with 1 being Key username and Value test, and the second
|
||||||
|
|
@ -114,7 +118,7 @@ type DB interface {
|
||||||
|
|
||||||
// DeleteWhere deletes i where key = value
|
// DeleteWhere deletes i where key = value
|
||||||
// If i didn't exist anyway, then no error should be returned.
|
// If i didn't exist anyway, then no error should be returned.
|
||||||
DeleteWhere(key string, value interface{}, i interface{}) error
|
DeleteWhere(where []Where, i interface{}) error
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HANDY SHORTCUTS
|
HANDY SHORTCUTS
|
||||||
|
|
|
||||||
|
|
@ -216,8 +216,17 @@ func (ps *postgresService) GetByID(id string, i interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *postgresService) GetWhere(key string, value interface{}, i interface{}) error {
|
func (ps *postgresService) GetWhere(where []db.Where, i interface{}) error {
|
||||||
if err := ps.conn.Model(i).Where("? = ?", pg.Safe(key), value).Select(); err != nil {
|
if len(where) == 0 {
|
||||||
|
return errors.New("no queries provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
q := ps.conn.Model(i)
|
||||||
|
for _, w := range where {
|
||||||
|
q = q.Where("? = ?", pg.Safe(w.Key), w.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := q.Select(); err != nil {
|
||||||
if err == pg.ErrNoRows {
|
if err == pg.ErrNoRows {
|
||||||
return db.ErrNoEntries{}
|
return db.ErrNoEntries{}
|
||||||
}
|
}
|
||||||
|
|
@ -284,8 +293,18 @@ func (ps *postgresService) DeleteByID(id string, i interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *postgresService) DeleteWhere(key string, value interface{}, i interface{}) error {
|
func (ps *postgresService) DeleteWhere(where []db.Where, i interface{}) error {
|
||||||
if _, err := ps.conn.Model(i).Where("? = ?", pg.Safe(key), value).Delete(); err != nil {
|
if len(where) == 0 {
|
||||||
|
return errors.New("no queries provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
q := ps.conn.Model(i)
|
||||||
|
for _, w := range where {
|
||||||
|
q = q.Where("? = ?", pg.Safe(w.Key), w.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if _, err := q.Delete(); err != nil {
|
||||||
// if there are no rows *anyway* then that's fine
|
// if there are no rows *anyway* then that's fine
|
||||||
// just return err if there's an actual error
|
// just return err if there's an actual error
|
||||||
if err != pg.ErrNoRows {
|
if err != pg.ErrNoRows {
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ func (f *federatingDB) Owns(c context.Context, id *url.URL) (bool, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
|
return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
|
||||||
}
|
}
|
||||||
if err := f.db.GetWhere("uri", uid, >smodel.Status{}); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: uid}}, >smodel.Status{}); err != nil {
|
||||||
if _, ok := err.(db.ErrNoEntries); ok {
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
// there are no entries for this status
|
// there are no entries for this status
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
@ -260,7 +260,7 @@ func (f *federatingDB) ActorForOutbox(c context.Context, outboxIRI *url.URL) (ac
|
||||||
return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String())
|
return nil, fmt.Errorf("%s is not an outbox URI", outboxIRI.String())
|
||||||
}
|
}
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("outbox_uri", outboxIRI.String(), acct); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "outbox_uri", Value: outboxIRI.String()}}, acct); err != nil {
|
||||||
if _, ok := err.(db.ErrNoEntries); ok {
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
return nil, fmt.Errorf("no actor found that corresponds to outbox %s", outboxIRI.String())
|
return nil, fmt.Errorf("no actor found that corresponds to outbox %s", outboxIRI.String())
|
||||||
}
|
}
|
||||||
|
|
@ -285,7 +285,7 @@ func (f *federatingDB) ActorForInbox(c context.Context, inboxIRI *url.URL) (acto
|
||||||
return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
|
return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
|
||||||
}
|
}
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("inbox_uri", inboxIRI.String(), acct); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "inbox_uri", Value: inboxIRI.String()}}, acct); err != nil {
|
||||||
if _, ok := err.(db.ErrNoEntries); ok {
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
|
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
|
||||||
}
|
}
|
||||||
|
|
@ -311,7 +311,7 @@ func (f *federatingDB) OutboxForInbox(c context.Context, inboxIRI *url.URL) (out
|
||||||
return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
|
return nil, fmt.Errorf("%s is not an inbox URI", inboxIRI.String())
|
||||||
}
|
}
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("inbox_uri", inboxIRI.String(), acct); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "inbox_uri", Value: inboxIRI.String()}}, acct); err != nil {
|
||||||
if _, ok := err.(db.ErrNoEntries); ok {
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
|
return nil, fmt.Errorf("no actor found that corresponds to inbox %s", inboxIRI.String())
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +350,7 @@ func (f *federatingDB) Get(c context.Context, id *url.URL) (value vocab.Type, er
|
||||||
|
|
||||||
if util.IsUserPath(id) {
|
if util.IsUserPath(id) {
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("uri", id.String(), acct); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: id.String()}}, acct); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l.Debug("is user path! returning account")
|
l.Debug("is user path! returning account")
|
||||||
|
|
@ -651,7 +651,7 @@ func (f *federatingDB) NewID(c context.Context, t vocab.Type) (id *url.URL, err
|
||||||
// take the IRI of the first actor we can find (there should only be one)
|
// take the IRI of the first actor we can find (there should only be one)
|
||||||
if iter.IsIRI() {
|
if iter.IsIRI() {
|
||||||
actorAccount := >smodel.Account{}
|
actorAccount := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("uri", iter.GetIRI().String(), actorAccount); err == nil { // if there's an error here, just use the fallback behavior -- we don't need to return an error here
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: iter.GetIRI().String()}}, actorAccount); err == nil { // if there's an error here, just use the fallback behavior -- we don't need to return an error here
|
||||||
return url.Parse(util.GenerateURIForFollow(actorAccount.Username, f.config.Protocol, f.config.Host))
|
return url.Parse(util.GenerateURIForFollow(actorAccount.Username, f.config.Protocol, f.config.Host))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -679,7 +679,7 @@ func (f *federatingDB) Followers(c context.Context, actorIRI *url.URL) (follower
|
||||||
l.Debugf("entering FOLLOWERS function with actorIRI %s", actorIRI.String())
|
l.Debugf("entering FOLLOWERS function with actorIRI %s", actorIRI.String())
|
||||||
|
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("uri", actorIRI.String(), acct); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: actorIRI.String()}}, acct); err != nil {
|
||||||
return nil, fmt.Errorf("db error getting account with uri %s: %s", actorIRI.String(), err)
|
return nil, fmt.Errorf("db error getting account with uri %s: %s", actorIRI.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -721,7 +721,7 @@ func (f *federatingDB) Following(c context.Context, actorIRI *url.URL) (followin
|
||||||
l.Debugf("entering FOLLOWING function with actorIRI %s", actorIRI.String())
|
l.Debugf("entering FOLLOWING function with actorIRI %s", actorIRI.String())
|
||||||
|
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("uri", actorIRI.String(), acct); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: actorIRI.String()}}, acct); err != nil {
|
||||||
return nil, fmt.Errorf("db error getting account with uri %s: %s", actorIRI.String(), err)
|
return nil, fmt.Errorf("db error getting account with uri %s: %s", actorIRI.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -823,11 +823,11 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)
|
||||||
return errors.New("UNDO: follow object account and inbox account were not the same")
|
return errors.New("UNDO: follow object account and inbox account were not the same")
|
||||||
}
|
}
|
||||||
// delete any existing FOLLOW
|
// delete any existing FOLLOW
|
||||||
if err := f.db.DeleteWhere("uri", gtsFollow.URI, >smodel.Follow{}); err != nil {
|
if err := f.db.DeleteWhere([]db.Where{{Key: "uri", Value: gtsFollow.URI}}, >smodel.Follow{}); err != nil {
|
||||||
return fmt.Errorf("UNDO: db error removing follow: %s", err)
|
return fmt.Errorf("UNDO: db error removing follow: %s", err)
|
||||||
}
|
}
|
||||||
// delete any existing FOLLOW REQUEST
|
// delete any existing FOLLOW REQUEST
|
||||||
if err := f.db.DeleteWhere("uri", gtsFollow.URI, >smodel.FollowRequest{}); err != nil {
|
if err := f.db.DeleteWhere([]db.Where{{Key: "uri", Value: gtsFollow.URI}}, >smodel.FollowRequest{}); err != nil {
|
||||||
return fmt.Errorf("UNDO: db error removing follow request: %s", err)
|
return fmt.Errorf("UNDO: db error removing follow request: %s", err)
|
||||||
}
|
}
|
||||||
l.Debug("follow undone")
|
l.Debug("follow undone")
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr
|
||||||
}
|
}
|
||||||
|
|
||||||
requestingAccount := >smodel.Account{}
|
requestingAccount := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("uri", publicKeyOwnerURI.String(), requestingAccount); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: publicKeyOwnerURI.String()}}, requestingAccount); err != nil {
|
||||||
// there's been a proper error so return it
|
// there's been a proper error so return it
|
||||||
if _, ok := err.(db.ErrNoEntries); !ok {
|
if _, ok := err.(db.ErrNoEntries); !ok {
|
||||||
return ctx, false, fmt.Errorf("error getting requesting account with public key id %s: %s", publicKeyOwnerURI.String(), err)
|
return ctx, false, fmt.Errorf("error getting requesting account with public key id %s: %s", publicKeyOwnerURI.String(), err)
|
||||||
|
|
@ -200,7 +200,7 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er
|
||||||
|
|
||||||
for _, uri := range actorIRIs {
|
for _, uri := range actorIRIs {
|
||||||
a := >smodel.Account{}
|
a := >smodel.Account{}
|
||||||
if err := f.db.GetWhere("uri", uri.String(), a); err != nil {
|
if err := f.db.GetWhere([]db.Where{{Key: "uri", Value: uri.String()}}, a); err != nil {
|
||||||
_, ok := err.(db.ErrNoEntries)
|
_, ok := err.(db.ErrNoEntries)
|
||||||
if ok {
|
if ok {
|
||||||
// we don't have an entry for this account so it's not blocked
|
// we don't have an entry for this account so it's not blocked
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,12 @@ func (f *federator) DereferenceRemoteAccount(username string, remoteAccountID *u
|
||||||
return nil, errors.New("error resolving type as activitystreams application")
|
return nil, errors.New("error resolving type as activitystreams application")
|
||||||
}
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
|
case string(gtsmodel.ActivityStreamsService):
|
||||||
|
p, ok := t.(vocab.ActivityStreamsService)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("error resolving type as activitystreams service")
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("type name %s not supported", t.GetTypeName())
|
return nil, fmt.Errorf("type name %s not supported", t.GetTypeName())
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,57 @@ func (p *processor) AccountFollowersGet(authed *oauth.Auth, targetAccountID stri
|
||||||
return accounts, nil
|
return accounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *processor) AccountFollowingGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode) {
|
||||||
|
blocked, err := p.db.Blocked(authed.Account.ID, targetAccountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if blocked {
|
||||||
|
return nil, NewErrorNotFound(fmt.Errorf("block exists between accounts"))
|
||||||
|
}
|
||||||
|
|
||||||
|
following := []gtsmodel.Follow{}
|
||||||
|
accounts := []apimodel.Account{}
|
||||||
|
if err := p.db.GetFollowingByAccountID(targetAccountID, &following); err != nil {
|
||||||
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
|
return accounts, nil
|
||||||
|
}
|
||||||
|
return nil, NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range following {
|
||||||
|
blocked, err := p.db.Blocked(authed.Account.ID, f.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
if blocked {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
a := >smodel.Account{}
|
||||||
|
if err := p.db.GetByID(f.TargetAccountID, a); err != nil {
|
||||||
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// derefence account fields in case we haven't done it already
|
||||||
|
if err := p.dereferenceAccountFields(a, authed.Account.Username); err != nil {
|
||||||
|
// don't bail if we can't fetch them, we'll try another time
|
||||||
|
p.log.WithField("func", "AccountFollowingGet").Debugf("error dereferencing account fields: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := p.tc.AccountToMastoPublic(a)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
accounts = append(accounts, *account)
|
||||||
|
}
|
||||||
|
return accounts, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *processor) AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode) {
|
func (p *processor) AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode) {
|
||||||
if authed == nil || authed.Account == nil {
|
if authed == nil || authed.Account == nil {
|
||||||
return nil, NewErrorForbidden(errors.New("not authed"))
|
return nil, NewErrorForbidden(errors.New("not authed"))
|
||||||
|
|
@ -410,3 +461,85 @@ func (p *processor) AccountFollowCreate(authed *oauth.Auth, form *apimodel.Accou
|
||||||
// return whatever relationship results from this
|
// return whatever relationship results from this
|
||||||
return p.AccountRelationshipGet(authed, form.TargetAccountID)
|
return p.AccountRelationshipGet(authed, form.TargetAccountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *processor) AccountFollowRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode) {
|
||||||
|
// if there's a block between the accounts we shouldn't do anything
|
||||||
|
blocked, err := p.db.Blocked(authed.Account.ID, targetAccountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
if blocked {
|
||||||
|
return nil, NewErrorNotFound(fmt.Errorf("AccountFollowRemove: block exists between accounts"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the target account actually exists in our db
|
||||||
|
targetAcct := >smodel.Account{}
|
||||||
|
if err := p.db.GetByID(targetAccountID, targetAcct); err != nil {
|
||||||
|
if _, ok := err.(db.ErrNoEntries); ok {
|
||||||
|
return nil, NewErrorNotFound(fmt.Errorf("AccountFollowRemove: account %s not found in the db: %s", targetAccountID, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if a follow request exists, and remove it if it does (storing the URI for later)
|
||||||
|
var frChanged bool
|
||||||
|
var frURI string
|
||||||
|
fr := >smodel.FollowRequest{}
|
||||||
|
if err := p.db.GetWhere([]db.Where{
|
||||||
|
{Key: "account_id", Value: authed.Account.ID},
|
||||||
|
{Key: "target_account_id", Value: targetAccountID},
|
||||||
|
}, fr); err == nil {
|
||||||
|
frURI = fr.URI
|
||||||
|
if err := p.db.DeleteByID(fr.ID, fr); err != nil {
|
||||||
|
return nil, NewErrorInternalError(fmt.Errorf("AccountFollowRemove: error removing follow request from db: %s", err))
|
||||||
|
}
|
||||||
|
frChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// now do the same thing for any existing follow
|
||||||
|
var fChanged bool
|
||||||
|
var fURI string
|
||||||
|
f := >smodel.Follow{}
|
||||||
|
if err := p.db.GetWhere([]db.Where{
|
||||||
|
{Key: "account_id", Value: authed.Account.ID},
|
||||||
|
{Key: "target_account_id", Value: targetAccountID},
|
||||||
|
}, f); err == nil {
|
||||||
|
fURI = f.URI
|
||||||
|
if err := p.db.DeleteByID(f.ID, f); err != nil {
|
||||||
|
return nil, NewErrorInternalError(fmt.Errorf("AccountFollowRemove: error removing follow from db: %s", err))
|
||||||
|
}
|
||||||
|
fChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// follow request status changed so send the UNDO activity to the channel for async processing
|
||||||
|
if frChanged {
|
||||||
|
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||||
|
APObjectType: gtsmodel.ActivityStreamsFollow,
|
||||||
|
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||||
|
GTSModel: >smodel.Follow{
|
||||||
|
AccountID: authed.Account.ID,
|
||||||
|
TargetAccountID: targetAccountID,
|
||||||
|
URI: frURI,
|
||||||
|
},
|
||||||
|
OriginAccount: authed.Account,
|
||||||
|
TargetAccount: targetAcct,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// follow status changed so send the UNDO activity to the channel for async processing
|
||||||
|
if fChanged {
|
||||||
|
p.fromClientAPI <- gtsmodel.FromClientAPI{
|
||||||
|
APObjectType: gtsmodel.ActivityStreamsFollow,
|
||||||
|
APActivityType: gtsmodel.ActivityStreamsUndo,
|
||||||
|
GTSModel: >smodel.Follow{
|
||||||
|
AccountID: authed.Account.ID,
|
||||||
|
TargetAccountID: targetAccountID,
|
||||||
|
URI: fURI,
|
||||||
|
},
|
||||||
|
OriginAccount: authed.Account,
|
||||||
|
TargetAccount: targetAcct,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return whatever relationship results from all this
|
||||||
|
return p.AccountRelationshipGet(authed, targetAccountID)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func (p *processor) authenticateAndDereferenceFediRequest(username string, r *ht
|
||||||
// we might already have an entry for this account so check that first
|
// we might already have an entry for this account so check that first
|
||||||
requestingAccount := >smodel.Account{}
|
requestingAccount := >smodel.Account{}
|
||||||
|
|
||||||
err = p.db.GetWhere("uri", requestingAccountURI.String(), requestingAccount)
|
err = p.db.GetWhere([]db.Where{{Key: "uri", Value: requestingAccountURI.String()}}, requestingAccount)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// we do have it yay, return it
|
// we do have it yay, return it
|
||||||
return requestingAccount, nil
|
return requestingAccount, nil
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,17 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
|
||||||
return errors.New("accept was not parseable as *gtsmodel.Follow")
|
return errors.New("accept was not parseable as *gtsmodel.Follow")
|
||||||
}
|
}
|
||||||
return p.federateAcceptFollowRequest(follow)
|
return p.federateAcceptFollowRequest(follow)
|
||||||
|
case gtsmodel.ActivityStreamsUndo:
|
||||||
|
// UNDO
|
||||||
|
switch clientMsg.APObjectType {
|
||||||
|
// UNDO FOLLOW
|
||||||
|
case gtsmodel.ActivityStreamsFollow:
|
||||||
|
follow, ok := clientMsg.GTSModel.(*gtsmodel.Follow)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("undo was not parseable as *gtsmodel.Follow")
|
||||||
|
}
|
||||||
|
return p.federateUnfollow(follow, clientMsg.OriginAccount, clientMsg.TargetAccount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -117,11 +128,46 @@ func (p *processor) federateFollow(follow *gtsmodel.Follow, originAccount *gtsmo
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *processor) federateUnfollow(follow *gtsmodel.Follow, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
|
||||||
|
// recreate the follow
|
||||||
|
asFollow, err := p.tc.FollowToAS(follow, originAccount, targetAccount)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("federateUnfollow: error converting follow to as format: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
targetAccountURI, err := url.Parse(targetAccount.URI)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing uri %s: %s", targetAccount.URI, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create an Undo and set the appropriate actor on it
|
||||||
|
undo := streams.NewActivityStreamsUndo()
|
||||||
|
undo.SetActivityStreamsActor(asFollow.GetActivityStreamsActor())
|
||||||
|
|
||||||
|
// Set the recreated follow as the 'object' property.
|
||||||
|
undoObject := streams.NewActivityStreamsObjectProperty()
|
||||||
|
undoObject.AppendActivityStreamsFollow(asFollow)
|
||||||
|
undo.SetActivityStreamsObject(undoObject)
|
||||||
|
|
||||||
|
// Set the To of the undo as the target of the recreated follow
|
||||||
|
undoTo := streams.NewActivityStreamsToProperty()
|
||||||
|
undoTo.AppendIRI(targetAccountURI)
|
||||||
|
undo.SetActivityStreamsTo(undoTo)
|
||||||
|
|
||||||
|
outboxIRI, err := url.Parse(originAccount.OutboxURI)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("federateUnfollow: error parsing outboxURI %s: %s", originAccount.OutboxURI, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send off the Undo
|
||||||
|
_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, undo)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow) error {
|
func (p *processor) federateAcceptFollowRequest(follow *gtsmodel.Follow) error {
|
||||||
|
|
||||||
// TODO: tidy up this whole function -- move most of the logic for the conversion to the type converter because this is just a mess! Shame on me!
|
// TODO: tidy up this whole function -- move most of the logic for the conversion to the type converter because this is just a mess! Shame on me!
|
||||||
|
|
||||||
|
|
||||||
followAccepter := >smodel.Account{}
|
followAccepter := >smodel.Account{}
|
||||||
if err := p.db.GetByID(follow.TargetAccountID, followAccepter); err != nil {
|
if err := p.db.GetByID(follow.TargetAccountID, followAccepter); err != nil {
|
||||||
return fmt.Errorf("error federating follow accept: %s", err)
|
return fmt.Errorf("error federating follow accept: %s", err)
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ func (p *processor) dereferenceStatusFields(status *gtsmodel.Status) error {
|
||||||
|
|
||||||
// it might have been processed elsewhere so check first if it's already in the database or not
|
// it might have been processed elsewhere so check first if it's already in the database or not
|
||||||
maybeAttachment := >smodel.MediaAttachment{}
|
maybeAttachment := >smodel.MediaAttachment{}
|
||||||
err := p.db.GetWhere("remote_url", a.RemoteURL, maybeAttachment)
|
err := p.db.GetWhere([]db.Where{{Key: "remote_url", Value: a.RemoteURL}}, maybeAttachment)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// we already have it in the db, dereferenced, no need to do it again
|
// we already have it in the db, dereferenced, no need to do it again
|
||||||
l.Debugf("attachment already exists with id %s", maybeAttachment.ID)
|
l.Debugf("attachment already exists with id %s", maybeAttachment.ID)
|
||||||
|
|
@ -206,7 +206,7 @@ func (p *processor) dereferenceStatusFields(status *gtsmodel.Status) error {
|
||||||
m.OriginAccountURI = status.GTSAccount.URI
|
m.OriginAccountURI = status.GTSAccount.URI
|
||||||
|
|
||||||
targetAccount := >smodel.Account{}
|
targetAccount := >smodel.Account{}
|
||||||
if err := p.db.GetWhere("uri", uri.String(), targetAccount); err != nil {
|
if err := p.db.GetWhere([]db.Where{{Key: "uri", Value: uri.String()}}, targetAccount); err != nil {
|
||||||
// proper error
|
// proper error
|
||||||
if _, ok := err.(db.ErrNoEntries); !ok {
|
if _, ok := err.(db.ErrNoEntries); !ok {
|
||||||
return fmt.Errorf("db error checking for account with uri %s", uri.String())
|
return fmt.Errorf("db error checking for account with uri %s", uri.String())
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) InstanceGet(domain string) (*apimodel.Instance, ErrorWithCode) {
|
func (p *processor) InstanceGet(domain string) (*apimodel.Instance, ErrorWithCode) {
|
||||||
i := >smodel.Instance{}
|
i := >smodel.Instance{}
|
||||||
if err := p.db.GetWhere("domain", domain, i); err != nil {
|
if err := p.db.GetWhere([]db.Where{{Key: "domain", Value: domain}}, i); err != nil {
|
||||||
return nil, NewErrorInternalError(fmt.Errorf("db error fetching instance %s: %s", p.config.Host, err))
|
return nil, NewErrorInternalError(fmt.Errorf("db error fetching instance %s: %s", p.config.Host, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,10 +73,14 @@ type Processor interface {
|
||||||
AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, ErrorWithCode)
|
AccountStatusesGet(authed *oauth.Auth, targetAccountID string, limit int, excludeReplies bool, maxID string, pinned bool, mediaOnly bool) ([]apimodel.Status, ErrorWithCode)
|
||||||
// AccountFollowersGet fetches a list of the target account's followers.
|
// AccountFollowersGet fetches a list of the target account's followers.
|
||||||
AccountFollowersGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode)
|
AccountFollowersGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode)
|
||||||
|
// AccountFollowingGet fetches a list of the accounts that target account is following.
|
||||||
|
AccountFollowingGet(authed *oauth.Auth, targetAccountID string) ([]apimodel.Account, ErrorWithCode)
|
||||||
// AccountRelationshipGet returns a relationship model describing the relationship of the targetAccount to the Authed account.
|
// AccountRelationshipGet returns a relationship model describing the relationship of the targetAccount to the Authed account.
|
||||||
AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode)
|
AccountRelationshipGet(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode)
|
||||||
// AccountFollowCreate handles a follow request to an account, either remote or local.
|
// AccountFollowCreate handles a follow request to an account, either remote or local.
|
||||||
AccountFollowCreate(authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, ErrorWithCode)
|
AccountFollowCreate(authed *oauth.Auth, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, ErrorWithCode)
|
||||||
|
// AccountFollowRemove handles the removal of a follow/follow request to an account, either remote or local.
|
||||||
|
AccountFollowRemove(authed *oauth.Auth, targetAccountID string) (*apimodel.Relationship, ErrorWithCode)
|
||||||
|
|
||||||
// AdminEmojiCreate handles the creation of a new instance emoji by an admin, using the given form.
|
// 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(authed *oauth.Auth, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, error)
|
||||||
|
|
@ -204,15 +208,11 @@ func (p *processor) Start() error {
|
||||||
DistLoop:
|
DistLoop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// case clientMsg := <-p.toClientAPI:
|
|
||||||
// p.log.Infof("received message TO client API: %+v", clientMsg)
|
|
||||||
case clientMsg := <-p.fromClientAPI:
|
case clientMsg := <-p.fromClientAPI:
|
||||||
p.log.Infof("received message FROM client API: %+v", clientMsg)
|
p.log.Infof("received message FROM client API: %+v", clientMsg)
|
||||||
if err := p.processFromClientAPI(clientMsg); err != nil {
|
if err := p.processFromClientAPI(clientMsg); err != nil {
|
||||||
p.log.Error(err)
|
p.log.Error(err)
|
||||||
}
|
}
|
||||||
// case federatorMsg := <-p.toFederator:
|
|
||||||
// p.log.Infof("received message TO federator: %+v", federatorMsg)
|
|
||||||
case federatorMsg := <-p.fromFederator:
|
case federatorMsg := <-p.fromFederator:
|
||||||
p.log.Infof("received message FROM federator: %+v", federatorMsg)
|
p.log.Infof("received message FROM federator: %+v", federatorMsg)
|
||||||
if err := p.processFromFederator(federatorMsg); err != nil {
|
if err := p.processFromFederator(federatorMsg); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -106,17 +106,17 @@ func (pts *tokenStore) Create(ctx context.Context, info oauth2.TokenInfo) error
|
||||||
|
|
||||||
// RemoveByCode deletes a token from the DB based on the Code field
|
// RemoveByCode deletes a token from the DB based on the Code field
|
||||||
func (pts *tokenStore) RemoveByCode(ctx context.Context, code string) error {
|
func (pts *tokenStore) RemoveByCode(ctx context.Context, code string) error {
|
||||||
return pts.db.DeleteWhere("code", code, &Token{})
|
return pts.db.DeleteWhere([]db.Where{{Key: "code", Value: code}}, &Token{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveByAccess deletes a token from the DB based on the Access field
|
// RemoveByAccess deletes a token from the DB based on the Access field
|
||||||
func (pts *tokenStore) RemoveByAccess(ctx context.Context, access string) error {
|
func (pts *tokenStore) RemoveByAccess(ctx context.Context, access string) error {
|
||||||
return pts.db.DeleteWhere("access", access, &Token{})
|
return pts.db.DeleteWhere([]db.Where{{Key: "access", Value: access}}, &Token{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveByRefresh deletes a token from the DB based on the Refresh field
|
// RemoveByRefresh deletes a token from the DB based on the Refresh field
|
||||||
func (pts *tokenStore) RemoveByRefresh(ctx context.Context, refresh string) error {
|
func (pts *tokenStore) RemoveByRefresh(ctx context.Context, refresh string) error {
|
||||||
return pts.db.DeleteWhere("refresh", refresh, &Token{})
|
return pts.db.DeleteWhere([]db.Where{{Key: "refresh", Value: refresh}}, &Token{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByCode selects a token from the DB based on the Code field
|
// GetByCode selects a token from the DB based on the Code field
|
||||||
|
|
@ -127,7 +127,7 @@ func (pts *tokenStore) GetByCode(ctx context.Context, code string) (oauth2.Token
|
||||||
pgt := &Token{
|
pgt := &Token{
|
||||||
Code: code,
|
Code: code,
|
||||||
}
|
}
|
||||||
if err := pts.db.GetWhere("code", code, pgt); err != nil {
|
if err := pts.db.GetWhere([]db.Where{{Key: "code", Value: code}}, pgt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return TokenToOauthToken(pgt), nil
|
return TokenToOauthToken(pgt), nil
|
||||||
|
|
@ -141,7 +141,7 @@ func (pts *tokenStore) GetByAccess(ctx context.Context, access string) (oauth2.T
|
||||||
pgt := &Token{
|
pgt := &Token{
|
||||||
Access: access,
|
Access: access,
|
||||||
}
|
}
|
||||||
if err := pts.db.GetWhere("access", access, pgt); err != nil {
|
if err := pts.db.GetWhere([]db.Where{{Key: "access", Value: access}}, pgt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return TokenToOauthToken(pgt), nil
|
return TokenToOauthToken(pgt), nil
|
||||||
|
|
@ -155,7 +155,7 @@ func (pts *tokenStore) GetByRefresh(ctx context.Context, refresh string) (oauth2
|
||||||
pgt := &Token{
|
pgt := &Token{
|
||||||
Refresh: refresh,
|
Refresh: refresh,
|
||||||
}
|
}
|
||||||
if err := pts.db.GetWhere("refresh", refresh, pgt); err != nil {
|
if err := pts.db.GetWhere([]db.Where{{Key: "refresh", Value: refresh}}, pgt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return TokenToOauthToken(pgt), nil
|
return TokenToOauthToken(pgt), nil
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func (c *converter) ASRepresentationToAccount(accountable Accountable) (*gtsmode
|
||||||
uri := uriProp.GetIRI()
|
uri := uriProp.GetIRI()
|
||||||
|
|
||||||
acct := >smodel.Account{}
|
acct := >smodel.Account{}
|
||||||
err := c.db.GetWhere("uri", uri.String(), acct)
|
err := c.db.GetWhere([]db.Where{{Key: "uri", Value: uri.String()}}, acct)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// we already know this account so we can skip generating it
|
// we already know this account so we can skip generating it
|
||||||
return acct, nil
|
return acct, nil
|
||||||
|
|
@ -220,7 +220,7 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e
|
||||||
status.APStatusOwnerURI = attributedTo.String()
|
status.APStatusOwnerURI = attributedTo.String()
|
||||||
|
|
||||||
statusOwner := >smodel.Account{}
|
statusOwner := >smodel.Account{}
|
||||||
if err := c.db.GetWhere("uri", attributedTo.String(), statusOwner); err != nil {
|
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: attributedTo.String()}}, statusOwner); err != nil {
|
||||||
return nil, fmt.Errorf("couldn't get status owner from db: %s", err)
|
return nil, fmt.Errorf("couldn't get status owner from db: %s", err)
|
||||||
}
|
}
|
||||||
status.AccountID = statusOwner.ID
|
status.AccountID = statusOwner.ID
|
||||||
|
|
@ -235,7 +235,7 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e
|
||||||
|
|
||||||
// now we can check if we have the replied-to status in our db already
|
// now we can check if we have the replied-to status in our db already
|
||||||
inReplyToStatus := >smodel.Status{}
|
inReplyToStatus := >smodel.Status{}
|
||||||
if err := c.db.GetWhere("uri", inReplyToURI.String(), inReplyToStatus); err == nil {
|
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: inReplyToURI.String()}}, inReplyToStatus); err == nil {
|
||||||
// we have the status in our database already
|
// we have the status in our database already
|
||||||
// so we can set these fields here and then...
|
// so we can set these fields here and then...
|
||||||
status.InReplyToID = inReplyToStatus.ID
|
status.InReplyToID = inReplyToStatus.ID
|
||||||
|
|
@ -322,7 +322,7 @@ func (c *converter) ASFollowToFollowRequest(followable Followable) (*gtsmodel.Fo
|
||||||
return nil, errors.New("error extracting actor property from follow")
|
return nil, errors.New("error extracting actor property from follow")
|
||||||
}
|
}
|
||||||
originAccount := >smodel.Account{}
|
originAccount := >smodel.Account{}
|
||||||
if err := c.db.GetWhere("uri", origin.String(), originAccount); err != nil {
|
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: origin.String()}}, originAccount); err != nil {
|
||||||
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +331,7 @@ func (c *converter) ASFollowToFollowRequest(followable Followable) (*gtsmodel.Fo
|
||||||
return nil, errors.New("error extracting object property from follow")
|
return nil, errors.New("error extracting object property from follow")
|
||||||
}
|
}
|
||||||
targetAccount := >smodel.Account{}
|
targetAccount := >smodel.Account{}
|
||||||
if err := c.db.GetWhere("uri", target.String(), targetAccount); err != nil {
|
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: target.String()}}, targetAccount); err != nil {
|
||||||
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -356,7 +356,7 @@ func (c *converter) ASFollowToFollow(followable Followable) (*gtsmodel.Follow, e
|
||||||
return nil, errors.New("error extracting actor property from follow")
|
return nil, errors.New("error extracting actor property from follow")
|
||||||
}
|
}
|
||||||
originAccount := >smodel.Account{}
|
originAccount := >smodel.Account{}
|
||||||
if err := c.db.GetWhere("uri", origin.String(), originAccount); err != nil {
|
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: origin.String()}}, originAccount); err != nil {
|
||||||
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -365,7 +365,7 @@ func (c *converter) ASFollowToFollow(followable Followable) (*gtsmodel.Follow, e
|
||||||
return nil, errors.New("error extracting object property from follow")
|
return nil, errors.New("error extracting object property from follow")
|
||||||
}
|
}
|
||||||
targetAccount := >smodel.Account{}
|
targetAccount := >smodel.Account{}
|
||||||
if err := c.db.GetWhere("uri", target.String(), targetAccount); err != nil {
|
if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: target.String()}}, targetAccount); err != nil {
|
||||||
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
return nil, fmt.Errorf("error extracting account with uri %s from the database: %s", origin.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue