Files

347 lines
9.1 KiB
Go
Raw Permalink Normal View History

// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package org
import (
2019-12-20 18:07:12 +01:00
"net/http"
2021-11-16 18:18:25 +00:00
"net/url"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
2019-08-23 09:40:30 -07:00
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/user"
2020-01-24 19:00:29 +00:00
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
2022-12-29 03:57:15 +01:00
"code.gitea.io/gitea/services/convert"
org_service "code.gitea.io/gitea/services/org"
)
// listMembers list an organization's members
func listMembers(ctx *context.APIContext, isMember bool) {
2026-02-06 14:12:05 +01:00
listOptions := utils.GetListOptions(ctx)
opts := &organization.FindOrgMembersOpts{
Doer: ctx.Doer,
IsDoerMember: isMember,
OrgID: ctx.Org.Organization.ID,
2026-02-06 14:12:05 +01:00
ListOptions: listOptions,
2021-08-12 14:43:08 +02:00
}
count, err := organization.CountOrgMembers(ctx, opts)
2021-08-12 14:43:08 +02:00
if err != nil {
2025-02-17 14:13:17 +08:00
ctx.APIErrorInternal(err)
2021-08-12 14:43:08 +02:00
return
}
2023-09-14 19:09:32 +02:00
members, _, err := organization.FindOrgMembers(ctx, opts)
if err != nil {
2025-02-17 14:13:17 +08:00
ctx.APIErrorInternal(err)
return
}
apiMembers := make([]*api.User, len(members))
for i, member := range members {
apiMembers[i] = convert.ToUser(ctx, member, ctx.Doer)
}
2026-03-08 15:35:50 +01:00
ctx.SetLinkHeader(count, listOptions.PageSize)
2021-08-12 14:43:08 +02:00
ctx.SetTotalCountHeader(count)
2019-12-20 18:07:12 +01:00
ctx.JSON(http.StatusOK, apiMembers)
}
// ListMembers list an organization's members
func ListMembers(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /orgs/{org}/members organization orgListMembers
// ---
// summary: List an organization's members
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
2020-01-24 19:00:29 +00:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
2020-01-24 19:00:29 +00:00
// type: integer
2017-11-12 23:02:25 -08:00
// responses:
// "200":
// "$ref": "#/responses/UserList"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
var (
isMember bool
err error
)
2022-03-22 08:03:22 +01:00
if ctx.Doer != nil {
isMember, err = ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID)
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
return
}
}
listMembers(ctx, isMember)
}
// ListPublicMembers list an organization's public members
func ListPublicMembers(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /orgs/{org}/public_members organization orgListPublicMembers
// ---
// summary: List an organization's public members
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
2020-01-24 19:00:29 +00:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
2020-01-24 19:00:29 +00:00
// type: integer
2017-11-12 23:02:25 -08:00
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/UserList"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
listMembers(ctx, false)
}
// IsMember check if a user is a member of an organization
func IsMember(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /orgs/{org}/members/{username} organization orgIsMember
// ---
// summary: Check if a user is a member of an organization
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
// - name: username
// in: path
// description: username of the user to check for an organization membership
2017-11-12 23:02:25 -08:00
// type: string
// required: true
// responses:
// "204":
// description: user is a member
// "303":
2019-12-20 18:07:12 +01:00
// description: redirection to /orgs/{org}/public_members/{username}
2017-11-12 23:02:25 -08:00
// "404":
// description: user is not a member
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
userToCheck := user.GetContextUserByPathParam(ctx)
2017-06-07 12:10:35 -04:00
if ctx.Written() {
return
}
2022-03-22 08:03:22 +01:00
if ctx.Doer != nil {
userIsMember, err := ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID)
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
return
2022-03-22 08:03:22 +01:00
} else if userIsMember || ctx.Doer.IsAdmin {
userToCheckIsMember, err := ctx.Org.Organization.IsOrgMember(ctx, userToCheck.ID)
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
} else if userToCheckIsMember {
2019-12-20 18:07:12 +01:00
ctx.Status(http.StatusNoContent)
} else {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
}
return
2022-03-22 08:03:22 +01:00
} else if ctx.Doer.ID == userToCheck.ID {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
return
}
}
2021-11-16 18:18:25 +00:00
redirectURL := setting.AppSubURL + "/api/v1/orgs/" + url.PathEscape(ctx.Org.Organization.Name) + "/public_members/" + url.PathEscape(userToCheck.Name)
ctx.Redirect(redirectURL)
}
// IsPublicMember check if a user is a public member of an organization
func IsPublicMember(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation GET /orgs/{org}/public_members/{username} organization orgIsPublicMember
// ---
// summary: Check if a user is a public member of an organization
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
// - name: username
// in: path
// description: username of the user to check for a public organization membership
2017-11-12 23:02:25 -08:00
// type: string
// required: true
// responses:
// "204":
// description: user is a public member
// "404":
// description: user is not a public member
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
userToCheck := user.GetContextUserByPathParam(ctx)
2017-06-07 12:10:35 -04:00
if ctx.Written() {
return
}
is, err := organization.IsPublicMembership(ctx, ctx.Org.Organization.ID, userToCheck.ID)
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
return
}
if is {
2019-12-20 18:07:12 +01:00
ctx.Status(http.StatusNoContent)
} else {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
}
}
func checkCanChangeOrgUserStatus(ctx *context.APIContext, targetUser *user_model.User) {
// allow user themselves to change their status, and allow admins to change any user
if targetUser.ID == ctx.Doer.ID || ctx.Doer.IsAdmin {
return
}
// allow org owners to change status of members
isOwner, err := ctx.Org.Organization.IsOwnedBy(ctx, ctx.Doer.ID)
if err != nil {
ctx.APIError(http.StatusInternalServerError, err)
} else if !isOwner {
ctx.APIError(http.StatusForbidden, "Cannot change member visibility")
}
}
// PublicizeMember make a member's membership public
func PublicizeMember(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation PUT /orgs/{org}/public_members/{username} organization orgPublicizeMember
// ---
// summary: Publicize a user's membership
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
// - name: username
// in: path
// description: username of the user whose membership is to be publicized
2017-11-12 23:02:25 -08:00
// type: string
// required: true
// responses:
// "204":
// description: membership publicized
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
userToPublicize := user.GetContextUserByPathParam(ctx)
2017-06-07 12:10:35 -04:00
if ctx.Written() {
return
}
checkCanChangeOrgUserStatus(ctx, userToPublicize)
if ctx.Written() {
return
}
err := organization.ChangeOrgUserStatus(ctx, ctx.Org.Organization.ID, userToPublicize.ID, true)
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
return
}
2019-12-20 18:07:12 +01:00
ctx.Status(http.StatusNoContent)
}
// ConcealMember make a member's membership not public
func ConcealMember(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation DELETE /orgs/{org}/public_members/{username} organization orgConcealMember
// ---
// summary: Conceal a user's membership
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
// - name: username
// in: path
// description: username of the user whose membership is to be concealed
2017-11-12 23:02:25 -08:00
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
userToConceal := user.GetContextUserByPathParam(ctx)
2017-06-07 12:10:35 -04:00
if ctx.Written() {
return
}
checkCanChangeOrgUserStatus(ctx, userToConceal)
if ctx.Written() {
return
}
err := organization.ChangeOrgUserStatus(ctx, ctx.Org.Organization.ID, userToConceal.ID, false)
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
return
}
2019-12-20 18:07:12 +01:00
ctx.Status(http.StatusNoContent)
}
// DeleteMember remove a member from an organization
func DeleteMember(ctx *context.APIContext) {
2017-11-12 23:02:25 -08:00
// swagger:operation DELETE /orgs/{org}/members/{username} organization orgDeleteMember
// ---
// summary: Remove a member from an organization
// produces:
// - application/json
// parameters:
// - name: org
// in: path
// description: name of the organization
// type: string
// required: true
// - name: username
// in: path
// description: username of the user to remove from the organization
2017-11-12 23:02:25 -08:00
// type: string
// required: true
// responses:
// "204":
// description: member removed
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
member := user.GetContextUserByPathParam(ctx)
2017-06-07 12:10:35 -04:00
if ctx.Written() {
return
}
if err := org_service.RemoveOrgUser(ctx, ctx.Org.Organization, member); err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
}
2019-12-20 18:07:12 +01:00
ctx.Status(http.StatusNoContent)
}