summaryrefslogtreecommitdiff
path: root/internal/api/client
diff options
context:
space:
mode:
Diffstat (limited to 'internal/api/client')
-rw-r--r--internal/api/client/account/account.go12
-rw-r--r--internal/api/client/account/follow.go56
-rw-r--r--internal/api/client/account/following.go49
-rw-r--r--internal/api/client/account/relationships.go46
-rw-r--r--internal/api/client/account/unfollow.go53
-rw-r--r--internal/api/client/auth/authorize.go3
-rw-r--r--internal/api/client/auth/middleware.go3
-rw-r--r--internal/api/client/auth/signin.go3
-rw-r--r--internal/api/client/followrequest/accept.go5
-rw-r--r--internal/api/client/status/statuscreate_test.go3
10 files changed, 227 insertions, 6 deletions
diff --git a/internal/api/client/account/account.go b/internal/api/client/account/account.go
index 1e4b716f5..94f753825 100644
--- a/internal/api/client/account/account.go
+++ b/internal/api/client/account/account.go
@@ -57,6 +57,14 @@ const (
GetStatusesPath = BasePathWithID + "/statuses"
// GetFollowersPath is for showing an account's 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 = BasePath + "/relationships"
+ // FollowPath is for POSTing new follows to, and updating existing follows
+ PostFollowPath = BasePathWithID + "/follow"
+ // PostUnfollowPath is for POSTing an unfollow
+ PostUnfollowPath = BasePathWithID + "/unfollow"
)
// Module implements the ClientAPIModule interface for account-related actions
@@ -82,6 +90,10 @@ func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodPatch, BasePathWithID, m.muxHandler)
r.AttachHandler(http.MethodGet, GetStatusesPath, m.AccountStatusesGETHandler)
r.AttachHandler(http.MethodGet, GetFollowersPath, m.AccountFollowersGETHandler)
+ r.AttachHandler(http.MethodGet, GetFollowingPath, m.AccountFollowingGETHandler)
+ r.AttachHandler(http.MethodGet, GetRelationshipsPath, m.AccountRelationshipsGETHandler)
+ r.AttachHandler(http.MethodPost, PostFollowPath, m.AccountFollowPOSTHandler)
+ r.AttachHandler(http.MethodPost, PostUnfollowPath, m.AccountUnfollowPOSTHandler)
return nil
}
diff --git a/internal/api/client/account/follow.go b/internal/api/client/account/follow.go
new file mode 100644
index 000000000..bee41c280
--- /dev/null
+++ b/internal/api/client/account/follow.go
@@ -0,0 +1,56 @@
+/*
+ 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/api/model"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+// AccountFollowPOSTHandler is the endpoint for creating a new follow request to the target account
+func (m *Module) AccountFollowPOSTHandler(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
+ }
+ form := &model.AccountFollowRequest{}
+ if err := c.ShouldBind(form); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+ form.TargetAccountID = targetAcctID
+
+ relationship, errWithCode := m.processor.AccountFollowCreate(authed, form)
+ if errWithCode != nil {
+ c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
+ return
+ }
+
+ c.JSON(http.StatusOK, relationship)
+}
diff --git a/internal/api/client/account/following.go b/internal/api/client/account/following.go
new file mode 100644
index 000000000..2a1373e40
--- /dev/null
+++ b/internal/api/client/account/following.go
@@ -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)
+}
diff --git a/internal/api/client/account/relationships.go b/internal/api/client/account/relationships.go
new file mode 100644
index 000000000..fd96867ac
--- /dev/null
+++ b/internal/api/client/account/relationships.go
@@ -0,0 +1,46 @@
+package account
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/superseriousbusiness/gotosocial/internal/api/model"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+// AccountRelationshipsGETHandler serves the relationship of the requesting account with one or more requested account IDs.
+func (m *Module) AccountRelationshipsGETHandler(c *gin.Context) {
+ l := m.log.WithField("func", "AccountRelationshipsGETHandler")
+
+ authed, err := oauth.Authed(c, true, true, true, true)
+ if err != nil {
+ l.Debugf("error authing: %s", err)
+ c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
+ return
+ }
+
+ targetAccountIDs := c.QueryArray("id[]")
+ if len(targetAccountIDs) == 0 {
+ // check fallback -- let's be generous and see if maybe it's just set as 'id'?
+ id := c.Query("id")
+ if id == "" {
+ l.Debug("no account id specified in query")
+ c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
+ return
+ }
+ targetAccountIDs = append(targetAccountIDs, id)
+ }
+
+ relationships := []model.Relationship{}
+
+ for _, targetAccountID := range targetAccountIDs {
+ r, errWithCode := m.processor.AccountRelationshipGet(authed, targetAccountID)
+ if err != nil {
+ c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
+ return
+ }
+ relationships = append(relationships, *r)
+ }
+
+ c.JSON(http.StatusOK, relationships)
+}
diff --git a/internal/api/client/account/unfollow.go b/internal/api/client/account/unfollow.go
new file mode 100644
index 000000000..69ed72b88
--- /dev/null
+++ b/internal/api/client/account/unfollow.go
@@ -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)
+}
diff --git a/internal/api/client/auth/authorize.go b/internal/api/client/auth/authorize.go
index d5f8ee214..f473579db 100644
--- a/internal/api/client/auth/authorize.go
+++ b/internal/api/client/auth/authorize.go
@@ -28,6 +28,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
@@ -60,7 +61,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
app := &gtsmodel.Application{
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)})
return
}
diff --git a/internal/api/client/auth/middleware.go b/internal/api/client/auth/middleware.go
index 2a63cbdb6..dba8e5a1d 100644
--- a/internal/api/client/auth/middleware.go
+++ b/internal/api/client/auth/middleware.go
@@ -20,6 +20,7 @@ package auth
import (
"github.com/gin-gonic/gin"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -68,7 +69,7 @@ func (m *Module) OauthTokenMiddleware(c *gin.Context) {
if cid := ti.GetClientID(); cid != "" {
l.Tracef("authenticated client %s with bearer token, scope is %s", cid, ti.GetScope())
app := &gtsmodel.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)
}
c.Set(oauth.SessionAuthorizedApplication, app)
diff --git a/internal/api/client/auth/signin.go b/internal/api/client/auth/signin.go
index 79d9b300e..e9385e39a 100644
--- a/internal/api/client/auth/signin.go
+++ b/internal/api/client/auth/signin.go
@@ -24,6 +24,7 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"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
gtsUser := &gtsmodel.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)
return incorrectPassword()
}
diff --git a/internal/api/client/followrequest/accept.go b/internal/api/client/followrequest/accept.go
index 45dc1a2af..bb2910c8f 100644
--- a/internal/api/client/followrequest/accept.go
+++ b/internal/api/client/followrequest/accept.go
@@ -48,10 +48,11 @@ func (m *Module) FollowRequestAcceptPOSTHandler(c *gin.Context) {
return
}
- if errWithCode := m.processor.FollowRequestAccept(authed, originAccountID); errWithCode != nil {
+ r, errWithCode := m.processor.FollowRequestAccept(authed, originAccountID)
+ if errWithCode != nil {
l.Debug(errWithCode.Error())
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
return
}
- c.Status(http.StatusOK)
+ c.JSON(http.StatusOK, r)
}
diff --git a/internal/api/client/status/statuscreate_test.go b/internal/api/client/status/statuscreate_test.go
index fb9b48f8a..a78374fe8 100644
--- a/internal/api/client/status/statuscreate_test.go
+++ b/internal/api/client/status/statuscreate_test.go
@@ -32,6 +32,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
@@ -118,7 +119,7 @@ func (suite *StatusCreateTestSuite) TestPostNewStatus() {
}, statusReply.Tags[0])
gtsTag := &gtsmodel.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.Equal(suite.T(), statusReply.Account.ID, gtsTag.FirstSeenFromAccountID)
}