0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-11 04:55:34 +02:00

refactor: update API

- use `GroupAssignmentAPI` for routes with a group id param
- use `ctx.RepoGroup` fields when determining group membership in `reqGroupMembership`
- allow users with write access to a group to also write to repos within it
- update "move repo" endpoint to check errors more granularly
This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2026-05-08 18:47:08 -04:00
parent 038cad9754
commit 2a1b0cd104
No known key found for this signature in database
GPG Key ID: 924A5F6AF051E87C
2 changed files with 22 additions and 34 deletions

View File

@ -70,12 +70,10 @@ import (
"strings"
auth_model "code.gitea.io/gitea/models/auth"
group_model "code.gitea.io/gitea/models/group"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
shared_group_model "code.gitea.io/gitea/models/shared/group"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
@ -440,7 +438,7 @@ func reqAdmin() func(ctx *context.APIContext) {
// reqRepoWriter user should have a permission to write to a repo, or be a site admin
func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() && !(ctx.RepoGroup != nil && ctx.IsUserGroupWriter(unitTypes)) {
ctx.APIError(http.StatusForbidden, "user should have a permission to write to a repo")
return
}
@ -538,19 +536,10 @@ func reqGroupMembership(mode perm.AccessMode, needsCreatePerm bool) func(ctx *co
if ctx.IsUserSiteAdmin() {
return
}
gid := ctx.PathParamInt64("group_id")
g, err := group_model.GetGroupByID(ctx, gid)
if err != nil {
ctx.APIErrorInternal(err)
return
}
err = g.LoadOwner(ctx)
if err != nil {
ctx.APIErrorInternal(err)
return
}
var err error
isOrgOwner := false
isOrgAdmin := false
g := ctx.RepoGroup.Group
if ctx.Doer != nil {
isOrgOwner, err = organization.IsOrganizationOwner(ctx, g.OwnerID, ctx.Doer.ID)
@ -568,31 +557,21 @@ func reqGroupMembership(mode perm.AccessMode, needsCreatePerm bool) func(ctx *co
}
}
canAccess, err := g.CanAccessAtLevel(ctx, ctx.Doer, mode)
if err != nil {
ctx.APIErrorInternal(err)
return
}
igm, err := shared_group_model.IsGroupMember(ctx, gid, ctx.Doer)
canAccess, err := ctx.RepoGroup.Group.CanAccessAtLevel(ctx, ctx.Doer, mode)
if err != nil {
ctx.APIErrorInternal(err)
return
}
igm := ctx.RepoGroup.IsMember
if !igm && !canAccess {
ctx.APIErrorNotFound()
return
}
if needsCreatePerm {
canCreateIn := false
if ctx.IsSigned {
canCreateIn, err = g.CanCreateIn(ctx, ctx.Doer.ID)
if err != nil {
ctx.APIErrorInternal(err)
return
}
}
canCreateIn := ctx.RepoGroup.CanCreateRepoOrGroup
if !(canCreateIn || isOrgOwner || isOrgAdmin) {
ctx.APIError(http.StatusForbidden, fmt.Sprintf("User[%d] does not have permission to create new items in group[%d]", ctx.Doer.ID, gid))
ctx.APIError(http.StatusForbidden, fmt.Sprintf("User[%d] does not have permission to create new items in group[%d]", ctx.Doer.ID, g.ID))
return
}
}
@ -1215,7 +1194,7 @@ func Routes() *web.Router {
m.Delete("", user.Unstar)
}
m.Group("/{username}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, context.GroupAssignmentAPI(), repoAssignment(), reqGroupMembership(perm.AccessModeRead, false), checkTokenPublicOnly())
}, reqStarsEnabled(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
m.Get("/times", repo.ListMyTrackedTimes)
m.Get("/stopwatches", repo.GetStopwatches)
@ -1562,7 +1541,7 @@ func Routes() *web.Router {
m.Methods("HEAD,GET", "/{ball_type:tarball|zipball|bundle}/*", reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true), repo.DownloadArchive)
}
m.Group("/{username}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, context.GroupAssignmentAPI(), repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
// Artifacts direct download endpoint authenticates via signed url
@ -1578,7 +1557,7 @@ func Routes() *web.Router {
Put(notify.ReadRepoNotifications)
}
m.Group("/{username}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, repoAssignment(), context.GroupAssignmentAPI(), reqGroupMembership(perm.AccessModeRead, false), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification))
// Issue (requires issue scope)
@ -1698,7 +1677,7 @@ func Routes() *web.Router {
})
}
m.Group("/{username}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, repoAssignment(), checkTokenPublicOnly())
m.Group("/{username}/group/{group_id}/{reponame}", fn, context.GroupAssignmentAPI(), repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue))
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
@ -1899,7 +1878,7 @@ func Routes() *web.Router {
Patch(reqGroupMembership(perm.AccessModeAdmin, false), bind(api.CreateOrUpdateRepoGroupTeamOption{}), group.EditTeam).
Delete(reqGroupMembership(perm.AccessModeAdmin, false), group.DeleteTeam)
}, reqToken(), reqGroupMembership(perm.AccessModeRead, false))
}, checkTokenPublicOnly())
}, context.GroupAssignmentAPI(), checkTokenPublicOnly())
})
return m
}

View File

@ -15,6 +15,7 @@ import (
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
group_model "code.gitea.io/gitea/models/group"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
@ -1368,6 +1369,14 @@ func MoveRepoToGroup(ctx *context.APIContext) {
NewParent: form.NewParent,
}, ctx.Doer)
if err != nil {
if group_model.IsErrUserDoesNotHaveAccessToGroup(err) {
ctx.APIError(http.StatusForbidden, err)
return
}
if group_model.IsErrGroupNotExist(err) {
ctx.APIErrorNotFound()
return
}
ctx.APIErrorInternal(err)
return
}