[MODERATION] add user blocking API
- Follow up for: #540, #802 - Add API routes for user blocking from user and organization perspective. - The new routes have integration testing. - The new model functions have unit tests. - Actually quite boring to write and to read this pull request. (cherry picked from commit f3afaf15c7e34038363c9ce8e1ef957ec1e22b06) (cherry picked from commit 6d754db3e5faff93a58fab2867737f81f40f6599) (cherry picked from commit d0fc8bc9d3b6bb189a2ab634a5329253af9b4629) (cherry picked from commit 9a53b0d1a07455596622cb02716b476b6aaa95e4) (cherry picked from commit 44a2a4fd48678058777d6db46c13a2c7298497d4) (cherry picked from commit 182025db9cc76073bdb0221dfd1fb3b2b66f7fd4) (cherry picked from commit 558a35963eddd672f1911393a649ab08a9283e5b)
This commit is contained in:
parent
cdf6318f51
commit
73776d6195
12 changed files with 626 additions and 9 deletions
|
@ -52,18 +52,29 @@ func UnblockUser(ctx context.Context, userID, blockID int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountBlockedUsers returns the number of users the user has blocked.
|
||||||
|
func CountBlockedUsers(ctx context.Context, userID int64) (int64, error) {
|
||||||
|
return db.GetEngine(ctx).Where("user_id=?", userID).Count(&BlockedUser{})
|
||||||
|
}
|
||||||
|
|
||||||
// ListBlockedUsers returns the users that the user has blocked.
|
// ListBlockedUsers returns the users that the user has blocked.
|
||||||
// The created_unix field of the user struct is overridden by the creation_unix
|
// The created_unix field of the user struct is overridden by the creation_unix
|
||||||
// field of blockeduser.
|
// field of blockeduser.
|
||||||
func ListBlockedUsers(ctx context.Context, userID int64) ([]*User, error) {
|
func ListBlockedUsers(ctx context.Context, userID int64, opts db.ListOptions) ([]*User, error) {
|
||||||
users := make([]*User, 0, 8)
|
sess := db.GetEngine(ctx).
|
||||||
err := db.GetEngine(ctx).
|
|
||||||
Select("`forgejo_blocked_user`.created_unix, `user`.*").
|
Select("`forgejo_blocked_user`.created_unix, `user`.*").
|
||||||
Join("INNER", "forgejo_blocked_user", "`user`.id=`forgejo_blocked_user`.block_id").
|
Join("INNER", "forgejo_blocked_user", "`user`.id=`forgejo_blocked_user`.block_id").
|
||||||
Where("`forgejo_blocked_user`.user_id=?", userID).
|
Where("`forgejo_blocked_user`.user_id=?", userID)
|
||||||
Find(&users)
|
|
||||||
|
|
||||||
return users, err
|
if opts.Page > 0 {
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
users := make([]*User, 0, opts.PageSize)
|
||||||
|
|
||||||
|
return users, sess.Find(&users)
|
||||||
|
}
|
||||||
|
|
||||||
|
users := make([]*User, 0, 8)
|
||||||
|
return users, sess.Find(&users)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListBlockedByUsersID returns the ids of the users that blocked the user.
|
// ListBlockedByUsersID returns the ids of the users that blocked the user.
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestUnblockUser(t *testing.T) {
|
||||||
func TestListBlockedUsers(t *testing.T) {
|
func TestListBlockedUsers(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
blockedUsers, err := user_model.ListBlockedUsers(db.DefaultContext, 4)
|
blockedUsers, err := user_model.ListBlockedUsers(db.DefaultContext, 4, db.ListOptions{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, blockedUsers, 1) {
|
if assert.Len(t, blockedUsers, 1) {
|
||||||
assert.EqualValues(t, 1, blockedUsers[0].ID)
|
assert.EqualValues(t, 1, blockedUsers[0].ID)
|
||||||
|
@ -61,3 +61,15 @@ func TestListBlockedByUsersID(t *testing.T) {
|
||||||
assert.EqualValues(t, 4, blockedByUserIDs[0])
|
assert.EqualValues(t, 4, blockedByUserIDs[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCountBlockedUsers(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
count, err := user_model.CountBlockedUsers(db.DefaultContext, 4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, count)
|
||||||
|
|
||||||
|
count, err = user_model.CountBlockedUsers(db.DefaultContext, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0, count)
|
||||||
|
}
|
||||||
|
|
13
modules/structs/moderation.go
Normal file
13
modules/structs/moderation.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// BlockedUser represents a blocked user.
|
||||||
|
type BlockedUser struct {
|
||||||
|
BlockID int64 `json:"block_id"`
|
||||||
|
// swagger:strfmt date-time
|
||||||
|
Created time.Time `json:"created_at"`
|
||||||
|
}
|
|
@ -905,6 +905,12 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
Patch(bind(api.EditHookOption{}), user.EditHook).
|
Patch(bind(api.EditHookOption{}), user.EditHook).
|
||||||
Delete(user.DeleteHook)
|
Delete(user.DeleteHook)
|
||||||
}, reqWebhooksEnabled())
|
}, reqWebhooksEnabled())
|
||||||
|
|
||||||
|
m.Group("", func() {
|
||||||
|
m.Get("/list_blocked", user.ListBlockedUsers)
|
||||||
|
m.Put("/block/{username}", user.BlockUser)
|
||||||
|
m.Put("/unblock/{username}", user.UnblockUser)
|
||||||
|
})
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
|
||||||
|
|
||||||
// Repositories (requires repo scope, org scope)
|
// Repositories (requires repo scope, org scope)
|
||||||
|
@ -1321,6 +1327,12 @@ func Routes(ctx gocontext.Context) *web.Route {
|
||||||
Delete(org.DeleteHook)
|
Delete(org.DeleteHook)
|
||||||
}, reqToken(), reqOrgOwnership(), reqWebhooksEnabled())
|
}, reqToken(), reqOrgOwnership(), reqWebhooksEnabled())
|
||||||
m.Get("/activities/feeds", org.ListOrgActivityFeeds)
|
m.Get("/activities/feeds", org.ListOrgActivityFeeds)
|
||||||
|
|
||||||
|
m.Group("", func() {
|
||||||
|
m.Get("/list_blocked", reqToken(), reqOrgOwnership(), org.ListBlockedUsers)
|
||||||
|
m.Put("/block/{username}", reqToken(), reqOrgOwnership(), org.BlockUser)
|
||||||
|
m.Put("/unblock/{username}", reqToken(), reqOrgOwnership(), org.UnblockUser)
|
||||||
|
}, reqToken(), reqOrgOwnership())
|
||||||
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true))
|
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true))
|
||||||
m.Group("/teams/{teamid}", func() {
|
m.Group("/teams/{teamid}", func() {
|
||||||
m.Combo("").Get(reqToken(), org.GetTeam).
|
m.Combo("").Get(reqToken(), org.GetTeam).
|
||||||
|
|
|
@ -437,3 +437,95 @@ func ListOrgActivityFeeds(ctx *context.APIContext) {
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer))
|
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListBlockedUsers list the organization's blocked users.
|
||||||
|
func ListBlockedUsers(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /orgs/{org}/list_blocked organization orgListBlockedUsers
|
||||||
|
// ---
|
||||||
|
// summary: List the organization's blocked users
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: org
|
||||||
|
// in: path
|
||||||
|
// description: name of the org
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: page
|
||||||
|
// in: query
|
||||||
|
// description: page number of results to return (1-based)
|
||||||
|
// type: integer
|
||||||
|
// - name: limit
|
||||||
|
// in: query
|
||||||
|
// description: page size of results
|
||||||
|
// type: integer
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/BlockedUserList"
|
||||||
|
|
||||||
|
utils.ListUserBlockedUsers(ctx, ctx.ContextUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockUser blocks a user from the organization.
|
||||||
|
func BlockUser(ctx *context.APIContext) {
|
||||||
|
// swagger:operation PUT /orgs/{org}/block/{username} organization orgBlockUser
|
||||||
|
// ---
|
||||||
|
// summary: Blocks a user from the organization
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: org
|
||||||
|
// in: path
|
||||||
|
// description: name of the org
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of the user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
user := user.GetUserByParams(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.BlockUser(ctx, ctx.Org.Organization.AsUser(), user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnblockUser unblocks a user from the organization.
|
||||||
|
func UnblockUser(ctx *context.APIContext) {
|
||||||
|
// swagger:operation PUT /orgs/{org}/unblock/{username} organization orgUnblockUser
|
||||||
|
// ---
|
||||||
|
// summary: Unblock a user from the organization
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: org
|
||||||
|
// in: path
|
||||||
|
// description: name of the org
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of the user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
user := user.GetUserByParams(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.UnblockUser(ctx, ctx.Org.Organization.AsUser(), user)
|
||||||
|
}
|
||||||
|
|
|
@ -414,3 +414,10 @@ type swaggerRepoNewIssuePinsAllowed struct {
|
||||||
// in:body
|
// in:body
|
||||||
Body api.NewIssuePinsAllowed `json:"body"`
|
Body api.NewIssuePinsAllowed `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockedUserList
|
||||||
|
// swagger:response BlockedUserList
|
||||||
|
type swaggerBlockedUserList struct {
|
||||||
|
// in:body
|
||||||
|
Body []api.BlockedUser `json:"body"`
|
||||||
|
}
|
||||||
|
|
|
@ -202,3 +202,80 @@ func ListUserActivityFeeds(ctx *context.APIContext) {
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer))
|
ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListBlockedUsers list the authenticated user's blocked users.
|
||||||
|
func ListBlockedUsers(ctx *context.APIContext) {
|
||||||
|
// swagger:operation GET /user/list_blocked user userListBlockedUsers
|
||||||
|
// ---
|
||||||
|
// summary: List the authenticated user's blocked users
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: page
|
||||||
|
// in: query
|
||||||
|
// description: page number of results to return (1-based)
|
||||||
|
// type: integer
|
||||||
|
// - name: limit
|
||||||
|
// in: query
|
||||||
|
// description: page size of results
|
||||||
|
// type: integer
|
||||||
|
// responses:
|
||||||
|
// "200":
|
||||||
|
// "$ref": "#/responses/BlockedUserList"
|
||||||
|
|
||||||
|
utils.ListUserBlockedUsers(ctx, ctx.Doer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockUser blocks a user from the doer.
|
||||||
|
func BlockUser(ctx *context.APIContext) {
|
||||||
|
// swagger:operation PUT /user/block/{username} user userBlockUser
|
||||||
|
// ---
|
||||||
|
// summary: Blocks a user from the doer.
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of the user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
user := GetUserByParams(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.BlockUser(ctx, ctx.Doer, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnblockUser unblocks a user from the doer.
|
||||||
|
func UnblockUser(ctx *context.APIContext) {
|
||||||
|
// swagger:operation PUT /user/unblock/{username} user userUnblockUser
|
||||||
|
// ---
|
||||||
|
// summary: Unblocks a user from the doer.
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
// parameters:
|
||||||
|
// - name: username
|
||||||
|
// in: path
|
||||||
|
// description: username of the user
|
||||||
|
// type: string
|
||||||
|
// required: true
|
||||||
|
// responses:
|
||||||
|
// "204":
|
||||||
|
// "$ref": "#/responses/empty"
|
||||||
|
// "404":
|
||||||
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
|
user := GetUserByParams(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.UnblockUser(ctx, ctx.Doer, user)
|
||||||
|
}
|
||||||
|
|
65
routers/api/v1/utils/block.go
Normal file
65
routers/api/v1/utils/block.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListUserBlockedUsers lists the blocked users of the provided doer.
|
||||||
|
func ListUserBlockedUsers(ctx *context.APIContext, doer *user_model.User) {
|
||||||
|
count, err := user_model.CountBlockedUsers(ctx, doer.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.InternalServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
blockedUsers, err := user_model.ListBlockedUsers(ctx, doer.ID, GetListOptions(ctx))
|
||||||
|
if err != nil {
|
||||||
|
ctx.InternalServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apiBlockedUsers := make([]*api.BlockedUser, len(blockedUsers))
|
||||||
|
for i, blockedUser := range blockedUsers {
|
||||||
|
apiBlockedUsers[i] = &api.BlockedUser{
|
||||||
|
BlockID: blockedUser.ID,
|
||||||
|
Created: blockedUser.CreatedUnix.AsTime(),
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
ctx.InternalServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetTotalCountHeader(count)
|
||||||
|
ctx.JSON(http.StatusOK, apiBlockedUsers)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockUser blocks the blockUser from the doer.
|
||||||
|
func BlockUser(ctx *context.APIContext, doer, blockUser *user_model.User) {
|
||||||
|
err := user_service.BlockUser(ctx, doer.ID, blockUser.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.InternalServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnblockUser unblocks the blockUser from the doer.
|
||||||
|
func UnblockUser(ctx *context.APIContext, doer, blockUser *user_model.User) {
|
||||||
|
err := user_model.UnblockUser(ctx, doer.ID, blockUser.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.InternalServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(http.StatusNoContent)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/routers/utils"
|
"code.gitea.io/gitea/routers/utils"
|
||||||
|
@ -20,7 +21,7 @@ func BlockedUsers(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("settings.blocked_users")
|
ctx.Data["Title"] = ctx.Tr("settings.blocked_users")
|
||||||
ctx.Data["PageIsSettingsBlockedUsers"] = true
|
ctx.Data["PageIsSettingsBlockedUsers"] = true
|
||||||
|
|
||||||
blockedUsers, err := user_model.ListBlockedUsers(ctx, ctx.Org.Organization.ID)
|
blockedUsers, err := user_model.ListBlockedUsers(ctx, ctx.Org.Organization.ID, db.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ListBlockedUsers", err)
|
ctx.ServerError("ListBlockedUsers", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -6,6 +6,7 @@ package setting
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
@ -23,7 +24,7 @@ func BlockedUsers(ctx *context.Context) {
|
||||||
ctx.Data["BaseLink"] = setting.AppSubURL + "/user/settings/blocked_users"
|
ctx.Data["BaseLink"] = setting.AppSubURL + "/user/settings/blocked_users"
|
||||||
ctx.Data["BaseLinkNew"] = setting.AppSubURL + "/user/settings/blocked_users"
|
ctx.Data["BaseLinkNew"] = setting.AppSubURL + "/user/settings/blocked_users"
|
||||||
|
|
||||||
blockedUsers, err := user_model.ListBlockedUsers(ctx, ctx.Doer.ID)
|
blockedUsers, err := user_model.ListBlockedUsers(ctx, ctx.Doer.ID, db.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ListBlockedUsers", err)
|
ctx.ServerError("ListBlockedUsers", err)
|
||||||
return
|
return
|
||||||
|
|
225
templates/swagger/v1_json.tmpl
generated
225
templates/swagger/v1_json.tmpl
generated
|
@ -1595,6 +1595,42 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/orgs/{org}/block/{username}": {
|
||||||
|
"put": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"organization"
|
||||||
|
],
|
||||||
|
"summary": "Blocks a user from the organization",
|
||||||
|
"operationId": "orgBlockUser",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the org",
|
||||||
|
"name": "org",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "username of the user",
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/orgs/{org}/hooks": {
|
"/orgs/{org}/hooks": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -1959,6 +1995,44 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/orgs/{org}/list_blocked": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"organization"
|
||||||
|
],
|
||||||
|
"summary": "List the organization's blocked users",
|
||||||
|
"operationId": "orgListBlockedUsers",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the org",
|
||||||
|
"name": "org",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page number of results to return (1-based)",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page size of results",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/BlockedUserList"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/orgs/{org}/members": {
|
"/orgs/{org}/members": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -2423,6 +2497,42 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/orgs/{org}/unblock/{username}": {
|
||||||
|
"put": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"organization"
|
||||||
|
],
|
||||||
|
"summary": "Unblock a user from the organization",
|
||||||
|
"operationId": "orgUnblockUser",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "name of the org",
|
||||||
|
"name": "org",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "username of the user",
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/packages/{owner}": {
|
"/packages/{owner}": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -13790,6 +13900,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/block/{username}": {
|
||||||
|
"put": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Blocks a user from the doer.",
|
||||||
|
"operationId": "userBlockUser",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "username of the user",
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user/emails": {
|
"/user/emails": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -14439,6 +14578,37 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/list_blocked": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "List the authenticated user's blocked users",
|
||||||
|
"operationId": "userListBlockedUsers",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page number of results to return (1-based)",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page size of results",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"$ref": "#/responses/BlockedUserList"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/user/orgs": {
|
"/user/orgs": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -14840,6 +15010,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/user/unblock/{username}": {
|
||||||
|
"put": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Unblocks a user from the doer.",
|
||||||
|
"operationId": "userUnblockUser",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "username of the user",
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/users/search": {
|
"/users/search": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -15770,6 +15969,23 @@
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
},
|
},
|
||||||
|
"BlockedUser": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "BlockedUser represents a blocked user.",
|
||||||
|
"properties": {
|
||||||
|
"block_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "BlockID"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"x-go-name": "Created"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
|
},
|
||||||
"Branch": {
|
"Branch": {
|
||||||
"description": "Branch represents a repository branch",
|
"description": "Branch represents a repository branch",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -21953,6 +22169,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"BlockedUserList": {
|
||||||
|
"description": "BlockedUserList",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/BlockedUser"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Branch": {
|
"Branch": {
|
||||||
"description": "Branch",
|
"description": "Branch",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
101
tests/integration/api_block_test.go
Normal file
101
tests/integration/api_block_test.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIUserBlock(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
user := "user4"
|
||||||
|
session := loginUser(t, user)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser)
|
||||||
|
|
||||||
|
t.Run("BlockUser", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/block/user2?token=%s", token))
|
||||||
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &user_model.BlockedUser{UserID: 4, BlockID: 2})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ListBlocked", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/list_blocked?token=%s", token))
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
// One user just got blocked and the other one is defined in the fixtures.
|
||||||
|
assert.Equal(t, "2", resp.Header().Get("X-Total-Count"))
|
||||||
|
|
||||||
|
var blockedUsers []api.BlockedUser
|
||||||
|
DecodeJSON(t, resp, &blockedUsers)
|
||||||
|
assert.Len(t, blockedUsers, 2)
|
||||||
|
assert.EqualValues(t, 1, blockedUsers[0].BlockID)
|
||||||
|
assert.EqualValues(t, 2, blockedUsers[1].BlockID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UnblockUser", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/unblock/user2?token=%s", token))
|
||||||
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{UserID: 4, BlockID: 2})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAPIOrgBlock(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
user := "user5"
|
||||||
|
org := "user6"
|
||||||
|
session := loginUser(t, user)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
|
||||||
|
|
||||||
|
t.Run("BlockUser", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/orgs/%s/block/user2?token=%s", org, token))
|
||||||
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &user_model.BlockedUser{UserID: 6, BlockID: 2})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ListBlocked", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/%s/list_blocked?token=%s", org, token))
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
assert.Equal(t, "1", resp.Header().Get("X-Total-Count"))
|
||||||
|
|
||||||
|
var blockedUsers []api.BlockedUser
|
||||||
|
DecodeJSON(t, resp, &blockedUsers)
|
||||||
|
assert.Len(t, blockedUsers, 1)
|
||||||
|
assert.EqualValues(t, 2, blockedUsers[0].BlockID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("UnblockUser", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/orgs/%s/unblock/user2?token=%s", org, token))
|
||||||
|
MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
|
||||||
|
unittest.AssertNotExistsBean(t, &user_model.BlockedUser{UserID: 6, BlockID: 2})
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue