[feature] More consistent API error handling (#637)

* update templates

* start reworking api error handling

* update template

* return AP status at web endpoint if negotiated

* start making api error handling much more consistent

* update account endpoints to new error handling

* use new api error handling in admin endpoints

* go fmt ./...

* use api error logic in app

* use generic error handling in auth

* don't export generic error handler

* don't defer clearing session

* user nicer error handling on oidc callback handler

* tidy up the sign in handler

* tidy up the token handler

* use nicer error handling in blocksget

* auth emojis endpoint

* fix up remaining api endpoints

* fix whoopsie during login flow

* regenerate swagger docs

* change http error logging to debug
This commit is contained in:
tobi 2022-06-08 20:38:03 +02:00 committed by GitHub
commit 1ede54ddf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
130 changed files with 2154 additions and 1673 deletions

View file

@ -23,12 +23,11 @@ import (
"net"
"net/http"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/internal/validate"
)
@ -61,58 +60,51 @@ import (
// description: "An OAuth2 access token for the newly-created account."
// schema:
// "$ref": "#/definitions/oauthToken"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal error
// description: internal server error
func (m *Module) AccountCreatePOSTHandler(c *gin.Context) {
l := logrus.WithField("func", "accountCreatePOSTHandler")
authed, err := oauth.Authed(c, true, true, false, false)
if err != nil {
l.Debugf("couldn't auth: %s", err)
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
l.Trace("parsing request form")
form := &model.AccountCreateRequest{}
if err := c.ShouldBind(form); err != nil || form == nil {
l.Debugf("could not parse form from request: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "missing one or more required form values"})
if err := c.ShouldBind(form); err != nil {
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
l.Tracef("validating form %+v", form)
if err := validateCreateAccount(form); err != nil {
l.Debugf("error validating form: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
clientIP := c.ClientIP()
l.Tracef("attempting to parse client ip address %s", clientIP)
signUpIP := net.ParseIP(clientIP)
if signUpIP == nil {
l.Debugf("error validating sign up ip address %s", clientIP)
c.JSON(http.StatusBadRequest, gin.H{"error": "ip address could not be parsed from request"})
err := errors.New("ip address could not be parsed from request")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form.IP = signUpIP
ti, err := m.processor.AccountCreate(c.Request.Context(), authed, form)
if err != nil {
l.Errorf("internal server error while creating new account: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
ti, errWithCode := m.processor.AccountCreate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
@ -122,6 +114,10 @@ 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 {
if form == nil {
return errors.New("form was nil")
}
if !config.GetAccountsRegistrationOpen() {
return errors.New("registration is not open for this server")
}

View file

@ -19,12 +19,13 @@
package account
import (
"errors"
"net/http"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -57,32 +58,35 @@ import (
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountDeletePOSTHandler(c *gin.Context) {
l := logrus.WithField("func", "AccountDeletePOSTHandler")
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
l.Debugf("couldn't auth: %s", err)
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
l.Tracef("retrieved account %+v", authed.Account.ID)
form := &model.AccountDeleteRequest{}
if err := c.ShouldBind(&form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
if form.Password == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no password provided in account delete request"})
err = errors.New("no password provided in account delete request")
api.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 {
l.Debugf("could not delete account: %s", errWithCode.Error())
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,11 +19,12 @@
package account
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -53,34 +54,38 @@ import (
// '200':
// schema:
// "$ref": "#/definitions/account"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
acctInfo, errWithCode := m.processor.AccountGet(c.Request.Context(), authed, targetAcctID)
if err != nil {
logrus.Debug(errWithCode.Error())
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,15 +19,15 @@
package account
import (
"errors"
"fmt"
"net/http"
"strconv"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -98,68 +98,67 @@ import (
// description: "The newly updated account."
// schema:
// "$ref": "#/definitions/account"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountUpdateCredentialsPATCHHandler(c *gin.Context) {
l := logrus.WithField("func", "accountUpdateCredentialsPATCHHandler")
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
l.Debugf("couldn't auth: %s", err)
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
l.Tracef("retrieved account %+v", authed.Account.ID)
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
form, err := parseUpdateAccountForm(c)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
// if everything on the form is nil, then nothing has been set and we shouldn't continue
if form.Discoverable == nil &&
form.Bot == nil &&
form.DisplayName == nil &&
form.Note == nil &&
form.Avatar == nil &&
form.Header == nil &&
form.Locked == nil &&
form.Source.Privacy == nil &&
form.Source.Sensitive == nil &&
form.Source.Language == nil &&
form.FieldsAttributes == nil {
l.Debugf("could not parse form from request")
c.JSON(http.StatusBadRequest, gin.H{"error": "empty form submitted"})
acctSensitive, errWithCode := m.processor.AccountUpdate(c.Request.Context(), authed, form)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
acctSensitive, err := m.processor.AccountUpdate(c.Request.Context(), authed, form)
if err != nil {
l.Debugf("could not update account: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
l.Tracef("conversion successful, returning OK and apisensitive account %+v", acctSensitive)
c.JSON(http.StatusOK, acctSensitive)
}
func parseUpdateAccountForm(c *gin.Context) (*model.UpdateCredentialsRequest, error) {
// parse main fields from request
form := &model.UpdateCredentialsRequest{
Source: &model.UpdateSource{},
}
if err := c.ShouldBind(&form); err != nil || form == nil {
if err := c.ShouldBind(&form); err != nil {
return nil, fmt.Errorf("could not parse form from request: %s", err)
}
if form == nil ||
(form.Discoverable == nil &&
form.Bot == nil &&
form.DisplayName == nil &&
form.Note == nil &&
form.Avatar == nil &&
form.Header == nil &&
form.Locked == nil &&
form.Source.Privacy == nil &&
form.Source.Sensitive == nil &&
form.Source.Language == nil &&
form.FieldsAttributes == nil) {
return nil, errors.New("empty form submitted")
}
// parse source field-by-field
sourceMap := c.PostFormMap("source")

View file

@ -26,7 +26,6 @@ import (
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/account"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
@ -65,7 +64,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandler()
// check the response
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount := &apimodel.Account{}
@ -104,7 +103,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUnl
// check the response
b1, err := ioutil.ReadAll(result1.Body)
assert.NoError(suite.T(), err)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount1 := &apimodel.Account{}
@ -185,7 +184,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerGet
// check the response
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount := &apimodel.Account{}
@ -227,7 +226,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerTwo
// check the response
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount := &apimodel.Account{}
@ -271,7 +270,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerWit
// check the response
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount := &apimodel.Account{}
@ -313,8 +312,8 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerEmp
// check the response
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
suite.Equal(`{"error":"empty form submitted"}`, string(b))
suite.NoError(err)
suite.Equal(`{"error":"Bad Request: empty form submitted"}`, string(b))
}
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpdateSource() {
@ -348,7 +347,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpd
// check the response
b, err := ioutil.ReadAll(result.Body)
assert.NoError(suite.T(), err)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount := &apimodel.Account{}

View file

@ -21,10 +21,9 @@ package account
import (
"net/http"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -47,30 +46,31 @@ import (
// '200':
// schema:
// "$ref": "#/definitions/account"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountVerifyGETHandler(c *gin.Context) {
l := logrus.WithField("func", "accountVerifyGETHandler")
authed, err := oauth.Authed(c, true, false, false, true)
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
l.Debugf("couldn't auth: %s", err)
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
acctSensitive, err := m.processor.AccountGet(c.Request.Context(), authed, authed.Account.ID)
if err != nil {
l.Debugf("error getting account from processor: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"})
acctSensitive, errWithCode := m.processor.AccountGet(c.Request.Context(), authed, authed.Account.ID)
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,10 +19,12 @@
package account
import (
"errors"
"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"
)
@ -54,33 +56,38 @@ import (
// description: Your relationship to this account.
// schema:
// "$ref": "#/definitions/accountRelationship"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountBlockPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.AccountBlockCreate(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,11 +19,13 @@
package account
import (
"errors"
"net/http"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -75,39 +77,45 @@ import (
// description: Your relationship to this account.
// schema:
// "$ref": "#/definitions/accountRelationship"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountFollowPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
form := &model.AccountFollowRequest{}
if err := c.ShouldBind(form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
api.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 {
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,10 +19,12 @@
package account
import (
"errors"
"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"
)
@ -56,33 +58,38 @@ import (
// type: array
// items:
// "$ref": "#/definitions/account"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountFollowersGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
followers, errWithCode := m.processor.AccountFollowersGet(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,10 +19,12 @@
package account
import (
"errors"
"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"
)
@ -56,33 +58,38 @@ import (
// type: array
// items:
// "$ref": "#/definitions/account"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountFollowingGETHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
following, errWithCode := m.processor.AccountFollowingGet(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -1,13 +1,13 @@
package account
import (
"errors"
"net/http"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -43,24 +43,25 @@ import (
// type: array
// items:
// "$ref": "#/definitions/accountRelationship"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountRelationshipsGETHandler(c *gin.Context) {
l := logrus.WithField("func", "AccountRelationshipsGETHandler")
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
l.Debugf("error authing: %s", err)
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
@ -69,8 +70,8 @@ func (m *Module) AccountRelationshipsGETHandler(c *gin.Context) {
// check fallback -- let's be generous and see if maybe it's just set as 'id'?
id := c.Query("id")
if id == "" {
l.Debug("no account id specified in query")
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err = errors.New("no account id(s) specified in query")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
targetAccountIDs = append(targetAccountIDs, id)
@ -80,8 +81,8 @@ func (m *Module) AccountRelationshipsGETHandler(c *gin.Context) {
for _, targetAccountID := range targetAccountIDs {
r, errWithCode := m.processor.AccountRelationshipGet(c.Request.Context(), authed, targetAccountID)
if err != nil {
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
if errWithCode != nil {
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}
relationships = append(relationships, *r)

View file

@ -19,13 +19,14 @@
package account
import (
"errors"
"fmt"
"net/http"
"strconv"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -110,31 +111,32 @@ import (
// type: array
// items:
// "$ref": "#/definitions/status"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
l := logrus.WithField("func", "AccountStatusesGETHandler")
authed, err := oauth.Authed(c, false, false, false, false)
if err != nil {
l.Debugf("error authing: %s", err)
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
l.Debug("no account id specified in query")
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
@ -143,8 +145,8 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
if limitString != "" {
i, err := strconv.ParseInt(limitString, 10, 64)
if err != nil {
l.Debugf("error parsing limit string: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse limit query param"})
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
limit = int(i)
@ -155,8 +157,8 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
if excludeRepliesString != "" {
i, err := strconv.ParseBool(excludeRepliesString)
if err != nil {
l.Debugf("error parsing exclude replies string: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse exclude replies query param"})
err := fmt.Errorf("error parsing %s: %s", ExcludeRepliesKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
excludeReplies = i
@ -167,8 +169,8 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
if excludeReblogsString != "" {
i, err := strconv.ParseBool(excludeReblogsString)
if err != nil {
l.Debugf("error parsing exclude reblogs string: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse exclude reblogs query param"})
err := fmt.Errorf("error parsing %s: %s", ExcludeReblogsKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
excludeReblogs = i
@ -191,8 +193,8 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
if pinnedString != "" {
i, err := strconv.ParseBool(pinnedString)
if err != nil {
l.Debugf("error parsing pinned string: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse pinned query param"})
err := fmt.Errorf("error parsing %s: %s", PinnedKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
pinnedOnly = i
@ -203,8 +205,8 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
if mediaOnlyString != "" {
i, err := strconv.ParseBool(mediaOnlyString)
if err != nil {
l.Debugf("error parsing media only string: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse media only query param"})
err := fmt.Errorf("error parsing %s: %s", OnlyMediaKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
mediaOnly = i
@ -215,8 +217,8 @@ func (m *Module) AccountStatusesGETHandler(c *gin.Context) {
if publicOnlyString != "" {
i, err := strconv.ParseBool(publicOnlyString)
if err != nil {
l.Debugf("error parsing public only string: %s", err)
c.JSON(http.StatusBadRequest, gin.H{"error": "couldn't parse public only query param"})
err := fmt.Errorf("error parsing %s: %s", OnlyPublicKey, err)
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
publicOnly = i
@ -224,8 +226,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 {
l.Debugf("error from processor account statuses get: %s", errWithCode)
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,10 +19,12 @@
package account
import (
"errors"
"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"
)
@ -54,33 +56,38 @@ import (
// description: Your relationship to this account.
// schema:
// "$ref": "#/definitions/accountRelationship"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountUnblockPOSTHandler(c *gin.Context) {
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.AccountBlockRemove(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}

View file

@ -19,12 +19,12 @@
package account
import (
"errors"
"net/http"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
@ -56,37 +56,38 @@ import (
// description: Your relationship to this account.
// schema:
// "$ref": "#/definitions/accountRelationship"
// '401':
// description: unauthorized
// '400':
// description: bad request
// '401':
// description: unauthorized
// '404':
// description: not found
// '406':
// description: not acceptable
// '500':
// description: internal server error
func (m *Module) AccountUnfollowPOSTHandler(c *gin.Context) {
l := logrus.WithField("func", "AccountUnfollowPOSTHandler")
authed, err := oauth.Authed(c, true, true, true, true)
if err != nil {
l.Debug(err)
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
api.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGet)
return
}
if _, err := api.NegotiateAccept(c, api.JSONAcceptHeaders...); err != nil {
c.JSON(http.StatusNotAcceptable, gin.H{"error": err.Error()})
api.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGet)
return
}
targetAcctID := c.Param(IDKey)
if targetAcctID == "" {
l.Debug(err)
c.JSON(http.StatusBadRequest, gin.H{"error": "no account id specified"})
err := errors.New("no account id specified")
api.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGet)
return
}
relationship, errWithCode := m.processor.AccountFollowRemove(c.Request.Context(), authed, targetAcctID)
if errWithCode != nil {
l.Debug(errWithCode.Error())
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
api.ErrorHandler(c, errWithCode, m.processor.InstanceGet)
return
}