[chore] The Big Middleware and API Refactor (tm) (#1250)

* interim commit: start refactoring middlewares into package under router

* another interim commit, this is becoming a big job

* another fucking massive interim commit

* refactor bookmarks to new style

* ambassador, wiz zeze commits you are spoiling uz

* she compiles, we're getting there

* we're just normal men; we're just innocent men

* apiutil

* whoopsie

* i'm glad noone reads commit msgs haha :blob_sweat:

* use that weirdo go-bytesize library for maxMultipartMemory

* fix media module paths
This commit is contained in:
tobi
2023-01-02 13:10:50 +01:00
committed by GitHub
parent 560ff1209d
commit 941893a774
228 changed files with 3188 additions and 3047 deletions

View File

@@ -0,0 +1,66 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 api
import (
"context"
"net/url"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/emoji"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
type ActivityPub struct {
emoji *emoji.Module
users *users.Module
isURIBlocked func(context.Context, *url.URL) (bool, db.Error)
}
func (a *ActivityPub) Route(r router.Router) {
// create groupings for the 'emoji' and 'users' prefixes
emojiGroup := r.AttachGroup("emoji")
usersGroup := r.AttachGroup("users")
// instantiate + attach shared, non-global middlewares to both of these groups
var (
rateLimitMiddleware = middleware.RateLimit() // nolint:contextcheck
signatureCheckMiddleware = middleware.SignatureCheck(a.isURIBlocked)
gzipMiddleware = middleware.Gzip()
cacheControlMiddleware = middleware.CacheControl("no-store")
)
emojiGroup.Use(rateLimitMiddleware, signatureCheckMiddleware, gzipMiddleware, cacheControlMiddleware)
usersGroup.Use(rateLimitMiddleware, signatureCheckMiddleware, gzipMiddleware, cacheControlMiddleware)
a.emoji.Route(emojiGroup.Handle)
a.users.Route(usersGroup.Handle)
}
func NewActivityPub(db db.DB, p processing.Processor) *ActivityPub {
return &ActivityPub{
emoji: emoji.New(p),
users: users.New(p),
isURIBlocked: db.IsURIBlocked,
}
}

View File

@@ -21,30 +21,27 @@ package emoji
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// BasePath is the base path for serving the emoji API
BasePath = "/api/v1/custom_emojis"
// EmojiIDKey is for emoji IDs
EmojiIDKey = "id"
// EmojiBasePath is the base path for serving AP Emojis, minus the "emoji" prefix
EmojiWithIDPath = "/:" + EmojiIDKey
)
// Module implements the ClientAPIModule interface for everything related to emoji
type Module struct {
processor processing.Processor
}
// New returns a new emoji module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodGet, BasePath, m.EmojisGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, EmojiWithIDPath, m.EmojiGetHandler)
}

View File

