mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-12-07 14:48:07 -06:00
[feature/frontend] Reports frontend v2 (#3022)
* use apiutil + paging in admin processor+handlers * we're making it happen * fix little whoopsie * styling for report list * don't youuuu forget about meee don't don't don't don't * last bits * sanitize content before showing in report statuses * update report docs
This commit is contained in:
parent
b08c1bd0cb
commit
d2b3d37724
56 changed files with 1389 additions and 726 deletions
|
|
@ -116,10 +116,9 @@ func (m *Module) AccountActionPOSTHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
targetAcctID := c.Param(IDKey)
|
||||
if targetAcctID == "" {
|
||||
err := errors.New("no account id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
targetAcctID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
form.TargetID = targetAcctID
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"codeberg.org/gruf/go-debug"
|
||||
"github.com/gin-gonic/gin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
)
|
||||
|
|
@ -29,48 +30,40 @@ import (
|
|||
const (
|
||||
BasePath = "/v1/admin"
|
||||
EmojiPath = BasePath + "/custom_emojis"
|
||||
EmojiPathWithID = EmojiPath + "/:" + IDKey
|
||||
EmojiPathWithID = EmojiPath + "/:" + apiutil.IDKey
|
||||
EmojiCategoriesPath = EmojiPath + "/categories"
|
||||
DomainBlocksPath = BasePath + "/domain_blocks"
|
||||
DomainBlocksPathWithID = DomainBlocksPath + "/:" + IDKey
|
||||
DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
|
||||
DomainAllowsPath = BasePath + "/domain_allows"
|
||||
DomainAllowsPathWithID = DomainAllowsPath + "/:" + IDKey
|
||||
DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
|
||||
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
||||
HeaderAllowsPath = BasePath + "/header_allows"
|
||||
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + IDKey
|
||||
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
||||
HeaderBlocksPath = BasePath + "/header_blocks"
|
||||
HeaderBlocksPathWithID = HeaderBlocksPath + "/:" + IDKey
|
||||
HeaderBlocksPathWithID = HeaderBlocksPath + "/:" + apiutil.IDKey
|
||||
AccountsV1Path = BasePath + "/accounts"
|
||||
AccountsV2Path = "/v2/admin/accounts"
|
||||
AccountsPathWithID = AccountsV1Path + "/:" + IDKey
|
||||
AccountsPathWithID = AccountsV1Path + "/:" + apiutil.IDKey
|
||||
AccountsActionPath = AccountsPathWithID + "/action"
|
||||
AccountsApprovePath = AccountsPathWithID + "/approve"
|
||||
AccountsRejectPath = AccountsPathWithID + "/reject"
|
||||
MediaCleanupPath = BasePath + "/media_cleanup"
|
||||
MediaRefetchPath = BasePath + "/media_refetch"
|
||||
ReportsPath = BasePath + "/reports"
|
||||
ReportsPathWithID = ReportsPath + "/:" + IDKey
|
||||
ReportsPathWithID = ReportsPath + "/:" + apiutil.IDKey
|
||||
ReportsResolvePath = ReportsPathWithID + "/resolve"
|
||||
EmailPath = BasePath + "/email"
|
||||
EmailTestPath = EmailPath + "/test"
|
||||
InstanceRulesPath = BasePath + "/instance/rules"
|
||||
InstanceRulesPathWithID = InstanceRulesPath + "/:" + IDKey
|
||||
InstanceRulesPathWithID = InstanceRulesPath + "/:" + apiutil.IDKey
|
||||
DebugPath = BasePath + "/debug"
|
||||
DebugAPUrlPath = DebugPath + "/apurl"
|
||||
DebugClearCachesPath = DebugPath + "/caches/clear"
|
||||
|
||||
IDKey = "id"
|
||||
FilterQueryKey = "filter"
|
||||
MaxShortcodeDomainKey = "max_shortcode_domain"
|
||||
MinShortcodeDomainKey = "min_shortcode_domain"
|
||||
LimitKey = "limit"
|
||||
DomainQueryKey = "domain"
|
||||
ResolvedKey = "resolved"
|
||||
AccountIDKey = "account_id"
|
||||
TargetAccountIDKey = "target_account_id"
|
||||
MaxIDKey = "max_id"
|
||||
SinceIDKey = "since_id"
|
||||
MinIDKey = "min_id"
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -97,10 +96,9 @@ func (m *Module) EmojiDELETEHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
emojiID := c.Param(IDKey)
|
||||
if emojiID == "" {
|
||||
err := errors.New("no emoji id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
emojiID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
)
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ func (suite *EmojiDeleteTestSuite) TestEmojiDelete1() {
|
|||
|
||||
path := admin.EmojiPathWithID
|
||||
ctx := suite.newContext(recorder, http.MethodDelete, nil, path, "application/json")
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
suite.adminModule.EmojiDELETEHandler(ctx)
|
||||
suite.Equal(http.StatusOK, recorder.Code)
|
||||
|
|
@ -78,7 +79,7 @@ func (suite *EmojiDeleteTestSuite) TestEmojiDelete2() {
|
|||
|
||||
path := admin.EmojiPathWithID
|
||||
ctx := suite.newContext(recorder, http.MethodDelete, nil, path, "application/json")
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
suite.adminModule.EmojiDELETEHandler(ctx)
|
||||
suite.Equal(http.StatusBadRequest, recorder.Code)
|
||||
|
|
@ -100,7 +101,7 @@ func (suite *EmojiDeleteTestSuite) TestEmojiDeleteNotFound() {
|
|||
|
||||
path := admin.EmojiPathWithID
|
||||
ctx := suite.newContext(recorder, http.MethodDelete, nil, path, "application/json")
|
||||
ctx.AddParam(admin.IDKey, "01GF8VRXX1R00X7XH8973Z29R1")
|
||||
ctx.AddParam(apiutil.IDKey, "01GF8VRXX1R00X7XH8973Z29R1")
|
||||
|
||||
suite.adminModule.EmojiDELETEHandler(ctx)
|
||||
suite.Equal(http.StatusNotFound, recorder.Code)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -82,10 +81,9 @@ func (m *Module) EmojiGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
emojiID := c.Param(IDKey)
|
||||
if emojiID == "" {
|
||||
err := errors.New("no emoji id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
emojiID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
)
|
||||
|
||||
type EmojiGetTestSuite struct {
|
||||
|
|
@ -39,7 +40,7 @@ func (suite *EmojiGetTestSuite) TestEmojiGet1() {
|
|||
|
||||
path := admin.EmojiPathWithID
|
||||
ctx := suite.newContext(recorder, http.MethodGet, nil, path, "application/json")
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
suite.adminModule.EmojiGETHandler(ctx)
|
||||
suite.Equal(http.StatusOK, recorder.Code)
|
||||
|
|
@ -71,7 +72,7 @@ func (suite *EmojiGetTestSuite) TestEmojiGet2() {
|
|||
|
||||
path := admin.EmojiPathWithID
|
||||
ctx := suite.newContext(recorder, http.MethodGet, nil, path, "application/json")
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
suite.adminModule.EmojiGETHandler(ctx)
|
||||
suite.Equal(http.StatusOK, recorder.Code)
|
||||
|
|
@ -102,7 +103,7 @@ func (suite *EmojiGetTestSuite) TestEmojiGetNotFound() {
|
|||
|
||||
path := admin.EmojiPathWithID
|
||||
ctx := suite.newContext(recorder, http.MethodGet, nil, path, "application/json")
|
||||
ctx.AddParam(admin.IDKey, "01GF8VRXX1R00X7XH8973Z29R1")
|
||||
ctx.AddParam(apiutil.IDKey, "01GF8VRXX1R00X7XH8973Z29R1")
|
||||
|
||||
suite.adminModule.EmojiGETHandler(ctx)
|
||||
suite.Equal(http.StatusNotFound, recorder.Code)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package admin
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
|
@ -76,6 +75,8 @@ import (
|
|||
// type: integer
|
||||
// description: Number of emojis to return. Less than 1, or not set, means unlimited (all emojis).
|
||||
// default: 50
|
||||
// minimum: 0
|
||||
// maximum: 200
|
||||
// in: query
|
||||
// -
|
||||
// name: max_shortcode_domain
|
||||
|
|
@ -142,19 +143,10 @@ func (m *Module) EmojisGETHandler(c *gin.Context) {
|
|||
maxShortcodeDomain := c.Query(MaxShortcodeDomainKey)
|
||||
minShortcodeDomain := c.Query(MinShortcodeDomainKey)
|
||||
|
||||
limit := 50
|
||||
limitString := c.Query(LimitKey)
|
||||
if limitString != "" {
|
||||
i, err := strconv.ParseInt(limitString, 10, 32)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
limit = int(i)
|
||||
}
|
||||
if limit < 0 {
|
||||
limit = 0
|
||||
limit, errWithCode := apiutil.ParseLimit(c.Query(apiutil.LimitKey), 50, 200, 0)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
var domain string
|
||||
|
|
|
|||
|
|
@ -147,10 +147,9 @@ func (m *Module) EmojiPATCHHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
emojiID := c.Param(IDKey)
|
||||
if emojiID == "" {
|
||||
err := errors.New("no emoji id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
emojiID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
|
@ -53,7 +54,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateNewCategory() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -130,7 +131,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateSwitchCategory() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -208,7 +209,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyRemoteToLocal() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -284,7 +285,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateDisableEmoji() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -325,7 +326,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateDisableLocalEmoji() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -358,7 +359,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateModifyRemoteEmoji() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -391,7 +392,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateModifyNoParams() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -425,7 +426,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyLocalToLocal() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -459,7 +460,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyEmptyShortcode() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -492,7 +493,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyNoShortcode() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
@ -526,7 +527,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyShortcodeAlreadyInUse() {
|
|||
bodyBytes := requestBody.Bytes()
|
||||
recorder := httptest.NewRecorder()
|
||||
ctx := suite.newContext(recorder, http.MethodPost, bodyBytes, admin.EmojiPathWithID, w.FormDataContentType())
|
||||
ctx.AddParam(admin.IDKey, testEmoji.ID)
|
||||
ctx.AddParam(apiutil.IDKey, testEmoji.ID)
|
||||
|
||||
// call the handler
|
||||
suite.adminModule.EmojiPATCHHandler(ctx)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -85,10 +84,9 @@ func (m *Module) ReportGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
reportID := c.Param(IDKey)
|
||||
if reportID == "" {
|
||||
err := errors.New("no report id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
reportID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -107,10 +106,9 @@ func (m *Module) ReportResolvePOSTHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
reportID := c.Param(IDKey)
|
||||
if reportID == "" {
|
||||
err := errors.New("no report id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
reportID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
|
||||
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/gtsmodel"
|
||||
|
|
@ -65,7 +66,7 @@ func (suite *ReportResolveTestSuite) resolveReport(
|
|||
|
||||
// create the request
|
||||
ctx.Request = httptest.NewRequest(http.MethodPost, requestURI, nil)
|
||||
ctx.AddParam(admin.IDKey, targetReportID)
|
||||
ctx.AddParam(apiutil.IDKey, targetReportID)
|
||||
ctx.Request.Header.Set("accept", "application/json")
|
||||
if actionTakenComment != nil {
|
||||
ctx.Request.Form = url.Values{"action_taken_comment": {*actionTakenComment}}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ package admin
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"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"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// ReportsGETHandler swagger:operation GET /api/v1/admin/reports adminReports
|
||||
|
|
@ -72,7 +72,7 @@ import (
|
|||
// name: max_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only reports *OLDER* than the given max ID.
|
||||
// Return only reports *OLDER* than the given max ID (for paging downwards).
|
||||
// The report with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// -
|
||||
|
|
@ -81,23 +81,21 @@ import (
|
|||
// description: >-
|
||||
// Return only reports *NEWER* than the given since ID.
|
||||
// The report with the specified ID will not be included in the response.
|
||||
// This parameter is functionally equivalent to min_id.
|
||||
// in: query
|
||||
// -
|
||||
// name: min_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only reports *NEWER* than the given min ID.
|
||||
// Return only reports immediately *NEWER* than the given min ID (for paging upwards).
|
||||
// The report with the specified ID will not be included in the response.
|
||||
// This parameter is functionally equivalent to since_id.
|
||||
// in: query
|
||||
// -
|
||||
// name: limit
|
||||
// type: integer
|
||||
// description: >-
|
||||
// Number of reports to return.
|
||||
// If more than 100 or less than 1, will be clamped to 100.
|
||||
// description: Number of reports to return.
|
||||
// default: 20
|
||||
// minimum: 1
|
||||
// maximum: 100
|
||||
// in: query
|
||||
//
|
||||
// security:
|
||||
|
|
@ -144,34 +142,30 @@ func (m *Module) ReportsGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
var resolved *bool
|
||||
if resolvedString := c.Query(ResolvedKey); resolvedString != "" {
|
||||
i, err := strconv.ParseBool(resolvedString)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error parsing %s: %s", ResolvedKey, err)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
resolved = &i
|
||||
resolved, errWithCode := apiutil.ParseResolved(c.Query(apiutil.ResolvedKey), nil)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
limit := 20
|
||||
if limitString := c.Query(LimitKey); limitString != "" {
|
||||
i, err := strconv.Atoi(limitString)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
// normalize
|
||||
if i < 1 || i > 100 {
|
||||
i = 100
|
||||
}
|
||||
limit = i
|
||||
page, errWithCode := paging.ParseIDPage(c,
|
||||
1, // min limit
|
||||
100, // max limit
|
||||
20, // default limit
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
resp, errWithCode := m.processor.Admin().ReportsGet(c.Request.Context(), authed.Account, resolved, c.Query(AccountIDKey), c.Query(TargetAccountIDKey), c.Query(MaxIDKey), c.Query(SinceIDKey), c.Query(MinIDKey), limit)
|
||||
resp, errWithCode := m.processor.Admin().ReportsGet(
|
||||
c.Request.Context(),
|
||||
authed.Account,
|
||||
resolved,
|
||||
c.Query(apiutil.AccountIDKey),
|
||||
c.Query(apiutil.TargetAccountIDKey),
|
||||
page,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/admin"
|
||||
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/gtsmodel"
|
||||
|
|
@ -63,24 +64,24 @@ func (suite *ReportsGetTestSuite) getReports(
|
|||
ctx.Set(oauth.SessionAuthorizedUser, user)
|
||||
|
||||
// create the request URI
|
||||
requestPath := admin.ReportsPath + "?" + admin.LimitKey + "=" + strconv.Itoa(limit)
|
||||
requestPath := admin.ReportsPath + "?" + apiutil.LimitKey + "=" + strconv.Itoa(limit)
|
||||
if resolved != nil {
|
||||
requestPath = requestPath + "&" + admin.ResolvedKey + "=" + strconv.FormatBool(*resolved)
|
||||
requestPath = requestPath + "&" + apiutil.ResolvedKey + "=" + strconv.FormatBool(*resolved)
|
||||
}
|
||||
if accountID != "" {
|
||||
requestPath = requestPath + "&" + admin.AccountIDKey + "=" + accountID
|
||||
requestPath = requestPath + "&" + apiutil.AccountIDKey + "=" + accountID
|
||||
}
|
||||
if targetAccountID != "" {
|
||||
requestPath = requestPath + "&" + admin.TargetAccountIDKey + "=" + targetAccountID
|
||||
requestPath = requestPath + "&" + apiutil.TargetAccountIDKey + "=" + targetAccountID
|
||||
}
|
||||
if maxID != "" {
|
||||
requestPath = requestPath + "&" + admin.MaxIDKey + "=" + maxID
|
||||
requestPath = requestPath + "&" + apiutil.MaxIDKey + "=" + maxID
|
||||
}
|
||||
if sinceID != "" {
|
||||
requestPath = requestPath + "&" + admin.SinceIDKey + "=" + sinceID
|
||||
requestPath = requestPath + "&" + apiutil.SinceIDKey + "=" + sinceID
|
||||
}
|
||||
if minID != "" {
|
||||
requestPath = requestPath + "&" + admin.MinIDKey + "=" + minID
|
||||
requestPath = requestPath + "&" + apiutil.MinIDKey + "=" + minID
|
||||
}
|
||||
baseURI := config.GetProtocol() + "://" + config.GetHost()
|
||||
requestURI := baseURI + "/api/" + requestPath
|
||||
|
|
@ -766,7 +767,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
|
|||
}
|
||||
]`, string(b))
|
||||
|
||||
suite.Equal(`<http://localhost:8080/api/v1/admin/reports?limit=20&max_id=01GP3AWY4CRDVRNZKW0TEAMB5R&account_id=01F8MH5NBDF2MV7CTC4Q5128HF>; rel="next", <http://localhost:8080/api/v1/admin/reports?limit=20&min_id=01GP3AWY4CRDVRNZKW0TEAMB5R&account_id=01F8MH5NBDF2MV7CTC4Q5128HF>; rel="prev"`, link)
|
||||
suite.Equal(`<http://localhost:8080/api/v1/admin/reports?account_id=01F8MH5NBDF2MV7CTC4Q5128HF&limit=20&max_id=01GP3AWY4CRDVRNZKW0TEAMB5R>; rel="next", <http://localhost:8080/api/v1/admin/reports?account_id=01F8MH5NBDF2MV7CTC4Q5128HF&limit=20&min_id=01GP3AWY4CRDVRNZKW0TEAMB5R>; rel="prev"`, link)
|
||||
}
|
||||
|
||||
func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
|
||||
|
|
@ -1028,8 +1029,8 @@ func (suite *ReportsGetTestSuite) TestReportsGetZeroLimit() {
|
|||
suite.NoError(err)
|
||||
suite.Len(reports, 2)
|
||||
|
||||
// Limit in Link header should be set to 100
|
||||
suite.Equal(`<http://localhost:8080/api/v1/admin/reports?limit=100&max_id=01GP3AWY4CRDVRNZKW0TEAMB5R>; rel="next", <http://localhost:8080/api/v1/admin/reports?limit=100&min_id=01GP3DFY9XQ1TJMZT5BGAZPXX7>; rel="prev"`, link)
|
||||
// Limit in Link header should be set to default (20)
|
||||
suite.Equal(`<http://localhost:8080/api/v1/admin/reports?limit=20&max_id=01GP3AWY4CRDVRNZKW0TEAMB5R>; rel="next", <http://localhost:8080/api/v1/admin/reports?limit=20&min_id=01GP3DFY9XQ1TJMZT5BGAZPXX7>; rel="prev"`, link)
|
||||
}
|
||||
|
||||
func (suite *ReportsGetTestSuite) TestReportsGetHighLimit() {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -95,10 +94,9 @@ func (m *Module) RuleDELETEHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
ruleID := c.Param(IDKey)
|
||||
if ruleID == "" {
|
||||
err := errors.New("no rule id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
ruleID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -85,10 +84,9 @@ func (m *Module) RuleGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
ruleID := c.Param(IDKey)
|
||||
if ruleID == "" {
|
||||
err := errors.New("no rule id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
ruleID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -87,10 +86,9 @@ func (m *Module) RulePATCHHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
ruleID := c.Param(IDKey)
|
||||
if ruleID == "" {
|
||||
err := errors.New("no rule id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
ruleID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package reports
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
|
@ -77,10 +76,9 @@ func (m *Module) ReportGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
targetReportID := c.Param(IDKey)
|
||||
if targetReportID == "" {
|
||||
err := errors.New("no report id specified")
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
targetReportID, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func (suite *ReportGetTestSuite) TestGetReport2() {
|
|||
}
|
||||
|
||||
func (suite *ReportGetTestSuite) TestGetReport3() {
|
||||
report, err := suite.getReport(http.StatusBadRequest, `{"error":"Bad Request: no report id specified"}`, "")
|
||||
report, err := suite.getReport(http.StatusBadRequest, `{"error":"Bad Request: required key id was not set or had empty value"}`, "")
|
||||
suite.NoError(err)
|
||||
suite.Nil(report)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,19 +21,13 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/processing"
|
||||
)
|
||||
|
||||
const (
|
||||
BasePath = "/v1/reports"
|
||||
IDKey = "id"
|
||||
ResolvedKey = "resolved"
|
||||
TargetAccountIDKey = "target_account_id"
|
||||
MaxIDKey = "max_id"
|
||||
SinceIDKey = "since_id"
|
||||
MinIDKey = "min_id"
|
||||
LimitKey = "limit"
|
||||
BasePathWithID = BasePath + "/:" + IDKey
|
||||
BasePath = "/v1/reports"
|
||||
BasePathWithID = BasePath + "/:" + apiutil.IDKey
|
||||
)
|
||||
|
||||
type Module struct {
|
||||
|
|
|
|||
|
|
@ -18,14 +18,13 @@
|
|||
package reports
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"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"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// ReportsGETHandler swagger:operation GET /api/v1/reports reports
|
||||
|
|
@ -67,7 +66,7 @@ import (
|
|||
// name: max_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only reports *OLDER* than the given max ID.
|
||||
// Return only reports *OLDER* than the given max ID (for paging downwards).
|
||||
// The report with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// -
|
||||
|
|
@ -76,24 +75,21 @@ import (
|
|||
// description: >-
|
||||
// Return only reports *NEWER* than the given since ID.
|
||||
// The report with the specified ID will not be included in the response.
|
||||
// This parameter is functionally equivalent to min_id.
|
||||
// in: query
|
||||
// -
|
||||
// name: min_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only reports *NEWER* than the given min ID.
|
||||
// Return only reports immediately *NEWER* than the given min ID (for paging upwards).
|
||||
// The report with the specified ID will not be included in the response.
|
||||
// This parameter is functionally equivalent to since_id.
|
||||
// in: query
|
||||
// -
|
||||
// name: limit
|
||||
// type: integer
|
||||
// description: >-
|
||||
// Number of reports to return.
|
||||
// If less than 1, will be clamped to 1.
|
||||
// If more than 100, will be clamped to 100.
|
||||
// description: Number of reports to return.
|
||||
// default: 20
|
||||
// minimum: 1
|
||||
// maximum: 100
|
||||
// in: query
|
||||
//
|
||||
// security:
|
||||
|
|
@ -134,36 +130,29 @@ func (m *Module) ReportsGETHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
var resolved *bool
|
||||
if resolvedString := c.Query(ResolvedKey); resolvedString != "" {
|
||||
i, err := strconv.ParseBool(resolvedString)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error parsing %s: %s", ResolvedKey, err)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
resolved = &i
|
||||
resolved, errWithCode := apiutil.ParseResolved(c.Query(apiutil.ResolvedKey), nil)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
limit := 20
|
||||
if limitString := c.Query(LimitKey); limitString != "" {
|
||||
i, err := strconv.Atoi(limitString)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error parsing %s: %s", LimitKey, err)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
// normalize
|
||||
if i <= 0 {
|
||||
i = 1
|
||||
} else if i >= 100 {
|
||||
i = 100
|
||||
}
|
||||
limit = i
|
||||
page, errWithCode := paging.ParseIDPage(c,
|
||||
1, // min limit
|
||||
100, // max limit
|
||||
20, // default limit
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
resp, errWithCode := m.processor.Report().GetMultiple(c.Request.Context(), authed.Account, resolved, c.Query(TargetAccountIDKey), c.Query(MaxIDKey), c.Query(SinceIDKey), c.Query(MinIDKey), limit)
|
||||
resp, errWithCode := m.processor.Report().GetMultiple(
|
||||
c.Request.Context(),
|
||||
authed.Account,
|
||||
resolved,
|
||||
c.Query(apiutil.TargetAccountIDKey),
|
||||
page,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/api/client/reports"
|
||||
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/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
|
|
@ -61,21 +62,21 @@ func (suite *ReportsGetTestSuite) getReports(
|
|||
ctx.Set(oauth.SessionAuthorizedUser, user)
|
||||
|
||||
// create the request URI
|
||||
requestPath := reports.BasePath + "?" + reports.LimitKey + "=" + strconv.Itoa(limit)
|
||||
requestPath := reports.BasePath + "?" + apiutil.LimitKey + "=" + strconv.Itoa(limit)
|
||||
if resolved != nil {
|
||||
requestPath = requestPath + "&" + reports.ResolvedKey + "=" + strconv.FormatBool(*resolved)
|
||||
requestPath = requestPath + "&" + apiutil.ResolvedKey + "=" + strconv.FormatBool(*resolved)
|
||||
}
|
||||
if targetAccountID != "" {
|
||||
requestPath = requestPath + "&" + reports.TargetAccountIDKey + "=" + targetAccountID
|
||||
requestPath = requestPath + "&" + apiutil.TargetAccountIDKey + "=" + targetAccountID
|
||||
}
|
||||
if maxID != "" {
|
||||
requestPath = requestPath + "&" + reports.MaxIDKey + "=" + maxID
|
||||
requestPath = requestPath + "&" + apiutil.MaxIDKey + "=" + maxID
|
||||
}
|
||||
if sinceID != "" {
|
||||
requestPath = requestPath + "&" + reports.SinceIDKey + "=" + sinceID
|
||||
requestPath = requestPath + "&" + apiutil.SinceIDKey + "=" + sinceID
|
||||
}
|
||||
if minID != "" {
|
||||
requestPath = requestPath + "&" + reports.MinIDKey + "=" + minID
|
||||
requestPath = requestPath + "&" + apiutil.MinIDKey + "=" + minID
|
||||
}
|
||||
baseURI := config.GetProtocol() + "://" + config.GetHost()
|
||||
requestURI := baseURI + "/api/" + requestPath
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ func (m *Module) SearchGETHandler(c *gin.Context) {
|
|||
Resolve: resolve,
|
||||
Following: following,
|
||||
ExcludeUnreviewed: excludeUnreviewed,
|
||||
AccountID: c.Query(apiutil.SearchAccountIDKey),
|
||||
AccountID: c.Query(apiutil.AccountIDKey),
|
||||
APIv1: apiVersion == apiutil.APIv1,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func (suite *SearchGetTestSuite) getSearch(
|
|||
}
|
||||
|
||||
if fromAccountID != nil {
|
||||
queryParts = append(queryParts, apiutil.SearchAccountIDKey+"="+url.QueryEscape(*fromAccountID))
|
||||
queryParts = append(queryParts, apiutil.AccountIDKey+"="+url.QueryEscape(*fromAccountID))
|
||||
}
|
||||
|
||||
requestURL.RawQuery = strings.Join(queryParts, "&")
|
||||
|
|
|
|||
|
|
@ -34,13 +34,16 @@ const (
|
|||
|
||||
/* Common keys */
|
||||
|
||||
IDKey = "id"
|
||||
LimitKey = "limit"
|
||||
LocalKey = "local"
|
||||
MaxIDKey = "max_id"
|
||||
SinceIDKey = "since_id"
|
||||
MinIDKey = "min_id"
|
||||
UsernameKey = "username"
|
||||
IDKey = "id"
|
||||
LimitKey = "limit"
|
||||
LocalKey = "local"
|
||||
MaxIDKey = "max_id"
|
||||
SinceIDKey = "since_id"
|
||||
MinIDKey = "min_id"
|
||||
UsernameKey = "username"
|
||||
AccountIDKey = "account_id"
|
||||
TargetAccountIDKey = "target_account_id"
|
||||
ResolvedKey = "resolved"
|
||||
|
||||
/* AP endpoint keys */
|
||||
|
||||
|
|
@ -55,7 +58,6 @@ const (
|
|||
SearchQueryKey = "q"
|
||||
SearchResolveKey = "resolve"
|
||||
SearchTypeKey = "type"
|
||||
SearchAccountIDKey = "account_id"
|
||||
|
||||
/* Tag keys */
|
||||
|
||||
|
|
@ -132,6 +134,10 @@ func ParseLocal(value string, defaultValue bool) (bool, gtserror.WithCode) {
|
|||
return parseBool(value, defaultValue, LocalKey)
|
||||
}
|
||||
|
||||
func ParseResolved(value string, defaultValue *bool) (*bool, gtserror.WithCode) {
|
||||
return parseBoolPtr(value, defaultValue, ResolvedKey)
|
||||
}
|
||||
|
||||
func ParseSearchExcludeUnreviewed(value string, defaultValue bool) (bool, gtserror.WithCode) {
|
||||
return parseBool(value, defaultValue, SearchExcludeUnreviewedKey)
|
||||
}
|
||||
|
|
@ -289,6 +295,19 @@ func parseBool(value string, defaultValue bool, key string) (bool, gtserror.With
|
|||
return i, nil
|
||||
}
|
||||
|
||||
func parseBoolPtr(value string, defaultValue *bool, key string) (*bool, gtserror.WithCode) {
|
||||
if value == "" {
|
||||
return defaultValue, nil
|
||||
}
|
||||
|
||||
i, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return defaultValue, parseError(key, value, defaultValue, err)
|
||||
}
|
||||
|
||||
return &i, nil
|
||||
}
|
||||
|
||||
func parseInt(value string, defaultValue int, max int, min int, key string) (int, gtserror.WithCode) {
|
||||
if value == "" {
|
||||
return defaultValue, nil
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package bundb
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
|
|
@ -27,6 +28,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
|
@ -51,14 +53,23 @@ func (r *reportDB) GetReportByID(ctx context.Context, id string) (*gtsmodel.Repo
|
|||
)
|
||||
}
|
||||
|
||||
func (r *reportDB) GetReports(ctx context.Context, resolved *bool, accountID string, targetAccountID string, maxID string, sinceID string, minID string, limit int) ([]*gtsmodel.Report, error) {
|
||||
reportIDs := []string{}
|
||||
func (r *reportDB) GetReports(ctx context.Context, resolved *bool, accountID string, targetAccountID string, page *paging.Page) ([]*gtsmodel.Report, error) {
|
||||
var (
|
||||
// Get paging params.
|
||||
minID = page.GetMin()
|
||||
maxID = page.GetMax()
|
||||
limit = page.GetLimit()
|
||||
order = page.GetOrder()
|
||||
|
||||
// Make educated guess for slice size
|
||||
reportIDs = make([]string, 0, limit)
|
||||
)
|
||||
|
||||
q := r.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("reports"), bun.Ident("report")).
|
||||
Column("report.id").
|
||||
Order("report.id DESC")
|
||||
// Select only IDs from table.
|
||||
Column("report.id")
|
||||
|
||||
if resolved != nil {
|
||||
i := bun.Ident("report.action_taken_by_account_id")
|
||||
|
|
@ -77,22 +88,32 @@ func (r *reportDB) GetReports(ctx context.Context, resolved *bool, accountID str
|
|||
q = q.Where("? = ?", bun.Ident("report.target_account_id"), targetAccountID)
|
||||
}
|
||||
|
||||
// Return only reports with id
|
||||
// lower than provided maxID.
|
||||
if maxID != "" {
|
||||
q = q.Where("? < ?", bun.Ident("report.id"), maxID)
|
||||
}
|
||||
|
||||
if sinceID != "" {
|
||||
q = q.Where("? > ?", bun.Ident("report.id"), minID)
|
||||
}
|
||||
|
||||
// Return only reports with id
|
||||
// greater than provided minID.
|
||||
if minID != "" {
|
||||
q = q.Where("? > ?", bun.Ident("report.id"), minID)
|
||||
}
|
||||
|
||||
if limit != 0 {
|
||||
if limit > 0 {
|
||||
// Limit amount of
|
||||
// reports returned.
|
||||
q = q.Limit(limit)
|
||||
}
|
||||
|
||||
if order == paging.OrderAscending {
|
||||
// Page up.
|
||||
q = q.OrderExpr("? ASC", bun.Ident("report.id"))
|
||||
} else {
|
||||
// Page down.
|
||||
q = q.OrderExpr("? DESC", bun.Ident("report.id"))
|
||||
}
|
||||
|
||||
if err := q.Scan(ctx, &reportIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -102,6 +123,12 @@ func (r *reportDB) GetReports(ctx context.Context, resolved *bool, accountID str
|
|||
return nil, db.ErrNoEntries
|
||||
}
|
||||
|
||||
// If we're paging up, we still want reports
|
||||
// to be sorted by ID desc, so reverse ids slice.
|
||||
if order == paging.OrderAscending {
|
||||
slices.Reverse(reportIDs)
|
||||
}
|
||||
|
||||
// Allocate return slice (will be at most len reportIDs)
|
||||
reports := make([]*gtsmodel.Report, 0, len(reportIDs))
|
||||
for _, id := range reportIDs {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/testrig"
|
||||
)
|
||||
|
|
@ -61,14 +63,109 @@ func (suite *ReportTestSuite) TestGetReportByURI() {
|
|||
}
|
||||
|
||||
func (suite *ReportTestSuite) TestGetAllReports() {
|
||||
reports, err := suite.db.GetReports(context.Background(), nil, "", "", "", "", "", 0)
|
||||
reports, err := suite.db.GetReports(
|
||||
context.Background(),
|
||||
nil,
|
||||
"",
|
||||
"",
|
||||
&paging.Page{},
|
||||
)
|
||||
suite.NoError(err)
|
||||
suite.NotEmpty(reports)
|
||||
}
|
||||
|
||||
func (suite *ReportTestSuite) TestReportPagingDown() {
|
||||
// Get one from the top.
|
||||
reports1, err := suite.db.GetReports(
|
||||
context.Background(),
|
||||
nil,
|
||||
"",
|
||||
"",
|
||||
&paging.Page{
|
||||
Limit: 1,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
if l := len(reports1); l != 1 {
|
||||
suite.FailNowf("", "expected reports len 1, got %d", l)
|
||||
}
|
||||
id1 := reports1[0].ID
|
||||
|
||||
// Use this one to page down.
|
||||
reports2, err := suite.db.GetReports(
|
||||
context.Background(),
|
||||
nil,
|
||||
"",
|
||||
"",
|
||||
&paging.Page{
|
||||
Limit: 1,
|
||||
Max: paging.MaxID(id1),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
if l := len(reports2); l != 1 {
|
||||
suite.FailNowf("", "expected reports len 1, got %d", l)
|
||||
}
|
||||
id2 := reports2[0].ID
|
||||
|
||||
suite.Greater(id1, id2)
|
||||
}
|
||||
|
||||
func (suite *ReportTestSuite) TestReportPagingUp() {
|
||||
// Get one from the bottom.
|
||||
reports1, err := suite.db.GetReports(
|
||||
context.Background(),
|
||||
nil,
|
||||
"",
|
||||
"",
|
||||
&paging.Page{
|
||||
Limit: 1,
|
||||
Min: paging.MinID(id.Lowest),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
if l := len(reports1); l != 1 {
|
||||
suite.FailNowf("", "expected reports len 1, got %d", l)
|
||||
}
|
||||
id1 := reports1[0].ID
|
||||
|
||||
// Use this one to page up.
|
||||
reports2, err := suite.db.GetReports(
|
||||
context.Background(),
|
||||
nil,
|
||||
"",
|
||||
"",
|
||||
&paging.Page{
|
||||
Limit: 1,
|
||||
Min: paging.MinID(id1),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
suite.FailNow(err.Error())
|
||||
}
|
||||
if l := len(reports2); l != 1 {
|
||||
suite.FailNowf("", "expected reports len 1, got %d", l)
|
||||
}
|
||||
id2 := reports2[0].ID
|
||||
|
||||
suite.Less(id1, id2)
|
||||
}
|
||||
|
||||
func (suite *ReportTestSuite) TestGetAllReportsByAccountID() {
|
||||
accountID := suite.testAccounts["local_account_2"].ID
|
||||
reports, err := suite.db.GetReports(context.Background(), nil, accountID, "", "", "", "", 0)
|
||||
reports, err := suite.db.GetReports(
|
||||
context.Background(),
|
||||
nil,
|
||||
accountID,
|
||||
"",
|
||||
&paging.Page{},
|
||||
)
|
||||
suite.NoError(err)
|
||||
suite.NotEmpty(reports)
|
||||
for _, r := range reports {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// Report handles getting/creation/deletion/updating of user reports/flags.
|
||||
|
|
@ -30,7 +31,7 @@ type Report interface {
|
|||
|
||||
// GetReports gets limit n reports using the given parameters.
|
||||
// Parameters that are empty / zero are ignored.
|
||||
GetReports(ctx context.Context, resolved *bool, accountID string, targetAccountID string, maxID string, sinceID string, minID string, limit int) ([]*gtsmodel.Report, error)
|
||||
GetReports(ctx context.Context, resolved *bool, accountID string, targetAccountID string, page *paging.Page) ([]*gtsmodel.Report, error)
|
||||
|
||||
// PopulateReport populates the struct pointers on the given report.
|
||||
PopulateReport(ctx context.Context, report *gtsmodel.Report) error
|
||||
|
|
|
|||
|
|
@ -21,73 +21,81 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/ap"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/messages"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// ReportsGet returns all reports stored on this instance, with the given parameters.
|
||||
// ReportsGet returns reports stored on this
|
||||
// instance, with the given parameters.
|
||||
func (p *Processor) ReportsGet(
|
||||
ctx context.Context,
|
||||
account *gtsmodel.Account,
|
||||
resolved *bool,
|
||||
accountID string,
|
||||
targetAccountID string,
|
||||
maxID string,
|
||||
sinceID string,
|
||||
minID string,
|
||||
limit int,
|
||||
page *paging.Page,
|
||||
) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||
reports, err := p.state.DB.GetReports(ctx, resolved, accountID, targetAccountID, maxID, sinceID, minID, limit)
|
||||
reports, err := p.state.DB.GetReports(
|
||||
ctx,
|
||||
resolved,
|
||||
accountID,
|
||||
targetAccountID,
|
||||
page,
|
||||
)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
count := len(reports)
|
||||
if count == 0 {
|
||||
return util.EmptyPageableResponse(), nil
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
var (
|
||||
items = make([]interface{}, 0, count)
|
||||
nextMaxIDValue = reports[count-1].ID
|
||||
prevMinIDValue = reports[0].ID
|
||||
)
|
||||
// Get the lowest and highest
|
||||
// ID values, used for paging.
|
||||
lo := reports[count-1].ID
|
||||
hi := reports[0].ID
|
||||
|
||||
// Convert each report to API model.
|
||||
items := make([]interface{}, 0, count)
|
||||
for _, r := range reports {
|
||||
item, err := p.converter.ReportToAdminAPIReport(ctx, r, account)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting report to api: %s", err))
|
||||
err := fmt.Errorf("error converting report to api: %s", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
extraQueryParams := make([]string, 0, 3)
|
||||
// Assemble next/prev page queries.
|
||||
query := make(url.Values, 3)
|
||||
if resolved != nil {
|
||||
extraQueryParams = append(extraQueryParams, "resolved="+strconv.FormatBool(*resolved))
|
||||
query.Set(apiutil.ResolvedKey, strconv.FormatBool(*resolved))
|
||||
}
|
||||
if accountID != "" {
|
||||
extraQueryParams = append(extraQueryParams, "account_id="+accountID)
|
||||
query.Set(apiutil.AccountIDKey, accountID)
|
||||
}
|
||||
if targetAccountID != "" {
|
||||
extraQueryParams = append(extraQueryParams, "target_account_id="+targetAccountID)
|
||||
query.Set(apiutil.TargetAccountIDKey, targetAccountID)
|
||||
}
|
||||
|
||||
return util.PackagePageableResponse(util.PageableResponseParams{
|
||||
Items: items,
|
||||
Path: "/api/v1/admin/reports",
|
||||
NextMaxIDValue: nextMaxIDValue,
|
||||
PrevMinIDValue: prevMinIDValue,
|
||||
Limit: limit,
|
||||
ExtraQueryParams: extraQueryParams,
|
||||
})
|
||||
return paging.PackageResponse(paging.ResponseParams{
|
||||
Items: items,
|
||||
Path: "/api/v1/admin/reports",
|
||||
Next: page.Next(lo, hi),
|
||||
Prev: page.Prev(lo, hi),
|
||||
Query: query,
|
||||
}), nil
|
||||
}
|
||||
|
||||
// ReportGet returns one report, with the given ID.
|
||||
|
|
|
|||
|
|
@ -21,13 +21,15 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// Get returns the user view of a moderation report, with the given id.
|
||||
|
|
@ -53,53 +55,61 @@ func (p *Processor) Get(ctx context.Context, account *gtsmodel.Account, id strin
|
|||
return apiReport, nil
|
||||
}
|
||||
|
||||
// GetMultiple returns multiple reports created by the given account, filtered according to the provided parameters.
|
||||
// GetMultiple returns reports created by the given account,
|
||||
// filtered according to the provided parameters.
|
||||
func (p *Processor) GetMultiple(
|
||||
ctx context.Context,
|
||||
account *gtsmodel.Account,
|
||||
resolved *bool,
|
||||
targetAccountID string,
|
||||
maxID string,
|
||||
sinceID string,
|
||||
minID string,
|
||||
limit int,
|
||||
page *paging.Page,
|
||||
) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||
reports, err := p.state.DB.GetReports(ctx, resolved, account.ID, targetAccountID, maxID, sinceID, minID, limit)
|
||||
reports, err := p.state.DB.GetReports(
|
||||
ctx,
|
||||
resolved,
|
||||
account.ID,
|
||||
targetAccountID,
|
||||
page,
|
||||
)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
count := len(reports)
|
||||
if count == 0 {
|
||||
return util.EmptyPageableResponse(), nil
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0, count)
|
||||
nextMaxIDValue := reports[count-1].ID
|
||||
prevMinIDValue := reports[0].ID
|
||||
// Get the lowest and highest
|
||||
// ID values, used for paging.
|
||||
lo := reports[count-1].ID
|
||||
hi := reports[0].ID
|
||||
|
||||
// Convert each report to API model.
|
||||
items := make([]interface{}, 0, count)
|
||||
for _, r := range reports {
|
||||
item, err := p.converter.ReportToAPIReport(ctx, r)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting report to api: %s", err))
|
||||
err := fmt.Errorf("error converting report to api: %s", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
extraQueryParams := []string{}
|
||||
// Assemble next/prev page queries.
|
||||
query := make(url.Values, 3)
|
||||
if resolved != nil {
|
||||
extraQueryParams = append(extraQueryParams, "resolved="+strconv.FormatBool(*resolved))
|
||||
query.Set(apiutil.ResolvedKey, strconv.FormatBool(*resolved))
|
||||
}
|
||||
if targetAccountID != "" {
|
||||
extraQueryParams = append(extraQueryParams, "target_account_id="+targetAccountID)
|
||||
query.Set(apiutil.TargetAccountIDKey, targetAccountID)
|
||||
}
|
||||
|
||||
return util.PackagePageableResponse(util.PageableResponseParams{
|
||||
Items: items,
|
||||
Path: "/api/v1/reports",
|
||||
NextMaxIDValue: nextMaxIDValue,
|
||||
PrevMinIDValue: prevMinIDValue,
|
||||
Limit: limit,
|
||||
ExtraQueryParams: extraQueryParams,
|
||||
})
|
||||
return paging.PackageResponse(paging.ResponseParams{
|
||||
Items: items,
|
||||
Path: "/api/v1/reports",
|
||||
Next: page.Next(lo, hi),
|
||||
Prev: page.Prev(lo, hi),
|
||||
Query: query,
|
||||
}), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue