Skip to content

Commit

Permalink
[feature/frontend] Reports frontend v2 (#3022)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
tsmethurst authored Jun 18, 2024
1 parent b08c1bd commit d2b3d37
Show file tree
Hide file tree
Showing 56 changed files with 1,386 additions and 723 deletions.
4 changes: 3 additions & 1 deletion docs/admin/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ Instance moderation settings.

### Reports

![List of reports for testing, one resolved and one open.](../assets/admin-settings-reports.png)
![List of reports for testing, showing one open report.](../assets/admin-settings-reports.png)

The reports section shows a list of reports, originating from your local users, or remote instances (shown anonymously as just the name of the instance, without specific username).

Clicking a report shows if it was resolved (with the reasoning if available), more information, and a list of reported toots if selected by the reporting user. You can also use this view to mark a report as resolved, and fill in a comment. Whatever comment you enter here will be visible to the user that created the report, if that user is from your instance.

![The detailed view of an open report, showing the reported status and the reason for the report.](../assets/admin-settings-report-detail.png)

Clicking on the username of the reported account opens that account in the 'Accounts' view, allowing you to perform moderation actions on it.

### Accounts
Expand Down
22 changes: 14 additions & 8 deletions docs/api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4525,6 +4525,8 @@ paths:
- default: 50
description: Number of emojis to return. Less than 1, or not set, means unlimited (all emojis).
in: query
maximum: 200
minimum: 0
name: limit
type: integer
- description: |-
Expand Down Expand Up @@ -5739,21 +5741,23 @@ paths:
in: query
name: target_account_id
type: string
- description: Return only reports *OLDER* than the given max ID. The report with the specified ID will not be included in the response.
- description: 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
name: max_id
type: string
- 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.
- description: Return only reports *NEWER* than the given since ID. The report with the specified ID will not be included in the response.
in: query
name: since_id
type: string
- description: Return only reports *NEWER* than the given min ID. The report with the specified ID will not be included in the response. This parameter is functionally equivalent to since_id.
- description: 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.
in: query
name: min_id
type: string
- default: 20
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.
in: query
maximum: 100
minimum: 1
name: limit
type: integer
produces:
Expand Down Expand Up @@ -7707,21 +7711,23 @@ paths:
in: query
name: target_account_id
type: string
- description: Return only reports *OLDER* than the given max ID. The report with the specified ID will not be included in the response.
- description: 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
name: max_id
type: string
- 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.
- description: Return only reports *NEWER* than the given since ID. The report with the specified ID will not be included in the response.
in: query
name: since_id
type: string
- description: Return only reports *NEWER* than the given min ID. The report with the specified ID will not be included in the response. This parameter is functionally equivalent to since_id.
- description: 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.
in: query
name: min_id
type: string
- default: 20
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.
in: query
maximum: 100
minimum: 1
name: limit
type: integer
produces:
Expand Down
Binary file added docs/assets/admin-settings-report-detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/admin-settings-reports.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 3 additions & 4 deletions internal/api/client/admin/accountaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 9 additions & 16 deletions internal/api/client/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,48 @@ 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"
)

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 {
Expand Down
8 changes: 3 additions & 5 deletions internal/api/client/admin/emojidelete.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package admin

import (
"errors"
"fmt"
"net/http"

Expand Down Expand Up @@ -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
}

Expand Down
7 changes: 4 additions & 3 deletions internal/api/client/admin/emojidelete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
8 changes: 3 additions & 5 deletions internal/api/client/admin/emojiget.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package admin

import (
"errors"
"fmt"
"net/http"

Expand Down Expand Up @@ -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
}

Expand Down
7 changes: 4 additions & 3 deletions internal/api/client/admin/emojiget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 6 additions & 14 deletions internal/api/client/admin/emojisget.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package admin
import (
"fmt"
"net/http"
"strconv"
"strings"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions internal/api/client/admin/emojiupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
Loading

0 comments on commit d2b3d37

Please sign in to comment.