@@ -19,54 +19,39 @@
package emoji
import (
"context"
"encoding/json"
"errors"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
// EmojiGetHandler
func (m *Module) EmojiGetHandler(c *gin.Context) {
// usernames on our instance are always lowercase
requestedEmojiID := strings.ToUpper(c.Param(EmojiIDKey))
if requestedEmojiID == "" {
err := errors.New("no emoji id specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.ActivityPubAcceptHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.ActivityPubAcceptHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
ctx := c.Request.Context()
verifier, signed := c.Get(string(ap.ContextRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, ap.ContextRequestingPublicKeyVerifier, verifier)
}
signature, signed := c.Get(string(ap.ContextRequestingPublicKeySignature))
if signed {
ctx = context.WithValue(ctx, ap.ContextRequestingPublicKeySignature, signature)
}
resp, errWithCode := m.processor.GetFediEmoji(ctx, requestedEmojiID, c.Request.URL)
resp, errWithCode := m.processor.GetFediEmoji(apiutil.TransferSignatureContext(c), requestedEmojiID, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -26,8 +26,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/emoji"
"github.com/superseriousbusiness/gotosocial/internal/api/security"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/emoji"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/email"
@@ -35,7 +34,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
@@ -44,20 +43,20 @@ import (
type EmojiGetTestSuite struct {
suite.Suite
db db.DB
tc typeutils.TypeConverter
mediaManager media.Manager
federator federation.Federator
emailSender email.Sender
processor processing.Processor
storage *storage.Driver
oauthServer oauth.Server
securityModule *security.Module
db db.DB
tc typeutils.TypeConverter
mediaManager media.Manager
federator federation.Federator
emailSender email.Sender
processor processing.Processor
storage *storage.Driver
testEmojis map[string]*gtsmodel.Emoji
testAccounts map[string]*gtsmodel.Account
emojiModule *emoji.Module
signatureCheck gin.HandlerFunc
}
func (suite *EmojiGetTestSuite) SetupSuite() {
@@ -79,12 +78,12 @@ func (suite *EmojiGetTestSuite) SetupTest() {
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.emojiModule = emoji.New(suite.processor).(*emoji.Module)
suite.oauthServer = testrig.NewTestOauthServer(suite.db)
suite.securityModule = security.New(suite.db, suite.oauthServer).(*security.Module)
suite.emojiModule = emoji.New(suite.processor)
testrig.StandardDBSetup(suite.db, suite.testAccounts)
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")
suite.signatureCheck = middleware.SignatureCheck(suite.db.IsURIBlocked)
suite.NoError(suite.processor.Start())
}
@@ -108,7 +107,7 @@ func (suite *EmojiGetTestSuite) TestGetEmoji() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.

View File

@@ -16,31 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
import (
"context"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/ap"
)
// transferContext transfers the signature verifier and signature from the gin context to the request context
func transferContext(c *gin.Context) context.Context {
ctx := c.Request.Context()
verifier, signed := c.Get(string(ap.ContextRequestingPublicKeyVerifier))
if signed {
ctx = context.WithValue(ctx, ap.ContextRequestingPublicKeyVerifier, verifier)
}
signature, signed := c.Get(string(ap.ContextRequestingPublicKeySignature))
if signed {
ctx = context.WithValue(ctx, ap.ContextRequestingPublicKeySignature, signature)
}
return ctx
}
package users
// SwaggerCollection represents an activitypub collection.
// swagger:model swaggerCollection

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -25,7 +25,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -35,31 +35,31 @@ func (m *Module) FollowersGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the user's profile
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername)
return
}
resp, errWithCode := m.processor.GetFediFollowers(transferContext(c), requestedUsername, c.Request.URL)
resp, errWithCode := m.processor.GetFediFollowers(apiutil.TransferSignatureContext(c), requestedUsername, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -25,7 +25,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -35,31 +35,31 @@ func (m *Module) FollowingGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the user's profile
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername)
return
}
resp, errWithCode := m.processor.GetFediFollowing(transferContext(c), requestedUsername, c.Request.URL)
resp, errWithCode := m.processor.GetFediFollowing(apiutil.TransferSignatureContext(c), requestedUsername, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"errors"
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror" //nolint:typecheck
)
@@ -34,18 +34,18 @@ func (m *Module) InboxPOSTHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if posted, err := m.processor.InboxPost(transferContext(c), c.Writer, c.Request); err != nil {
if posted, err := m.processor.InboxPost(apiutil.TransferSignatureContext(c), c.Writer, c.Request); err != nil {
if withCode, ok := err.(gtserror.WithCode); ok {
api.ErrorHandler(c, withCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, withCode, m.processor.InstanceGet)
} else {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
}
} else if !posted {
err := errors.New("unable to process request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
}
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user_test
package users_test
import (
"bytes"
@@ -32,7 +32,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/activity/pub"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@@ -92,7 +92,7 @@ func (suite *InboxPostTestSuite) TestPostBlock() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -105,13 +105,13 @@ func (suite *InboxPostTestSuite) TestPostBlock() {
ctx.Request.Header.Set("Content-Type", "application/activity+json")
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: blockedAccount.Username,
},
}
@@ -196,7 +196,7 @@ func (suite *InboxPostTestSuite) TestPostUnblock() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -209,13 +209,13 @@ func (suite *InboxPostTestSuite) TestPostUnblock() {
ctx.Request.Header.Set("Content-Type", "application/activity+json")
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: blockedAccount.Username,
},
}
@@ -298,7 +298,7 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -311,13 +311,13 @@ func (suite *InboxPostTestSuite) TestPostUpdate() {
ctx.Request.Header.Set("Content-Type", "application/activity+json")
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: receivingAccount.Username,
},
}
@@ -431,7 +431,7 @@ func (suite *InboxPostTestSuite) TestPostDelete() {
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.NoError(processor.Start())
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
// setup request
recorder := httptest.NewRecorder()
@@ -443,13 +443,13 @@ func (suite *InboxPostTestSuite) TestPostDelete() {
ctx.Request.Header.Set("Content-Type", "application/activity+json")
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: receivingAccount.Username,
},
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -27,7 +27,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -90,17 +90,17 @@ func (m *Module) OutboxGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the user's profile
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername)
return
@@ -111,7 +111,7 @@ func (m *Module) OutboxGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(pageString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", PageKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
page = i
@@ -129,15 +129,15 @@ func (m *Module) OutboxGETHandler(c *gin.Context) {
maxID = maxIDString
}
resp, errWithCode := m.processor.GetFediOutbox(transferContext(c), requestedUsername, page, maxID, minID, c.Request.URL)
resp, errWithCode := m.processor.GetFediOutbox(apiutil.TransferSignatureContext(c), requestedUsername, page, maxID, minID, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user_test
package users_test
import (
"context"
@@ -30,7 +30,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/testrig"
@@ -55,13 +55,13 @@ func (suite *OutboxGetTestSuite) TestGetOutbox() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
}
@@ -102,7 +102,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxFirstPage() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -114,13 +114,13 @@ func (suite *OutboxGetTestSuite) TestGetOutboxFirstPage() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
}
@@ -161,7 +161,7 @@ func (suite *OutboxGetTestSuite) TestGetOutboxNextPage() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -173,17 +173,17 @@ func (suite *OutboxGetTestSuite) TestGetOutboxNextPage() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
gin.Param{
Key: user.MaxIDKey,
Key: users.MaxIDKey,
Value: "01F8MHAMCHF6Y650WCRSCP4WMY",
},
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -25,7 +25,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -39,31 +39,31 @@ func (m *Module) PublicKeyGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the user's profile
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername)
return
}
resp, errWithCode := m.processor.GetFediUser(transferContext(c), requestedUsername, c.Request.URL)
resp, errWithCode := m.processor.GetFediUser(apiutil.TransferSignatureContext(c), requestedUsername, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -27,7 +27,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -97,7 +97,7 @@ func (m *Module) StatusRepliesGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -105,17 +105,17 @@ func (m *Module) StatusRepliesGETHandler(c *gin.Context) {
requestedStatusID := strings.ToUpper(c.Param(StatusIDKey))
if requestedStatusID == "" {
err := errors.New("no status id specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the status
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername+"/statuses/"+requestedStatusID)
return
@@ -126,7 +126,7 @@ func (m *Module) StatusRepliesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(pageString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", PageKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
page = i
@@ -138,7 +138,7 @@ func (m *Module) StatusRepliesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(onlyOtherAccountsString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", OnlyOtherAccountsKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
onlyOtherAccounts = i
@@ -150,15 +150,15 @@ func (m *Module) StatusRepliesGETHandler(c *gin.Context) {
minID = minIDString
}
resp, errWithCode := m.processor.GetFediStatusReplies(transferContext(c), requestedUsername, requestedStatusID, page, onlyOtherAccounts, minID, c.Request.URL)
resp, errWithCode := m.processor.GetFediStatusReplies(apiutil.TransferSignatureContext(c), requestedUsername, requestedStatusID, page, onlyOtherAccounts, minID, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user_test
package users_test
import (
"context"
@@ -32,7 +32,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/testrig"
@@ -58,17 +58,17 @@ func (suite *RepliesGetTestSuite) TestGetReplies() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
gin.Param{
Key: user.StatusIDKey,
Key: users.StatusIDKey,
Value: targetStatus.ID,
},
}
@@ -111,7 +111,7 @@ func (suite *RepliesGetTestSuite) TestGetRepliesNext() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -123,17 +123,17 @@ func (suite *RepliesGetTestSuite) TestGetRepliesNext() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
gin.Param{
Key: user.StatusIDKey,
Key: users.StatusIDKey,
Value: targetStatus.ID,
},
}
@@ -179,7 +179,7 @@ func (suite *RepliesGetTestSuite) TestGetRepliesLast() {
federator := testrig.NewTestFederator(suite.db, tc, suite.storage, suite.mediaManager, fedWorker)
emailSender := testrig.NewEmailSender("../../../../web/template/", nil)
processor := testrig.NewTestProcessor(suite.db, suite.storage, federator, emailSender, suite.mediaManager, clientWorker, fedWorker)
userModule := user.New(processor).(*user.Module)
userModule := users.New(processor)
suite.NoError(processor.Start())
// setup request
@@ -191,17 +191,17 @@ func (suite *RepliesGetTestSuite) TestGetRepliesLast() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
gin.Param{
Key: user.StatusIDKey,
Key: users.StatusIDKey,
Value: targetStatus.ID,
},
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -25,7 +25,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -35,7 +35,7 @@ func (m *Module) StatusGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -43,31 +43,31 @@ func (m *Module) StatusGETHandler(c *gin.Context) {
requestedStatusID := strings.ToUpper(c.Param(StatusIDKey))
if requestedStatusID == "" {
err := errors.New("no status id specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the status
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername+"/statuses/"+requestedStatusID)
return
}
resp, errWithCode := m.processor.GetFediStatus(transferContext(c), requestedUsername, requestedStatusID, c.Request.URL)
resp, errWithCode := m.processor.GetFediStatus(apiutil.TransferSignatureContext(c), requestedUsername, requestedStatusID, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user_test
package users_test
import (
"context"
@@ -31,7 +31,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -55,17 +55,17 @@ func (suite *StatusGetTestSuite) TestGetStatus() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
gin.Param{
Key: user.StatusIDKey,
Key: users.StatusIDKey,
Value: targetStatus.ID,
},
}
@@ -114,17 +114,17 @@ func (suite *StatusGetTestSuite) TestGetStatusLowercase() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: strings.ToLower(targetAccount.Username),
},
gin.Param{
Key: user.StatusIDKey,
Key: users.StatusIDKey,
Value: strings.ToLower(targetStatus.ID),
},
}

View File

@@ -0,0 +1,80 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 users
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/uris"
)
const (
// UsernameKey is for account usernames.
UsernameKey = "username"
// StatusIDKey is for status IDs
StatusIDKey = "status"
// OnlyOtherAccountsKey is for filtering status responses.
OnlyOtherAccountsKey = "only_other_accounts"
// MinIDKey is for filtering status responses.
MinIDKey = "min_id"
// MaxIDKey is for filtering status responses.
MaxIDKey = "max_id"
// PageKey is for filtering status responses.
PageKey = "page"
// BasePath is the base path for serving AP 'users' requests, minus the 'users' prefix.
BasePath = "/:" + UsernameKey
// PublicKeyPath is a path to a user's public key, for serving bare minimum AP representations.
PublicKeyPath = BasePath + "/" + uris.PublicKeyPath
// InboxPath is for serving POST requests to a user's inbox with the given username key.
InboxPath = BasePath + "/" + uris.InboxPath
// OutboxPath is for serving GET requests to a user's outbox with the given username key.
OutboxPath = BasePath + "/" + uris.OutboxPath
// FollowersPath is for serving GET request's to a user's followers list, with the given username key.
FollowersPath = BasePath + "/" + uris.FollowersPath
// FollowingPath is for serving GET request's to a user's following list, with the given username key.
FollowingPath = BasePath + "/" + uris.FollowingPath
// StatusPath is for serving GET requests to a particular status by a user, with the given username key and status ID
StatusPath = BasePath + "/" + uris.StatusesPath + "/:" + StatusIDKey
// StatusRepliesPath is for serving the replies collection of a status.
StatusRepliesPath = StatusPath + "/replies"
)
type Module struct {
processor processing.Processor
}
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.UsersGETHandler)
attachHandler(http.MethodPost, InboxPath, m.InboxPOSTHandler)
attachHandler(http.MethodGet, FollowersPath, m.FollowersGETHandler)
attachHandler(http.MethodGet, FollowingPath, m.FollowingGETHandler)
attachHandler(http.MethodGet, StatusPath, m.StatusGETHandler)
attachHandler(http.MethodGet, PublicKeyPath, m.PublicKeyGETHandler)
attachHandler(http.MethodGet, StatusRepliesPath, m.StatusRepliesGETHandler)
attachHandler(http.MethodGet, OutboxPath, m.OutboxGETHandler)
}

View File

@@ -16,12 +16,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user_test
package users_test
import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/api/security"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/email"
@@ -29,7 +29,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/internal/typeutils"
@@ -39,15 +39,13 @@ import (
type UserStandardTestSuite struct {
// standard suite interfaces
suite.Suite
db db.DB
tc typeutils.TypeConverter
mediaManager media.Manager
federator federation.Federator
emailSender email.Sender
processor processing.Processor
storage *storage.Driver
oauthServer oauth.Server
securityModule *security.Module
db db.DB
tc typeutils.TypeConverter
mediaManager media.Manager
federator federation.Federator
emailSender email.Sender
processor processing.Processor
storage *storage.Driver
// standard suite models
testTokens map[string]*gtsmodel.Token
@@ -60,7 +58,9 @@ type UserStandardTestSuite struct {
testBlocks map[string]*gtsmodel.Block
// module being tested
userModule *user.Module
userModule *users.Module
signatureCheck gin.HandlerFunc
}
func (suite *UserStandardTestSuite) SetupSuite() {
@@ -88,12 +88,12 @@ func (suite *UserStandardTestSuite) SetupTest() {
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.userModule = user.New(suite.processor).(*user.Module)
suite.oauthServer = testrig.NewTestOauthServer(suite.db)
suite.securityModule = security.New(suite.db, suite.oauthServer).(*security.Module)
suite.userModule = users.New(suite.processor)
testrig.StandardDBSetup(suite.db, suite.testAccounts)
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")
suite.signatureCheck = middleware.SignatureCheck(suite.db.IsURIBlocked)
suite.NoError(suite.processor.Start())
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user
package users
import (
"encoding/json"
@@ -25,7 +25,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
@@ -43,31 +43,31 @@ func (m *Module) UsersGETHandler(c *gin.Context) {
requestedUsername := strings.ToLower(c.Param(UsernameKey))
if requestedUsername == "" {
err := errors.New("no username specified in request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
format, err := api.NegotiateAccept(c, api.HTMLOrActivityPubHeaders...)
format, err := apiutil.NegotiateAccept(c, apiutil.HTMLOrActivityPubHeaders...)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if format == string(api.TextHTML) {
if format == string(apiutil.TextHTML) {
// redirect to the user's profile
c.Redirect(http.StatusSeeOther, "/@"+requestedUsername)
return
}
resp, errWithCode := m.processor.GetFediUser(transferContext(c), requestedUsername, c.Request.URL)
resp, errWithCode := m.processor.GetFediUser(apiutil.TransferSignatureContext(c), requestedUsername, c.Request.URL)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
b, err := json.Marshal(resp)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package user_test
package users_test
import (
"context"
@@ -30,8 +30,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/api/activitypub/users"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/api/s2s/user"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -55,13 +55,13 @@ func (suite *UserGetTestSuite) TestGetUser() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
}
@@ -98,7 +98,7 @@ func (suite *UserGetTestSuite) TestGetUser() {
// TestGetUserPublicKeyDeleted checks whether the public key of a deleted account can still be dereferenced.
// This is needed by remote instances for authenticating delete requests and stuff like that.
func (suite *UserGetTestSuite) TestGetUserPublicKeyDeleted() {
userModule := user.New(suite.processor).(*user.Module)
userModule := users.New(suite.processor)
targetAccount := suite.testAccounts["local_account_1"]
// first delete the account, as though zork had deleted himself
@@ -133,13 +133,13 @@ func (suite *UserGetTestSuite) TestGetUserPublicKeyDeleted() {
ctx.Request.Header.Set("Date", signedRequest.DateHeader)
// we need to pass the context through signature check first to set appropriate values on it
suite.securityModule.SignatureCheck(ctx)
suite.signatureCheck(ctx)
// normally the router would populate these params from the path values,
// but because we're calling the function directly, we need to set them manually.
ctx.Params = gin.Params{
gin.Param{
Key: user.UsernameKey,
Key: users.UsernameKey,
Value: targetAccount.Username,
},
}

View File

@@ -1,37 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 api
import (
"github.com/superseriousbusiness/gotosocial/internal/router"
)
// ClientModule represents a chunk of code (usually contained in a single package) that adds a set
// of functionalities and/or side effects to a router, by mapping routes and/or middlewares onto it--in other words, a REST API ;)
// A ClientAPIMpdule with routes corresponds roughly to one main path of the gotosocial REST api, for example /api/v1/accounts/ or /oauth/
type ClientModule interface {
Route(s router.Router) error
}
// FederationModule represents a chunk of code (usually contained in a single package) that adds a set
// of functionalities and/or side effects to a router, by mapping routes and/or middlewares onto it--in other words, a REST API ;)
// Unlike ClientAPIModule, federation API module is not intended to be interacted with by clients directly -- it is primarily a server-to-server interface.
type FederationModule interface {
Route(s router.Router) error
}

64
internal/api/auth.go Normal file
View File

@@ -0,0 +1,64 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 api
import (
"github.com/superseriousbusiness/gotosocial/internal/api/auth"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/oidc"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
type Auth struct {
routerSession *gtsmodel.RouterSession
sessionName string
auth *auth.Module
}
// Route attaches 'auth' and 'oauth' groups to the given router.
func (a *Auth) Route(r router.Router) {
// create groupings for the 'auth' and 'oauth' prefixes
authGroup := r.AttachGroup("auth")
oauthGroup := r.AttachGroup("oauth")
// instantiate + attach shared, non-global middlewares to both of these groups
var (
rateLimitMiddleware = middleware.RateLimit() // nolint:contextcheck
gzipMiddleware = middleware.Gzip()
cacheControlMiddleware = middleware.CacheControl("private", "max-age=120")
sessionMiddleware = middleware.Session(a.sessionName, a.routerSession.Auth, a.routerSession.Crypt)
)
authGroup.Use(rateLimitMiddleware, gzipMiddleware, cacheControlMiddleware, sessionMiddleware)
oauthGroup.Use(rateLimitMiddleware, gzipMiddleware, cacheControlMiddleware, sessionMiddleware)
a.auth.RouteAuth(authGroup.Handle)
a.auth.RouteOauth(oauthGroup.Handle)
}
func NewAuth(db db.DB, p processing.Processor, idp oidc.IDP, routerSession *gtsmodel.RouterSession, sessionName string) *Auth {
return &Auth{
routerSession: routerSession,
sessionName: sessionName,
auth: auth.New(db, p, idp),
}
}

117
internal/api/auth/auth.go Normal file
View File

@@ -0,0 +1,117 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 auth
import (
"net/http"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/oidc"
"github.com/superseriousbusiness/gotosocial/internal/processing"
)
const (
/*
paths prefixed with 'auth'
*/
// AuthSignInPath is the API path for users to sign in through
AuthSignInPath = "/sign_in"
// AuthCheckYourEmailPath users land here after registering a new account, instructs them to confirm their email
AuthCheckYourEmailPath = "/check_your_email"
// AuthWaitForApprovalPath users land here after confirming their email
// but before an admin approves their account (if such is required)
AuthWaitForApprovalPath = "/wait_for_approval"
// AuthAccountDisabledPath users land here when their account is suspended by an admin
AuthAccountDisabledPath = "/account_disabled"
// AuthCallbackPath is the API path for receiving callback tokens from external OIDC providers
AuthCallbackPath = "/callback"
/*
paths prefixed with 'oauth'
*/
// OauthTokenPath is the API path to use for granting token requests to users with valid credentials
OauthTokenPath = "/token" // #nosec G101 else we get a hardcoded credentials warning
// OauthAuthorizePath is the API path for authorization requests (eg., authorize this app to act on my behalf as a user)
OauthAuthorizePath = "/authorize"
// OauthFinalizePath is the API path for completing user registration with additional user details
OauthFinalizePath = "/finalize"
// OauthOobTokenPath is the path for serving an html representation of an oob token page.
OauthOobTokenPath = "/oob" // #nosec G101 else we get a hardcoded credentials warning
/*
params / session keys
*/
callbackStateParam = "state"
callbackCodeParam = "code"
sessionUserID = "userid"
sessionClientID = "client_id"
sessionRedirectURI = "redirect_uri"
sessionForceLogin = "force_login"
sessionResponseType = "response_type"
sessionScope = "scope"
sessionInternalState = "internal_state"
sessionClientState = "client_state"
sessionClaims = "claims"
sessionAppID = "app_id"
)
type Module struct {
db db.DB
processor processing.Processor
idp oidc.IDP
}
// New returns an Auth module which provides both 'oauth' and 'auth' endpoints.
//
// It is safe to pass a nil idp if oidc is disabled.
func New(db db.DB, processor processing.Processor, idp oidc.IDP) *Module {
return &Module{
db: db,
processor: processor,
idp: idp,
}
}
// RouteAuth routes all paths that should have an 'auth' prefix
func (m *Module) RouteAuth(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, AuthSignInPath, m.SignInGETHandler)
attachHandler(http.MethodPost, AuthSignInPath, m.SignInPOSTHandler)
attachHandler(http.MethodGet, AuthCallbackPath, m.CallbackGETHandler)
}
// RouteOauth routes all paths that should have an 'oauth' prefix
func (m *Module) RouteOauth(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodPost, OauthTokenPath, m.TokenPOSTHandler)
attachHandler(http.MethodGet, OauthAuthorizePath, m.AuthorizeGETHandler)
attachHandler(http.MethodPost, OauthAuthorizePath, m.AuthorizePOSTHandler)
attachHandler(http.MethodPost, OauthFinalizePath, m.FinalizePOSTHandler)
attachHandler(http.MethodGet, OauthOobTokenPath, m.OobHandler)
}
func (m *Module) clearSession(s sessions.Session) {
s.Clear()
if err := s.Save(); err != nil {
panic(err)
}
}

View File

@@ -20,7 +20,6 @@ package auth_test
import (
"bytes"
"context"
"fmt"
"net/http/httptest"
@@ -28,7 +27,7 @@ import (
"github.com/gin-contrib/sessions/memstore"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/auth"
"github.com/superseriousbusiness/gotosocial/internal/api/auth"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -37,10 +36,9 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/messages"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/oidc"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
"github.com/superseriousbusiness/gotosocial/internal/storage"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -54,7 +52,6 @@ type AuthStandardTestSuite struct {
processor processing.Processor
emailSender email.Sender
idp oidc.IDP
oauthServer oauth.Server
// standard suite models
testTokens map[string]*gtsmodel.Token
@@ -90,17 +87,10 @@ func (suite *AuthStandardTestSuite) SetupTest() {
suite.db = testrig.NewTestDB()
suite.storage = testrig.NewInMemoryStorage()
suite.mediaManager = testrig.NewTestMediaManager(suite.db, suite.storage)
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../web/template/", nil)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.oauthServer = testrig.NewTestOauthServer(suite.db)
var err error
suite.idp, err = oidc.NewIDP(context.Background())
if err != nil {
panic(err)
}
suite.authModule = auth.New(suite.db, suite.idp, suite.processor).(*auth.Module)
suite.authModule = auth.New(suite.db, suite.processor, suite.idp)
testrig.StandardDBSetup(suite.db, suite.testAccounts)
}
@@ -114,7 +104,7 @@ func (suite *AuthStandardTestSuite) newContext(requestMethod string, requestPath
ctx, engine := testrig.CreateGinTestContext(recorder, nil)
// load templates into the engine
testrig.ConfigureTemplatesWithGin(engine, "../../../../web/template")
testrig.ConfigureTemplatesWithGin(engine, "../../../web/template")
// create the request
protocol := config.GetProtocol()
@@ -131,7 +121,7 @@ func (suite *AuthStandardTestSuite) newContext(requestMethod string, requestPath
// trigger the session middleware on the context
store := memstore.NewStore(make([]byte, 32), make([]byte, 32))
store.Options(router.SessionOptions())
store.Options(middleware.SessionOptions())
sessionMiddleware := sessions.Sessions("gotosocial-localhost", store)
sessionMiddleware(ctx)

View File

@@ -27,8 +27,8 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -42,8 +42,8 @@ import (
func (m *Module) AuthorizeGETHandler(c *gin.Context) {
s := sessions.Default(c)
if _, err := api.NegotiateAccept(c, api.HTMLAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.HTMLAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -51,20 +51,20 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
// If it's not set, then we don't know yet who the user is, so we need to redirect them to the sign in page.
userID, ok := s.Get(sessionUserID).(string)
if !ok || userID == "" {
form := &model.OAuthAuthorize{}
form := &apimodel.OAuthAuthorize{}
if err := c.ShouldBind(form); err != nil {
m.clearSession(s)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
if errWithCode := saveAuthFormToSession(s, form); errWithCode != nil {
m.clearSession(s)
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.Redirect(http.StatusSeeOther, AuthSignInPath)
c.Redirect(http.StatusSeeOther, "/auth"+AuthSignInPath)
return
}
@@ -73,7 +73,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
if !ok || clientID == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionClientID)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -87,7 +87,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -101,7 +101,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -115,7 +115,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -128,7 +128,7 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
if !ok || redirect == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionRedirectURI)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -136,13 +136,13 @@ func (m *Module) AuthorizeGETHandler(c *gin.Context) {
if !ok || scope == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionScope)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -206,7 +206,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
if len(errs) != 0 {
errs = append(errs, oauth.HelpfulAdvice)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during AuthorizePOSTHandler"), errs...), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during AuthorizePOSTHandler"), errs...), m.processor.InstanceGet)
return
}
@@ -220,7 +220,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -234,7 +234,7 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -263,13 +263,13 @@ func (m *Module) AuthorizePOSTHandler(c *gin.Context) {
}
if errWithCode := m.processor.OAuthHandleAuthorizeRequest(c.Writer, c.Request); errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
}
}
// saveAuthFormToSession checks the given OAuthAuthorize form,
// and stores the values in the form into the session.
func saveAuthFormToSession(s sessions.Session, form *model.OAuthAuthorize) gtserror.WithCode {
func saveAuthFormToSession(s sessions.Session, form *apimodel.OAuthAuthorize) gtserror.WithCode {
if form == nil {
err := errors.New("OAuthAuthorize form was nil")
return gtserror.NewErrorBadRequest(err, err.Error(), oauth.HelpfulAdvice)
@@ -314,19 +314,19 @@ func saveAuthFormToSession(s sessions.Session, form *model.OAuthAuthorize) gtser
func ensureUserIsAuthorizedOrRedirect(ctx *gin.Context, user *gtsmodel.User, account *gtsmodel.Account) (redirected bool) {
if user.ConfirmedAt.IsZero() {
ctx.Redirect(http.StatusSeeOther, CheckYourEmailPath)
ctx.Redirect(http.StatusSeeOther, "/auth"+AuthCheckYourEmailPath)
redirected = true
return
}
if !*user.Approved {
ctx.Redirect(http.StatusSeeOther, WaitForApprovalPath)
ctx.Redirect(http.StatusSeeOther, "/auth"+AuthWaitForApprovalPath)
redirected = true
return
}
if *user.Disabled || !account.SuspendedAt.IsZero() {
ctx.Redirect(http.StatusSeeOther, AccountDisabledPath)
ctx.Redirect(http.StatusSeeOther, "/auth"+AuthAccountDisabledPath)
redirected = true
return
}

View File

@@ -9,7 +9,7 @@ import (
"github.com/gin-contrib/sessions"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/auth"
"github.com/superseriousbusiness/gotosocial/internal/api/auth"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -34,7 +34,7 @@ func (suite *AuthAuthorizeTestSuite) TestAccountAuthorizeHandler() {
return []string{"confirmed_at"}
},
expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.CheckYourEmailPath,
expectedLocationHeader: "/auth" + auth.AuthCheckYourEmailPath,
},
{
description: "user has their email confirmed but is not approved",
@@ -44,7 +44,7 @@ func (suite *AuthAuthorizeTestSuite) TestAccountAuthorizeHandler() {
return []string{"confirmed_at", "email"}
},
expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.WaitForApprovalPath,
expectedLocationHeader: "/auth" + auth.AuthWaitForApprovalPath,
},
{
description: "user has their email confirmed and is approved, but User entity has been disabled",
@@ -56,7 +56,7 @@ func (suite *AuthAuthorizeTestSuite) TestAccountAuthorizeHandler() {
return []string{"confirmed_at", "email", "approved", "disabled"}
},
expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.AccountDisabledPath,
expectedLocationHeader: "/auth" + auth.AuthAccountDisabledPath,
},
{
description: "user has their email confirmed and is approved, but Account entity has been suspended",
@@ -69,7 +69,7 @@ func (suite *AuthAuthorizeTestSuite) TestAccountAuthorizeHandler() {
return []string{"confirmed_at", "email", "approved", "disabled"}
},
expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.AccountDisabledPath,
expectedLocationHeader: "/auth" + auth.AuthAccountDisabledPath,
},
}

View File

@@ -29,7 +29,7 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -47,6 +47,12 @@ type extraInfo struct {
// CallbackGETHandler parses a token from an external auth provider.
func (m *Module) CallbackGETHandler(c *gin.Context) {
if !config.GetOIDCEnabled() {
err := errors.New("oidc is not enabled for this server")
apiutil.ErrorHandler(c, gtserror.NewErrorNotFound(err, err.Error()), m.processor.InstanceGet)
return
}
s := sessions.Default(c)
// check the query vs session state parameter to mitigate csrf
@@ -56,7 +62,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if returnedInternalState == "" {
m.clearSession(s)
err := fmt.Errorf("%s parameter not found on callback query", callbackStateParam)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -65,14 +71,14 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if !ok {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionInternalState)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if returnedInternalState != savedInternalState {
m.clearSession(s)
err := errors.New("mismatch between callback state and saved state")
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -81,14 +87,14 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if code == "" {
m.clearSession(s)
err := fmt.Errorf("%s parameter not found on callback query", callbackCodeParam)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
claims, errWithCode := m.idp.HandleCallback(c.Request.Context(), code)
if errWithCode != nil {
m.clearSession(s)
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -98,7 +104,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
if !ok || clientID == "" {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionClientID)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -112,21 +118,21 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
user, errWithCode := m.fetchUserForClaims(c.Request.Context(), claims, net.IP(c.ClientIP()), app.ID)
if errWithCode != nil {
m.clearSession(s)
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
if user == nil {
// no user exists yet - let's ask them for their preferred username
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -135,7 +141,7 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
s.Set(sessionAppID, app.ID)
if err := s.Save(); err != nil {
m.clearSession(s)
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}
c.HTML(http.StatusOK, "finalize.tmpl", gin.H{
@@ -148,10 +154,10 @@ func (m *Module) CallbackGETHandler(c *gin.Context) {
s.Set(sessionUserID, user.ID)
if err := s.Save(); err != nil {
m.clearSession(s)
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}
c.Redirect(http.StatusFound, OauthAuthorizePath)
c.Redirect(http.StatusFound, "/oauth"+OauthAuthorizePath)
}
// FinalizePOSTHandler registers the user after additional data has been provided
@@ -161,7 +167,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
form := &extraInfo{}
if err := c.ShouldBind(form); err != nil {
m.clearSession(s)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -169,7 +175,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
validationError := func(err error) {
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.HTML(http.StatusOK, "finalize.tmpl", gin.H{
@@ -189,7 +195,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
// see if the username is still available
usernameAvailable, err := m.db.IsUsernameAvailable(c.Request.Context(), form.Username)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
if !usernameAvailable {
@@ -201,7 +207,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
appID, ok := s.Get(sessionAppID).(string)
if !ok {
err := fmt.Errorf("key %s was not found in session", sessionAppID)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -209,7 +215,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
claims, ok := s.Get(sessionClaims).(*oidc.Claims)
if !ok {
err := fmt.Errorf("key %s was not found in session", sessionClaims)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -217,7 +223,7 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
user, errWithCode := m.createUserFromOIDC(c.Request.Context(), claims, form, net.IP(c.ClientIP()), appID)
if errWithCode != nil {
m.clearSession(s)
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
s.Delete(sessionClaims)
@@ -225,10 +231,10 @@ func (m *Module) FinalizePOSTHandler(c *gin.Context) {
s.Set(sessionUserID, user.ID)
if err := s.Save(); err != nil {
m.clearSession(s)
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}
c.Redirect(http.StatusFound, OauthAuthorizePath)
c.Redirect(http.StatusFound, "/oauth"+OauthAuthorizePath)
}
func (m *Module) fetchUserForClaims(ctx context.Context, claims *oidc.Claims, ip net.IP, appID string) (*gtsmodel.User, gtserror.WithCode) {

View File

@@ -26,8 +26,8 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -38,16 +38,18 @@ func (m *Module) OobHandler(c *gin.Context) {
host := config.GetHost()
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), host)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
instanceGet := func(ctx context.Context, domain string) (*model.Instance, gtserror.WithCode) { return instance, nil }
instanceGet := func(ctx context.Context, domain string) (*apimodel.Instance, gtserror.WithCode) {
return instance, nil
}
oobToken := c.Query("code")
if oobToken == "" {
err := errors.New("no 'code' query value provided in callback redirect")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error(), oauth.HelpfulAdvice), instanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error(), oauth.HelpfulAdvice), instanceGet)
return
}
@@ -67,7 +69,7 @@ func (m *Module) OobHandler(c *gin.Context) {
if len(errs) != 0 {
errs = append(errs, oauth.HelpfulAdvice)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during OobHandler"), errs...), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(errors.New("one or more missing keys on session during OobHandler"), errs...), m.processor.InstanceGet)
return
}
@@ -81,7 +83,7 @@ func (m *Module) OobHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, instanceGet)
apiutil.ErrorHandler(c, errWithCode, instanceGet)
return
}
@@ -95,7 +97,7 @@ func (m *Module) OobHandler(c *gin.Context) {
} else {
errWithCode = gtserror.NewErrorInternalError(err, safe, oauth.HelpfulAdvice)
}
api.ErrorHandler(c, errWithCode, instanceGet)
apiutil.ErrorHandler(c, errWithCode, instanceGet)
return
}

View File

@@ -26,7 +26,7 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -44,15 +44,15 @@ type login struct {
// The form will then POST to the sign in page, which will be handled by SignInPOSTHandler.
// If an idp provider is set, then the user will be redirected to that to do their sign in.
func (m *Module) SignInGETHandler(c *gin.Context) {
if _, err := api.NegotiateAccept(c, api.HTMLAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.HTMLAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if m.idp == nil {
if !config.GetOIDCEnabled() {
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -71,7 +71,7 @@ func (m *Module) SignInGETHandler(c *gin.Context) {
if !ok {
m.clearSession(s)
err := fmt.Errorf("key %s was not found in session", sessionInternalState)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -87,7 +87,7 @@ func (m *Module) SignInPOSTHandler(c *gin.Context) {
form := &login{}
if err := c.ShouldBind(form); err != nil {
m.clearSession(s)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
return
}
@@ -95,17 +95,17 @@ func (m *Module) SignInPOSTHandler(c *gin.Context) {
if errWithCode != nil {
// don't clear session here, so the user can just press back and try again
// if they accidentally gave the wrong password or something
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
s.Set(sessionUserID, userid)
if err := s.Save(); err != nil {
err := fmt.Errorf("error saving user id onto session: %s", err)
api.ErrorHandler(c, gtserror.NewErrorInternalError(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorInternalError(err, oauth.HelpfulAdvice), m.processor.InstanceGet)
}
c.Redirect(http.StatusFound, OauthAuthorizePath)
c.Redirect(http.StatusFound, "/oauth"+OauthAuthorizePath)
}
// ValidatePassword takes an email address and a password.

View File

@@ -22,7 +22,7 @@ import (
"net/http"
"net/url"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -41,8 +41,8 @@ type tokenRequestForm struct {
// TokenPOSTHandler should be served as a POST at https://example.org/oauth/token
// The idea here is to serve an oauth access token to a user, which can be used for authorizing against non-public APIs.
func (m *Module) TokenPOSTHandler(c *gin.Context) {
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -50,7 +50,7 @@ func (m *Module) TokenPOSTHandler(c *gin.Context) {
form := &tokenRequestForm{}
if err := c.ShouldBind(form); err != nil {
api.OAuthErrorHandler(c, gtserror.NewErrorBadRequest(oauth.InvalidRequest(), err.Error()))
apiutil.OAuthErrorHandler(c, gtserror.NewErrorBadRequest(oauth.InvalidRequest(), err.Error()))
return
}
@@ -99,13 +99,13 @@ func (m *Module) TokenPOSTHandler(c *gin.Context) {
}
if len(help) != 0 {
api.OAuthErrorHandler(c, gtserror.NewErrorBadRequest(oauth.InvalidRequest(), help...))
apiutil.OAuthErrorHandler(c, gtserror.NewErrorBadRequest(oauth.InvalidRequest(), help...))
return
}
token, errWithCode := m.processor.OAuthHandleTokenRequest(c.Request)
if errWithCode != nil {
api.OAuthErrorHandler(c, errWithCode)
apiutil.OAuthErrorHandler(c, errWithCode)
return
}

129
internal/api/client.go Normal file
View File

@@ -0,0 +1,129 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 api
import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
"github.com/superseriousbusiness/gotosocial/internal/api/client/apps"
"github.com/superseriousbusiness/gotosocial/internal/api/client/blocks"
"github.com/superseriousbusiness/gotosocial/internal/api/client/bookmarks"
"github.com/superseriousbusiness/gotosocial/internal/api/client/customemojis"
"github.com/superseriousbusiness/gotosocial/internal/api/client/favourites"
filter "github.com/superseriousbusiness/gotosocial/internal/api/client/filters"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequests"
"github.com/superseriousbusiness/gotosocial/internal/api/client/instance"
"github.com/superseriousbusiness/gotosocial/internal/api/client/lists"
"github.com/superseriousbusiness/gotosocial/internal/api/client/media"
"github.com/superseriousbusiness/gotosocial/internal/api/client/notifications"
"github.com/superseriousbusiness/gotosocial/internal/api/client/search"
"github.com/superseriousbusiness/gotosocial/internal/api/client/statuses"
"github.com/superseriousbusiness/gotosocial/internal/api/client/streaming"
"github.com/superseriousbusiness/gotosocial/internal/api/client/timelines"
"github.com/superseriousbusiness/gotosocial/internal/api/client/user"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
type Client struct {
processor processing.Processor
db db.DB
accounts *accounts.Module // api/v1/accounts
admin *admin.Module // api/v1/admin
apps *apps.Module // api/v1/apps
blocks *blocks.Module // api/v1/blocks
bookmarks *bookmarks.Module // api/v1/bookmarks
customEmojis *customemojis.Module // api/v1/custom_emojis
favourites *favourites.Module // api/v1/favourites
filters *filter.Module // api/v1/filters
followRequests *followrequests.Module // api/v1/follow_requests
instance *instance.Module // api/v1/instance
lists *lists.Module // api/v1/lists
media *media.Module // api/v1/media, api/v2/media
notifications *notifications.Module // api/v1/notifications
search *search.Module // api/v1/search, api/v2/search
statuses *statuses.Module // api/v1/statuses
streaming *streaming.Module // api/v1/streaming
timelines *timelines.Module // api/v1/timelines
user *user.Module // api/v1/user
}
func (c *Client) Route(r router.Router) {
// create a new group on the top level client 'api' prefix
apiGroup := r.AttachGroup("api")
// attach non-global middlewares appropriate to the client api
apiGroup.Use(
middleware.TokenCheck(c.db, c.processor.OAuthValidateBearerToken),
middleware.RateLimit(),
middleware.Gzip(),
middleware.CacheControl("no-store"), // never cache api responses
)
// for each client api module, pass it the Handle function
// so that the module can attach its routes to this group
h := apiGroup.Handle
c.accounts.Route(h)
c.admin.Route(h)
c.apps.Route(h)
c.blocks.Route(h)
c.bookmarks.Route(h)
c.customEmojis.Route(h)
c.favourites.Route(h)
c.filters.Route(h)
c.followRequests.Route(h)
c.instance.Route(h)
c.lists.Route(h)
c.media.Route(h)
c.notifications.Route(h)
c.search.Route(h)
c.statuses.Route(h)
c.streaming.Route(h)
c.timelines.Route(h)
c.user.Route(h)
}
func NewClient(db db.DB, p processing.Processor) *Client {
return &Client{
processor: p,
db: db,
accounts: accounts.New(p),
admin: admin.New(p),
apps: apps.New(p),
blocks: blocks.New(p),
bookmarks: bookmarks.New(p),
customEmojis: customemojis.New(p),
favourites: favourites.New(p),
filters: filter.New(p),
followRequests: followrequests.New(p),
instance: instance.New(p),
lists: lists.New(p),
media: media.New(p),
notifications: notifications.New(p),
search: search.New(p),
statuses: statuses.New(p),
streaming: streaming.New(p),
timelines: timelines.New(p),
user: user.New(p),
}
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"bytes"
@@ -26,7 +26,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -62,7 +62,7 @@ type AccountStandardTestSuite struct {
testStatuses map[string]*gtsmodel.Status
// module being tested
accountModule *account.Module
accountsModule *accounts.Module
}
func (suite *AccountStandardTestSuite) SetupSuite() {
@@ -89,7 +89,7 @@ func (suite *AccountStandardTestSuite) SetupTest() {
suite.sentEmails = make(map[string]string)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", suite.sentEmails)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.accountModule = account.New(suite.processor).(*account.Module)
suite.accountsModule = accounts.New(suite.processor)
testrig.StandardDBSetup(suite.db, nil)
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
@@ -24,8 +24,8 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -73,23 +73,23 @@ import (
func (m *Module) AccountCreatePOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, false, false)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.AccountCreateRequest{}
form := &apimodel.AccountCreateRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if err := validateCreateAccount(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -97,14 +97,14 @@ func (m *Module) AccountCreatePOSTHandler(c *gin.Context) {
signUpIP := net.ParseIP(clientIP)
if signUpIP == nil {
err := errors.New("ip address could not be parsed from request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form.IP = signUpIP
ti, errWithCode := m.processor.AccountCreate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -113,7 +113,7 @@ func (m *Module) AccountCreatePOSTHandler(c *gin.Context) {
// validateCreateAccount checks through all the necessary prerequisites for creating a new account,
// according to the provided account create request. If the account isn't eligible, an error will be returned.
func validateCreateAccount(form *model.AccountCreateRequest) error {
func validateCreateAccount(form *apimodel.AccountCreateRequest) error {
if form == nil {
return errors.New("form was nil")
}

View File

@@ -16,4 +16,4 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// */
package account_test
package accounts_test

View File

@@ -16,15 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -68,26 +68,26 @@ import (
func (m *Module) AccountDeletePOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.AccountDeleteRequest{}
form := &apimodel.AccountDeleteRequest{}
if err := c.ShouldBind(&form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if form.Password == "" {
err = errors.New("no password provided in account delete request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form.DeleteOriginID = authed.Account.ID
if errWithCode := m.processor.AccountDeleteLocal(c.Request.Context(), authed, form); errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"net/http"
@@ -24,7 +24,7 @@ import (
"testing"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -45,10 +45,10 @@ func (suite *AccountDeleteTestSuite) TestAccountDeletePOSTHandler() {
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, account.DeleteAccountPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, accounts.DeleteAccountPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountDeletePOSTHandler(ctx)
suite.accountsModule.AccountDeletePOSTHandler(ctx)
// 1. we should have Accepted because our request was valid
suite.Equal(http.StatusAccepted, recorder.Code)
@@ -67,10 +67,10 @@ func (suite *AccountDeleteTestSuite) TestAccountDeletePOSTHandlerWrongPassword()
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, account.DeleteAccountPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, accounts.DeleteAccountPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountDeletePOSTHandler(ctx)
suite.accountsModule.AccountDeletePOSTHandler(ctx)
// 1. we should have Forbidden because we supplied the wrong password
suite.Equal(http.StatusForbidden, recorder.Code)
@@ -87,10 +87,10 @@ func (suite *AccountDeleteTestSuite) TestAccountDeletePOSTHandlerNoPassword() {
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, account.DeleteAccountPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, accounts.DeleteAccountPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountDeletePOSTHandler(ctx)
suite.accountsModule.AccountDeletePOSTHandler(ctx)
// 1. we should have StatusBadRequest because our request was invalid
suite.Equal(http.StatusBadRequest, recorder.Code)

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -69,25 +69,25 @@ import (
func (m *Module) AccountGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
acctInfo, errWithCode := m.processor.AccountGet(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,17 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
@@ -49,8 +45,8 @@ const (
// IDKey is the key to use for retrieving account ID in requests
IDKey = "id"
// BasePath is the base API path for this module
BasePath = "/api/v1/accounts"
// BasePath is the base API path for this module, excluding the 'api' prefix
BasePath = "/v1/accounts"
// BasePathWithID is the base path for this module with the ID key
BasePathWithID = BasePath + "/:" + IDKey
// VerifyPath is for verifying account credentials
@@ -77,65 +73,47 @@ const (
DeleteAccountPath = BasePath + "/delete"
)
// Module implements the ClientAPIModule interface for account-related actions
type Module struct {
processor processing.Processor
}
// New returns a new account module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
// create account
r.AttachHandler(http.MethodPost, BasePath, m.AccountCreatePOSTHandler)
// delete account
r.AttachHandler(http.MethodPost, DeleteAccountPath, m.AccountDeletePOSTHandler)
attachHandler(http.MethodPost, BasePath, m.AccountCreatePOSTHandler)
// get account
r.AttachHandler(http.MethodGet, BasePathWithID, m.muxHandler)
attachHandler(http.MethodGet, BasePathWithID, m.AccountGETHandler)
// delete account
attachHandler(http.MethodPost, DeleteAccountPath, m.AccountDeletePOSTHandler)
// verify account
attachHandler(http.MethodGet, VerifyPath, m.AccountVerifyGETHandler)
// modify account
r.AttachHandler(http.MethodPatch, BasePathWithID, m.muxHandler)
attachHandler(http.MethodPatch, UpdateCredentialsPath, m.AccountUpdateCredentialsPATCHHandler)
// get account's statuses
r.AttachHandler(http.MethodGet, GetStatusesPath, m.AccountStatusesGETHandler)
attachHandler(http.MethodGet, GetStatusesPath, m.AccountStatusesGETHandler)
// get following or followers
r.AttachHandler(http.MethodGet, GetFollowersPath, m.AccountFollowersGETHandler)
r.AttachHandler(http.MethodGet, GetFollowingPath, m.AccountFollowingGETHandler)
attachHandler(http.MethodGet, GetFollowersPath, m.AccountFollowersGETHandler)
attachHandler(http.MethodGet, GetFollowingPath, m.AccountFollowingGETHandler)
// get relationship with account
r.AttachHandler(http.MethodGet, GetRelationshipsPath, m.AccountRelationshipsGETHandler)
attachHandler(http.MethodGet, GetRelationshipsPath, m.AccountRelationshipsGETHandler)
// follow or unfollow account
r.AttachHandler(http.MethodPost, FollowPath, m.AccountFollowPOSTHandler)
r.AttachHandler(http.MethodPost, UnfollowPath, m.AccountUnfollowPOSTHandler)
attachHandler(http.MethodPost, FollowPath, m.AccountFollowPOSTHandler)
attachHandler(http.MethodPost, UnfollowPath, m.AccountUnfollowPOSTHandler)
// block or unblock account
r.AttachHandler(http.MethodPost, BlockPath, m.AccountBlockPOSTHandler)
r.AttachHandler(http.MethodPost, UnblockPath, m.AccountUnblockPOSTHandler)
return nil
}
func (m *Module) muxHandler(c *gin.Context) {
ru := c.Request.RequestURI
switch c.Request.Method {
case http.MethodGet:
if strings.HasPrefix(ru, VerifyPath) {
m.AccountVerifyGETHandler(c)
} else {
m.AccountGETHandler(c)
}
case http.MethodPatch:
if strings.HasPrefix(ru, UpdateCredentialsPath) {
m.AccountUpdateCredentialsPATCHHandler(c)
}
}
attachHandler(http.MethodPost, BlockPath, m.AccountBlockPOSTHandler)
attachHandler(http.MethodPost, UnblockPath, m.AccountUnblockPOSTHandler)
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
@@ -25,8 +25,8 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -138,33 +138,33 @@ import (
func (m *Module) AccountUpdateCredentialsPATCHHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
form, err := parseUpdateAccountForm(c)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
acctSensitive, errWithCode := m.processor.AccountUpdate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, acctSensitive)
}
func parseUpdateAccountForm(c *gin.Context) (*model.UpdateCredentialsRequest, error) {
form := &model.UpdateCredentialsRequest{
Source: &model.UpdateSource{},
func parseUpdateAccountForm(c *gin.Context) (*apimodel.UpdateCredentialsRequest, error) {
form := &apimodel.UpdateCredentialsRequest{
Source: &apimodel.UpdateSource{},
}
if err := c.ShouldBind(&form); err != nil {

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"context"
@@ -27,7 +27,7 @@ import (
"testing"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -50,10 +50,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandler()
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -89,10 +89,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUnl
}
bodyBytes1 := requestBody1.Bytes()
recorder1 := httptest.NewRecorder()
ctx1 := suite.newContext(recorder1, http.MethodPatch, bodyBytes1, account.UpdateCredentialsPath, w1.FormDataContentType())
ctx1 := suite.newContext(recorder1, http.MethodPatch, bodyBytes1, accounts.UpdateCredentialsPath, w1.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx1)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx1)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder1.Code)
@@ -125,10 +125,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUnl
}
bodyBytes2 := requestBody2.Bytes()
recorder2 := httptest.NewRecorder()
ctx2 := suite.newContext(recorder2, http.MethodPatch, bodyBytes2, account.UpdateCredentialsPath, w2.FormDataContentType())
ctx2 := suite.newContext(recorder2, http.MethodPatch, bodyBytes2, accounts.UpdateCredentialsPath, w2.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx2)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx2)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder1.Code)
@@ -170,10 +170,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerGet
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -212,10 +212,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerTwo
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -266,10 +266,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerWit
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -308,10 +308,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerEmp
// set up the request
bodyBytes := []byte{}
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, "")
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, "")
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusBadRequest, recorder.Code)
@@ -343,10 +343,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpd
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -385,10 +385,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpd
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -430,10 +430,10 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpd
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, accounts.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.accountsModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.Equal(http.StatusBadRequest, recorder.Code)

View File

@@ -16,13 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -59,18 +59,18 @@ import (
func (m *Module) AccountVerifyGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
acctSensitive, errWithCode := m.processor.AccountGet(c.Request.Context(), authed, authed.Account.ID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"encoding/json"
@@ -28,7 +28,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
@@ -42,10 +42,10 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
// set up the request
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodGet, nil, account.VerifyPath, "")
ctx := suite.newContext(recorder, http.MethodGet, nil, accounts.VerifyPath, "")
// call the handler
suite.accountModule.AccountVerifyGETHandler(ctx)
suite.accountsModule.AccountVerifyGETHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -69,25 +69,25 @@ import (
func (m *Module) AccountBlockPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.AccountBlockCreate(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"fmt"
@@ -29,7 +29,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -46,16 +46,16 @@ func (suite *BlockTestSuite) TestBlockSelf() {
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(account.BlockPath, ":id", testAcct.ID, 1)), nil)
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(accounts.BlockPath, ":id", testAcct.ID, 1)), nil)
ctx.Params = gin.Params{
gin.Param{
Key: account.IDKey,
Key: accounts.IDKey,
Value: testAcct.ID,
},
}
suite.accountModule.AccountBlockPOSTHandler(ctx)
suite.accountsModule.AccountBlockPOSTHandler(ctx)
// 1. status should be Not Acceptable due to attempted self-block
suite.Equal(http.StatusNotAcceptable, recorder.Code)

View File

@@ -16,15 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -91,32 +91,32 @@ import (
func (m *Module) AccountFollowPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.AccountFollowRequest{}
form := &apimodel.AccountFollowRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form.ID = targetAcctID
relationship, errWithCode := m.processor.AccountFollowCreate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"fmt"
@@ -29,7 +29,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
@@ -46,17 +46,17 @@ func (suite *FollowTestSuite) TestFollowSelf() {
ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"]))
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(account.FollowPath, ":id", testAcct.ID, 1)), nil)
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(accounts.FollowPath, ":id", testAcct.ID, 1)), nil)
ctx.Params = gin.Params{
gin.Param{
Key: account.IDKey,
Key: accounts.IDKey,
Value: testAcct.ID,
},
}
// call the handler
suite.accountModule.AccountFollowPOSTHandler(ctx)
suite.accountsModule.AccountFollowPOSTHandler(ctx)
// 1. status should be Not Acceptable due to self-follow attempt
suite.Equal(http.StatusNotAcceptable, recorder.Code)

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -72,25 +72,25 @@ import (
func (m *Module) AccountFollowersGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
followers, errWithCode := m.processor.AccountFollowersGet(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -72,25 +72,25 @@ import (
func (m *Module) AccountFollowingGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
following, errWithCode := m.processor.AccountFollowingGet(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -1,12 +1,12 @@
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -57,12 +57,12 @@ import (
func (m *Module) AccountRelationshipsGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -72,18 +72,18 @@ func (m *Module) AccountRelationshipsGETHandler(c *gin.Context) {
id := c.Query("id")
if id == "" {
err = errors.New("no account id(s) specified in query")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
targetAccountIDs = append(targetAccountIDs, id)
}
relationships := []model.Relationship{}
relationships := []apimodel.Relationship{}
for _, targetAccountID := range targetAccountIDs {
r, errWithCode := m.processor.AccountRelationshipGet(c.Request.Context(), authed, targetAccountID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
relationships = append(relationships, *r)

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
@@ -25,7 +25,7 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -133,19 +133,19 @@ import (
func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, false, false, false, false)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -155,7 +155,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
i, err := strconv.ParseInt(limitString, 10, 32)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
limit = int(i)
@@ -167,7 +167,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(excludeRepliesString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", ExcludeRepliesKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
excludeReplies = i
@@ -179,7 +179,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(excludeReblogsString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", ExcludeReblogsKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
excludeReblogs = i
@@ -203,7 +203,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(pinnedString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", PinnedKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
pinnedOnly = i
@@ -215,7 +215,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(mediaOnlyString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", OnlyMediaKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
mediaOnly = i
@@ -227,7 +227,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(publicOnlyString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", OnlyPublicKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
publicOnly = i
@@ -235,7 +235,7 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
resp, errWithCode := m.processor.AccountStatusesGet(c.Request.Context(), authed, targetAcctID, limit, excludeReplies, excludeReblogs, maxID, minID, pinnedOnly, mediaOnly, publicOnly)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account_test
package accounts_test
import (
"encoding/json"
@@ -29,7 +29,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
)
@@ -45,13 +45,13 @@ func (suite *AccountStatusesTestSuite) TestGetStatusesPublicOnly() {
ctx := suite.newContext(recorder, http.MethodGet, nil, fmt.Sprintf("/api/v1/accounts/%s/statuses?limit=20&only_media=false&only_public=true", targetAccount.ID), "")
ctx.Params = gin.Params{
gin.Param{
Key: account.IDKey,
Key: accounts.IDKey,
Value: targetAccount.ID,
},
}
// call the handler
suite.accountModule.AccountStatusesGETHandler(ctx)
suite.accountsModule.AccountStatusesGETHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
@@ -85,13 +85,13 @@ func (suite *AccountStatusesTestSuite) TestGetStatusesPublicOnlyMediaOnly() {
ctx := suite.newContext(recorder, http.MethodGet, nil, fmt.Sprintf("/api/v1/accounts/%s/statuses?limit=20&only_media=true&only_public=true", targetAccount.ID), "")
ctx.Params = gin.Params{
gin.Param{
Key: account.IDKey,
Key: accounts.IDKey,
Value: targetAccount.ID,
},
}
// call the handler
suite.accountModule.AccountStatusesGETHandler(ctx)
suite.accountsModule.AccountStatusesGETHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -70,25 +70,25 @@ import (
func (m *Module) AccountUnblockPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.AccountBlockRemove(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package account
package accounts
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -70,25 +70,25 @@ import (
func (m *Module) AccountUnfollowPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.AccountFollowRemove(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -24,8 +24,8 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -85,38 +85,38 @@ import (
func (m *Module) AccountActionPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.AdminAccountActionRequest{}
form := &apimodel.AdminAccountActionRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if form.Type == "" {
err := errors.New("no type specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form.TargetAccountID = targetAcctID
if errWithCode := m.processor.AdminAccountAction(c.Request.Context(), authed, form); errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -21,14 +21,13 @@ package admin
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// BasePath is the base API path for this module.
BasePath = "/api/v1/admin"
// BasePath is the base API path for this module, excluding the api prefix
BasePath = "/v1/admin"
// EmojiPath is used for posting/deleting custom emojis.
EmojiPath = BasePath + "/custom_emojis"
// EmojiPathWithID is used for interacting with a single emoji.
@@ -68,32 +67,28 @@ const (
DomainQueryKey = "domain"
)
// Module implements the ClientAPIModule interface for admin-related actions (reports, emojis, etc)
type Module struct {
processor processing.Processor
}
// New returns a new admin module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodPost, EmojiPath, m.EmojiCreatePOSTHandler)
r.AttachHandler(http.MethodGet, EmojiPath, m.EmojisGETHandler)
r.AttachHandler(http.MethodDelete, EmojiPathWithID, m.EmojiDELETEHandler)
r.AttachHandler(http.MethodGet, EmojiPathWithID, m.EmojiGETHandler)
r.AttachHandler(http.MethodPatch, EmojiPathWithID, m.EmojiPATCHHandler)
r.AttachHandler(http.MethodPost, DomainBlocksPath, m.DomainBlocksPOSTHandler)
r.AttachHandler(http.MethodGet, DomainBlocksPath, m.DomainBlocksGETHandler)
r.AttachHandler(http.MethodGet, DomainBlocksPathWithID, m.DomainBlockGETHandler)
r.AttachHandler(http.MethodDelete, DomainBlocksPathWithID, m.DomainBlockDELETEHandler)
r.AttachHandler(http.MethodPost, AccountsActionPath, m.AccountActionPOSTHandler)
r.AttachHandler(http.MethodPost, MediaCleanupPath, m.MediaCleanupPOSTHandler)
r.AttachHandler(http.MethodPost, MediaRefetchPath, m.MediaRefetchPOSTHandler)
r.AttachHandler(http.MethodGet, EmojiCategoriesPath, m.EmojiCategoriesGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodPost, EmojiPath, m.EmojiCreatePOSTHandler)
attachHandler(http.MethodGet, EmojiPath, m.EmojisGETHandler)
attachHandler(http.MethodDelete, EmojiPathWithID, m.EmojiDELETEHandler)
attachHandler(http.MethodGet, EmojiPathWithID, m.EmojiGETHandler)
attachHandler(http.MethodPatch, EmojiPathWithID, m.EmojiPATCHHandler)
attachHandler(http.MethodPost, DomainBlocksPath, m.DomainBlocksPOSTHandler)
attachHandler(http.MethodGet, DomainBlocksPath, m.DomainBlocksGETHandler)
attachHandler(http.MethodGet, DomainBlocksPathWithID, m.DomainBlockGETHandler)
attachHandler(http.MethodDelete, DomainBlocksPathWithID, m.DomainBlockDELETEHandler)
attachHandler(http.MethodPost, AccountsActionPath, m.AccountActionPOSTHandler)
attachHandler(http.MethodPost, MediaCleanupPath, m.MediaCleanupPOSTHandler)
attachHandler(http.MethodPost, MediaRefetchPath, m.MediaRefetchPOSTHandler)
attachHandler(http.MethodGet, EmojiCategoriesPath, m.EmojiCategoriesGETHandler)
}

View File

@@ -93,7 +93,7 @@ func (suite *AdminStandardTestSuite) SetupTest() {
suite.sentEmails = make(map[string]string)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", suite.sentEmails)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.adminModule = admin.New(suite.processor).(*admin.Module)
suite.adminModule = admin.New(suite.processor)
testrig.StandardDBSetup(suite.db, nil)
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")
}

View File

@@ -25,8 +25,8 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -126,18 +126,18 @@ import (
func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -147,21 +147,21 @@ func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) {
i, err := strconv.ParseBool(importString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", ImportQueryKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
imp = i
}
form := &model.DomainBlockCreateRequest{}
form := &apimodel.DomainBlockCreateRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if err := validateCreateDomainBlock(form, imp); err != nil {
err := fmt.Errorf("error validating form: %s", err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -169,7 +169,7 @@ func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) {
// we're importing multiple blocks
domainBlocks, errWithCode := m.processor.AdminDomainBlocksImport(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, domainBlocks)
@@ -179,13 +179,13 @@ func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) {
// we're just creating one block
domainBlock, errWithCode := m.processor.AdminDomainBlockCreate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, domainBlock)
}
func validateCreateDomainBlock(form *model.DomainBlockCreateRequest, imp bool) error {
func validateCreateDomainBlock(form *apimodel.DomainBlockCreateRequest, imp bool) error {
if imp {
if form.Domains.Size == 0 {
return errors.New("import was specified but list of domains is empty")

View File

@@ -24,7 +24,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -72,31 +72,31 @@ import (
func (m *Module) DomainBlockDELETEHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
domainBlockID := c.Param(IDKey)
if domainBlockID == "" {
err := errors.New("no domain block id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
domainBlock, errWithCode := m.processor.AdminDomainBlockDelete(c.Request.Context(), authed, domainBlockID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -25,7 +25,7 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -73,25 +73,25 @@ import (
func (m *Module) DomainBlockGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
domainBlockID := c.Param(IDKey)
if domainBlockID == "" {
err := errors.New("no domain block id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -101,7 +101,7 @@ func (m *Module) DomainBlockGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(exportString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", ExportQueryKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
export = i
@@ -109,7 +109,7 @@ func (m *Module) DomainBlockGETHandler(c *gin.Context) {
domainBlock, errWithCode := m.processor.AdminDomainBlockGet(c.Request.Context(), authed, domainBlockID, export)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -24,7 +24,7 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -78,18 +78,18 @@ import (
func (m *Module) DomainBlocksGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -99,7 +99,7 @@ func (m *Module) DomainBlocksGETHandler(c *gin.Context) {
i, err := strconv.ParseBool(exportString)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", ExportQueryKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
export = i
@@ -107,7 +107,7 @@ func (m *Module) DomainBlocksGETHandler(c *gin.Context) {
domainBlocks, errWithCode := m.processor.AdminDomainBlocksGet(c.Request.Context(), authed, export)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -23,7 +23,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -69,24 +69,24 @@ import (
func (m *Module) EmojiCategoriesGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
categories, errWithCode := m.processor.AdminEmojiCategoriesGet(c.Request.Context())
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -24,8 +24,8 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -100,42 +100,42 @@ import (
func (m *Module) EmojiCreatePOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.EmojiCreateRequest{}
form := &apimodel.EmojiCreateRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if err := validateCreateEmoji(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
apiEmoji, errWithCode := m.processor.AdminEmojiCreate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, apiEmoji)
}
func validateCreateEmoji(form *model.EmojiCreateRequest) error {
func validateCreateEmoji(form *apimodel.EmojiCreateRequest) error {
if form.Image == nil || form.Image.Size == 0 {
return errors.New("no emoji given")
}

View File

@@ -24,7 +24,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -78,31 +78,31 @@ import (
func (m *Module) EmojiDELETEHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
emojiID := c.Param(IDKey)
if emojiID == "" {
err := errors.New("no emoji id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
emoji, errWithCode := m.processor.AdminEmojiDelete(c.Request.Context(), authed, emojiID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -24,7 +24,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -68,31 +68,31 @@ import (
func (m *Module) EmojiGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
emojiID := c.Param(IDKey)
if emojiID == "" {
err := errors.New("no emoji id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
emoji, errWithCode := m.processor.AdminEmojiGet(c.Request.Context(), authed, emojiID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -25,7 +25,7 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -125,18 +125,18 @@ import (
func (m *Module) EmojisGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -149,7 +149,7 @@ func (m *Module) EmojisGETHandler(c *gin.Context) {
i, err := strconv.ParseInt(limitString, 10, 32)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
limit = int(i)
@@ -177,7 +177,7 @@ func (m *Module) EmojisGETHandler(c *gin.Context) {
shortcode = strings.Trim(filter[10:], ":") // remove any errant ":"
default:
err := fmt.Errorf("filter %s not recognized; accepted values are 'domain:[domain]', 'disabled', 'enabled', 'shortcode:[shortcode]'", filter)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
}
@@ -200,7 +200,7 @@ func (m *Module) EmojisGETHandler(c *gin.Context) {
resp, errWithCode := m.processor.AdminEmojisGet(c.Request.Context(), authed, domain, includeDisabled, includeEnabled, shortcode, maxShortcodeDomain, minShortcodeDomain, limit)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -25,8 +25,8 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -123,42 +123,42 @@ import (
func (m *Module) EmojiPATCHHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
emojiID := c.Param(IDKey)
if emojiID == "" {
err := errors.New("no emoji id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.EmojiUpdateRequest{}
form := &apimodel.EmojiUpdateRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if err := validateUpdateEmoji(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
emoji, errWithCode := m.processor.AdminEmojiUpdate(c.Request.Context(), emojiID, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@@ -166,14 +166,14 @@ func (m *Module) EmojiPATCHHandler(c *gin.Context) {
}
// do a first pass on the form here
func validateUpdateEmoji(form *model.EmojiUpdateRequest) error {
func validateUpdateEmoji(form *apimodel.EmojiUpdateRequest) error {
// check + normalize update type so we don't need
// to do this trimming + lowercasing again later
switch strings.TrimSpace(strings.ToLower(string(form.Type))) {
case string(model.EmojiUpdateDisable):
case string(apimodel.EmojiUpdateDisable):
// no params required for this one, so don't bother checking
form.Type = model.EmojiUpdateDisable
case string(model.EmojiUpdateCopy):
form.Type = apimodel.EmojiUpdateDisable
case string(apimodel.EmojiUpdateCopy):
// need at least a valid shortcode when doing a copy
if form.Shortcode == nil {
return errors.New("emoji action type was 'copy' but no shortcode was provided")
@@ -190,8 +190,8 @@ func validateUpdateEmoji(form *model.EmojiUpdateRequest) error {
}
}
form.Type = model.EmojiUpdateCopy
case string(model.EmojiUpdateModify):
form.Type = apimodel.EmojiUpdateCopy
case string(apimodel.EmojiUpdateModify):
// need either image or category name for modify
hasImage := form.Image != nil && form.Image.Size != 0
hasCategoryName := form.CategoryName != nil
@@ -212,7 +212,7 @@ func validateUpdateEmoji(form *model.EmojiUpdateRequest) error {
}
}
form.Type = model.EmojiUpdateModify
form.Type = apimodel.EmojiUpdateModify
default:
return errors.New("emoji action type must be one of 'disable', 'copy', 'modify'")
}

View File

@@ -23,8 +23,8 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -71,19 +71,19 @@ import (
func (m *Module) MediaCleanupPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.MediaCleanupRequest{}
form := &apimodel.MediaCleanupRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -98,7 +98,7 @@ func (m *Module) MediaCleanupPOSTHandler(c *gin.Context) {
}
if errWithCode := m.processor.AdminMediaPrune(c.Request.Context(), remoteCacheDays); errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -23,7 +23,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -74,18 +74,18 @@ import (
func (m *Module) MediaRefetchPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
if errWithCode := m.processor.AdminMediaRefetch(c.Request.Context(), authed, c.Query(DomainQueryKey)); errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -1,21 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 app_test
// TODO: write tests

View File

@@ -16,15 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package app
package apps
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -77,48 +77,48 @@ const (
func (m *Module) AppsPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, false, false, false, false)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.ApplicationCreateRequest{}
form := &apimodel.ApplicationCreateRequest{}
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if len([]rune(form.ClientName)) > formFieldLen {
err := fmt.Errorf("client_name must be less than %d characters", formFieldLen)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if len([]rune(form.RedirectURIs)) > formRedirectLen {
err := fmt.Errorf("redirect_uris must be less than %d characters", formRedirectLen)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if len([]rune(form.Scopes)) > formFieldLen {
err := fmt.Errorf("scopes must be less than %d characters", formFieldLen)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if len([]rune(form.Website)) > formFieldLen {
err := fmt.Errorf("website must be less than %d characters", formFieldLen)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
apiApp, errWithCode := m.processor.AppCreate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,20 +16,28 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package security
package apps
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
)
// UserAgentBlock aborts requests with empty user agent strings.
func (m *Module) UserAgentBlock(c *gin.Context) {
if ua := c.Request.UserAgent(); ua == "" {
code := http.StatusTeapot
err := errors.New(http.StatusText(code) + ": no user-agent sent with request")
c.AbortWithStatusJSON(code, gin.H{"error": err.Error()})
// BasePath is the base path for this api module, excluding the api prefix
const BasePath = "/v1/apps"
type Module struct {
processor processing.Processor
}
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodPost, BasePath, m.AppsPOSTHandler)
}

View File

@@ -1,105 +0,0 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 auth
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/oidc"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
/* #nosec G101 */
const (
// AuthSignInPath is the API path for users to sign in through
AuthSignInPath = "/auth/sign_in"
// CheckYourEmailPath users land here after registering a new account, instructs them to confirm thier email
CheckYourEmailPath = "/check_your_email"
// WaitForApprovalPath users land here after confirming thier email but before an admin approves thier account
// (if such is required)
WaitForApprovalPath = "/wait_for_approval"
// AccountDisabledPath users land here when thier account is suspended by an admin
AccountDisabledPath = "/account_disabled"
// OauthTokenPath is the API path to use for granting token requests to users with valid credentials
OauthTokenPath = "/oauth/token"
// OauthAuthorizePath is the API path for authorization requests (eg., authorize this app to act on my behalf as a user)
OauthAuthorizePath = "/oauth/authorize"
// OauthFinalizePath is the API path for completing user registration with additional user details
OauthFinalizePath = "/oauth/finalize"
// CallbackPath is the API path for receiving callback tokens from external OIDC providers
CallbackPath = oidc.CallbackPath
callbackStateParam = "state"
callbackCodeParam = "code"
sessionUserID = "userid"
sessionClientID = "client_id"
sessionRedirectURI = "redirect_uri"
sessionForceLogin = "force_login"
sessionResponseType = "response_type"
sessionScope = "scope"
sessionInternalState = "internal_state"
sessionClientState = "client_state"
sessionClaims = "claims"
sessionAppID = "app_id"
)
// Module implements the ClientAPIModule interface for
type Module struct {
db db.DB
idp oidc.IDP
processor processing.Processor
}
// New returns a new auth module
func New(db db.DB, idp oidc.IDP, processor processing.Processor) api.ClientModule {
return &Module{
db: db,
idp: idp,
processor: processor,
}
}
// Route satisfies the RESTAPIModule interface
func (m *Module) Route(s router.Router) error {
s.AttachHandler(http.MethodGet, AuthSignInPath, m.SignInGETHandler)
s.AttachHandler(http.MethodPost, AuthSignInPath, m.SignInPOSTHandler)
s.AttachHandler(http.MethodPost, OauthTokenPath, m.TokenPOSTHandler)
s.AttachHandler(http.MethodGet, OauthAuthorizePath, m.AuthorizeGETHandler)
s.AttachHandler(http.MethodPost, OauthAuthorizePath, m.AuthorizePOSTHandler)
s.AttachHandler(http.MethodGet, CallbackPath, m.CallbackGETHandler)
s.AttachHandler(http.MethodPost, OauthFinalizePath, m.FinalizePOSTHandler)
s.AttachHandler(http.MethodGet, oauth.OOBTokenPath, m.OobHandler)
return nil
}

View File

@@ -21,14 +21,13 @@ package blocks
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// BasePath is the base URI path for serving favourites
BasePath = "/api/v1/blocks"
// BasePath is the base URI path for serving blocks, minus the api prefix.
BasePath = "/v1/blocks"
// MaxIDKey is the url query for setting a max ID to return
MaxIDKey = "max_id"
@@ -38,20 +37,16 @@ const (
LimitKey = "limit"
)
// Module implements the ClientAPIModule interface for everything relating to viewing blocks
type Module struct {
processor processing.Processor
}
// New returns a new blocks module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodGet, BasePath, m.BlocksGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.BlocksGETHandler)
}

View File

@@ -24,7 +24,7 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -96,12 +96,12 @@ import (
func (m *Module) BlocksGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -123,7 +123,7 @@ func (m *Module) BlocksGETHandler(c *gin.Context) {
i, err := strconv.ParseInt(limitString, 10, 32)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
limit = int(i)
@@ -131,7 +131,7 @@ func (m *Module) BlocksGETHandler(c *gin.Context) {
resp, errWithCode := m.processor.BlocksGet(c.Request.Context(), authed, maxID, sinceID, limit)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -21,9 +21,8 @@ package bookmarks
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
@@ -31,20 +30,16 @@ const (
BasePath = "/api/v1/bookmarks"
)
// Module implements the ClientAPIModule interface for everything related to bookmarks
type Module struct {
processor processing.Processor
}
// New returns a new emoji module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodGet, BasePath, m.BookmarksGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.BookmarksGETHandler)
}

View File

@@ -29,7 +29,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/bookmarks"
"github.com/superseriousbusiness/gotosocial/internal/api/client/status"
"github.com/superseriousbusiness/gotosocial/internal/api/client/statuses"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -67,7 +67,7 @@ type BookmarkTestSuite struct {
testFollows map[string]*gtsmodel.Follow
// module being tested
statusModule *status.Module
statusModule *statuses.Module
bookmarkModule *bookmarks.Module
}
@@ -99,8 +99,8 @@ func (suite *BookmarkTestSuite) SetupTest() {
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.statusModule = status.New(suite.processor).(*status.Module)
suite.bookmarkModule = bookmarks.New(suite.processor).(*bookmarks.Module)
suite.statusModule = statuses.New(suite.processor)
suite.bookmarkModule = bookmarks.New(suite.processor)
suite.NoError(suite.processor.Start())
}
@@ -123,7 +123,7 @@ func (suite *BookmarkTestSuite) TestGetBookmark() {
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"])
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(status.BookmarkPath, ":id", targetStatus.ID, 1)), nil) // the endpoint we're hitting
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080%s", strings.Replace(statuses.BookmarkPath, ":id", targetStatus.ID, 1)), nil) // the endpoint we're hitting
ctx.Request.Header.Set("accept", "application/json")
suite.bookmarkModule.BookmarksGETHandler(ctx)

View File

@@ -6,7 +6,7 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -56,12 +56,12 @@ const (
func (m *Module) BookmarksGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -71,7 +71,7 @@ func (m *Module) BookmarksGETHandler(c *gin.Context) {
i, err := strconv.ParseInt(limitString, 10, 64)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
limit = int(i)
@@ -91,12 +91,12 @@ func (m *Module) BookmarksGETHandler(c *gin.Context) {
resp, errWithCode := m.processor.BookmarksGet(c.Request.Context(), authed, maxID, minID, limit)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,33 +16,30 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package app
package customemojis
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
// BasePath is the base path for this api module
const BasePath = "/api/v1/apps"
const (
// BasePath is the base path for serving custom emojis, minus the 'api' prefix
BasePath = "/v1/custom_emojis"
)
// Module implements the ClientAPIModule interface for requests relating to registering/removing applications
type Module struct {
processor processing.Processor
}
// New returns a new auth module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route satisfies the RESTAPIModule interface
func (m *Module) Route(s router.Router) error {
s.AttachHandler(http.MethodPost, BasePath, m.AppsPOSTHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.CustomEmojisGETHandler)
}

View File

@@ -0,0 +1,76 @@
/*
GoToSocial
Copyright (C) 2021-2022 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 customemojis
import (
"net/http"
"github.com/gin-gonic/gin"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
// CustomEmojisGETHandler swagger:operation GET /api/v1/custom_emojis customEmojisGet
//
// Get an array of custom emojis available on the instance.
//
// ---
// tags:
// - custom_emojis
//
// produces:
// - application/json
//
// security:
// - OAuth2 Bearer:
// - read:custom_emojis
//
// responses:
// '200':
// description: Array of custom emojis.
// schema:
// type: array
// items:
// "$ref": "#/definitions/emoji"
// '401':
// description: unauthorized
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) CustomEmojisGETHandler(c *gin.Context) {
if _, err := oauth.Authed(c, true, true, true, true); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
emojis, errWithCode := m.processor.CustomEmojisGet(c)
if errWithCode != nil {
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, emojis)
}

View File

@@ -1,58 +0,0 @@
package emoji
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
// EmojisGETHandler swagger:operation GET /api/v1/custom_emojis customEmojisGet
//
// Get an array of custom emojis available on the instance.
//
// ---
// tags:
// - custom_emojis
//
// produces:
// - application/json
//
// security:
// - OAuth2 Bearer:
// - read:custom_emojis
//
// responses:
// '200':
// description: Array of custom emojis.
// schema:
// type: array
// items:
// "$ref": "#/definitions/emoji"
// '401':
// description: unauthorized
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) EmojisGETHandler(c *gin.Context) {
if _, err := oauth.Authed(c, true, true, true, true); err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
emojis, errWithCode := m.processor.CustomEmojisGet(c)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, emojis)
}

View File

@@ -21,14 +21,13 @@ package favourites
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// BasePath is the base URI path for serving favourites
BasePath = "/api/v1/favourites"
// BasePath is the base URI path for serving favourites, minus the 'api' prefix
BasePath = "/v1/favourites"
// MaxIDKey is the url query for setting a max status ID to return
MaxIDKey = "max_id"
@@ -42,20 +41,16 @@ const (
LocalKey = "local"
)
// Module implements the ClientAPIModule interface for everything relating to viewing favourites
type Module struct {
processor processing.Processor
}
// New returns a new favourites module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodGet, BasePath, m.FavouritesGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.FavouritesGETHandler)
}

View File

@@ -87,7 +87,7 @@ func (suite *FavouritesStandardTestSuite) SetupTest() {
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.favModule = favourites.New(suite.processor).(*favourites.Module)
suite.favModule = favourites.New(suite.processor)
suite.NoError(suite.processor.Start())
}

View File

@@ -6,7 +6,7 @@ import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -78,12 +78,12 @@ import (
func (m *Module) FavouritesGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -105,7 +105,7 @@ func (m *Module) FavouritesGETHandler(c *gin.Context) {
i, err := strconv.ParseInt(limitString, 10, 32)
if err != nil {
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
limit = int(i)
@@ -113,7 +113,7 @@ func (m *Module) FavouritesGETHandler(c *gin.Context) {
resp, errWithCode := m.processor.FavedTimelineGet(c.Request.Context(), authed, maxID, minID, limit)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -21,30 +21,25 @@ package filter
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// BasePath is the base path for serving the filter API
BasePath = "/api/v1/filters"
// BasePath is the base path for serving the filters API, minus the 'api' prefix
BasePath = "/v1/filters"
)
// Module implements the ClientAPIModule interface for every related to filters
type Module struct {
processor processing.Processor
}
// New returns a new filter module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodGet, BasePath, m.FiltersGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.FiltersGETHandler)
}

View File

@@ -4,7 +4,7 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -12,12 +12,12 @@ import (
// FiltersGETHandler returns a list of filters set by/for the authed account
func (m *Module) FiltersGETHandler(c *gin.Context) {
if _, err := oauth.Authed(c, true, true, true, true); err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest
package followrequests
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -72,25 +72,25 @@ import (
func (m *Module) FollowRequestAuthorizePOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
originAccountID := c.Param(IDKey)
if originAccountID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.FollowRequestAccept(c.Request.Context(), authed, originAccountID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest_test
package followrequests_test
import (
"context"
@@ -30,7 +30,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequest"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequests"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
@@ -60,7 +60,7 @@ func (suite *AuthorizeTestSuite) TestAuthorize() {
ctx.Params = gin.Params{
gin.Param{
Key: followrequest.IDKey,
Key: followrequests.IDKey,
Value: requestingAccount.ID,
},
}
@@ -90,7 +90,7 @@ func (suite *AuthorizeTestSuite) TestAuthorizeNoFR() {
ctx.Params = gin.Params{
gin.Param{
Key: followrequest.IDKey,
Key: followrequests.IDKey,
Value: requestingAccount.ID,
},
}

View File

@@ -16,21 +16,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest
package followrequests
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// IDKey is for account IDs
IDKey = "id"
// BasePath is the base path for serving the follow request API
BasePath = "/api/v1/follow_requests"
// BasePath is the base path for serving the follow request API, minus the 'api' prefix
BasePath = "/v1/follow_requests"
// BasePathWithID is just the base path with the ID key in it.
// Use this anywhere you need to know the ID of the account that owns the follow request being queried.
BasePathWithID = BasePath + "/:" + IDKey
@@ -40,22 +39,18 @@ const (
RejectPath = BasePathWithID + "/reject"
)
// Module implements the ClientAPIModule interface
type Module struct {
processor processing.Processor
}
// New returns a new follow request module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route attaches all routes from this module to the given router
func (m *Module) Route(r router.Router) error {
r.AttachHandler(http.MethodGet, BasePath, m.FollowRequestGETHandler)
r.AttachHandler(http.MethodPost, AuthorizePath, m.FollowRequestAuthorizePOSTHandler)
r.AttachHandler(http.MethodPost, RejectPath, m.FollowRequestRejectPOSTHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, BasePath, m.FollowRequestGETHandler)
attachHandler(http.MethodPost, AuthorizePath, m.FollowRequestAuthorizePOSTHandler)
attachHandler(http.MethodPost, RejectPath, m.FollowRequestRejectPOSTHandler)
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest_test
package followrequests_test
import (
"bytes"
@@ -25,7 +25,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequest"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequests"
"github.com/superseriousbusiness/gotosocial/internal/concurrency"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db"
@@ -59,7 +59,7 @@ type FollowRequestStandardTestSuite struct {
testStatuses map[string]*gtsmodel.Status
// module being tested
followRequestModule *followrequest.Module
followRequestModule *followrequests.Module
}
func (suite *FollowRequestStandardTestSuite) SetupSuite() {
@@ -85,7 +85,7 @@ func (suite *FollowRequestStandardTestSuite) SetupTest() {
suite.federator = testrig.NewTestFederator(suite.db, testrig.NewTestTransportController(testrig.NewMockHTTPClient(nil, "../../../../testrig/media"), suite.db, fedWorker), suite.storage, suite.mediaManager, fedWorker)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", nil)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.followRequestModule = followrequest.New(suite.processor).(*followrequest.Module)
suite.followRequestModule = followrequests.New(suite.processor)
testrig.StandardDBSetup(suite.db, nil)
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")

View File

@@ -16,13 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest
package followrequests
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -74,18 +74,18 @@ import (
func (m *Module) FollowRequestGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
accts, errWithCode := m.processor.FollowRequestsGet(c.Request.Context(), authed)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest_test
package followrequests_test
import (
"context"

View File

@@ -16,14 +16,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest
package followrequests
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@@ -70,25 +70,25 @@ import (
func (m *Module) FollowRequestRejectPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
originAccountID := c.Param(IDKey)
if originAccountID == "" {
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.FollowRequestReject(c.Request.Context(), authed, originAccountID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package followrequest_test
package followrequests_test
import (
"context"
@@ -30,7 +30,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequest"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequests"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
)
@@ -60,7 +60,7 @@ func (suite *RejectTestSuite) TestReject() {
ctx.Params = gin.Params{
gin.Param{
Key: followrequest.IDKey,
Key: followrequests.IDKey,
Value: requestingAccount.ID,
},
}

View File

@@ -21,36 +21,31 @@ package instance
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/processing"
"github.com/superseriousbusiness/gotosocial/internal/router"
)
const (
// InstanceInformationPath is for serving instance info requests
InstanceInformationPath = "api/v1/instance"
// InstanceInformationPath is for serving instance info requests, minus the 'api' prefix.
InstanceInformationPath = "/v1/instance"
// InstancePeersPath is for serving instance peers requests.
InstancePeersPath = InstanceInformationPath + "/peers"
// PeersFilterKey is used to provide filters to /api/v1/instance/peers
PeersFilterKey = "filter"
)
// Module implements the ClientModule interface
type Module struct {
processor processing.Processor
}
// New returns a new instance information module
func New(processor processing.Processor) api.ClientModule {
func New(processor processing.Processor) *Module {
return &Module{
processor: processor,
}
}
// Route satisfies the ClientModule interface
func (m *Module) Route(s router.Router) error {
s.AttachHandler(http.MethodGet, InstanceInformationPath, m.InstanceInformationGETHandler)
s.AttachHandler(http.MethodPatch, InstanceInformationPath, m.InstanceUpdatePATCHHandler)
s.AttachHandler(http.MethodGet, InstancePeersPath, m.InstancePeersGETHandler)
return nil
func (m *Module) Route(attachHandler func(method string, path string, f ...gin.HandlerFunc) gin.IRoutes) {
attachHandler(http.MethodGet, InstanceInformationPath, m.InstanceInformationGETHandler)
attachHandler(http.MethodPatch, InstanceInformationPath, m.InstanceUpdatePATCHHandler)
attachHandler(http.MethodGet, InstancePeersPath, m.InstancePeersGETHandler)
}

View File

@@ -88,7 +88,7 @@ func (suite *InstanceStandardTestSuite) SetupTest() {
suite.sentEmails = make(map[string]string)
suite.emailSender = testrig.NewEmailSender("../../../../web/template/", suite.sentEmails)
suite.processor = testrig.NewTestProcessor(suite.db, suite.storage, suite.federator, suite.emailSender, suite.mediaManager, clientWorker, fedWorker)
suite.instanceModule = instance.New(suite.processor).(*instance.Module)
suite.instanceModule = instance.New(suite.processor)
testrig.StandardDBSetup(suite.db, nil)
testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media")
}

View File

@@ -21,7 +21,7 @@ package instance
import (
"net/http"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
@@ -49,14 +49,14 @@ import (
// '500':
// description: internal error
func (m *Module) InstanceInformationGETHandler(c *gin.Context) {
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
instance, errWithCode := m.processor.InstanceGet(c.Request.Context(), config.GetHost())
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -24,8 +24,8 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -130,42 +130,42 @@ import (
func (m *Module) InstanceUpdatePATCHHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
if !*authed.User.Admin {
err := errors.New("user is not an admin so cannot update instance settings")
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.InstanceSettingsUpdateRequest{}
form := &apimodel.InstanceSettingsUpdateRequest{}
if err := c.ShouldBind(&form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if err := validateInstanceUpdate(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
i, errWithCode := m.processor.InstancePatch(c.Request.Context(), form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, i)
}
func validateInstanceUpdate(form *model.InstanceSettingsUpdateRequest) error {
func validateInstanceUpdate(form *apimodel.InstanceSettingsUpdateRequest) error {
if form.Title == nil &&
form.ContactUsername == nil &&
form.ContactEmail == nil &&

View File

@@ -23,7 +23,7 @@ import (
"net/http"
"strings"
"github.com/superseriousbusiness/gotosocial/internal/api"
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
@@ -101,12 +101,12 @@ import (
func (m *Module) InstancePeersGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, false, false, false, false)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@@ -124,7 +124,7 @@ func (m *Module) InstancePeersGETHandler(c *gin.Context) {
includeOpen = true
default:
err := fmt.Errorf("filter %s not recognized; accepted values are 'open', 'suspended'", trimmed)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
}
@@ -138,7 +138,7 @@ func (m *Module) InstancePeersGETHandler(c *gin.Context) {
data, errWithCode := m.processor.InstancePeersGet(c.Request.Context(), authed, includeSuspended, includeOpen, flat)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View File

@@ -1,25 +0,0 @@
package list
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
// ListsGETHandler returns a list of lists created by/for the authed account
func (m *Module) ListsGETHandler(c *gin.Context) {
if _, err := oauth.Authed(c, true, true, true, true); err != nil {
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
c.JSON(http.StatusOK, []string{})
}

Some files were not shown because too many files have changed in this diff Show More