chore: move determinePackageAccessMode from context packages

It allows it to be called in isolation for testing purposes, when
no context is available.
This commit is contained in:
limiting-factor 2026-05-20 19:06:03 +02:00
commit f46082c3b2
No known key found for this signature in database
GPG key ID: FBFC3FECD17D904F
2 changed files with 74 additions and 61 deletions

View file

@ -7,14 +7,11 @@ import (
"fmt"
"net/http"
"forgejo.org/models/organization"
packages_model "forgejo.org/models/packages"
"forgejo.org/models/perm"
"forgejo.org/models/unit"
user_model "forgejo.org/models/user"
"forgejo.org/modules/setting"
"forgejo.org/modules/structs"
"forgejo.org/modules/templates"
packages_service "forgejo.org/services/packages"
)
// Package contains owner, access mode and optional the package descriptor
@ -62,7 +59,7 @@ func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any))
Owner: ctx.ContextUser,
}
var err error
pkg.AccessMode, err = determineAccessMode(ctx.Base, pkg, ctx.Doer)
pkg.AccessMode, err = packages_service.DeterminePackageAccessMode(ctx.Base, pkg.Owner, ctx.Doer)
if err != nil {
errCb(http.StatusInternalServerError, "determineAccessMode", err)
return pkg
@ -92,62 +89,6 @@ func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, string, any))
return pkg
}
func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.AccessMode, error) {
if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
return perm.AccessModeNone, nil
}
if doer != nil && !doer.IsGhost() && !doer.IsAccessAllowed(ctx) {
return perm.AccessModeNone, nil
}
// TODO: ActionUser permission check
accessMode := perm.AccessModeNone
if pkg.Owner.IsOrganization() {
org := organization.OrgFromUser(pkg.Owner)
if doer != nil && !doer.IsGhost() {
// 1. If user is logged in, check all team packages permissions
var err error
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx, doer.ID)
if err != nil {
return accessMode, err
}
// If access mode is less than write check every team for more permissions
// The minimum possible access mode is read for org members
if accessMode < perm.AccessModeWrite {
teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
if err != nil {
return accessMode, err
}
for _, t := range teams {
perm := t.UnitAccessMode(ctx, unit.TypePackages)
if accessMode < perm {
accessMode = perm
}
}
}
}
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, pkg.Owner, doer) {
// 2. If user is unauthorized or no org member, check if org is visible
accessMode = perm.AccessModeRead
}
} else {
if doer != nil && !doer.IsGhost() {
// 1. Check if user is package owner
if doer.ID == pkg.Owner.ID {
accessMode = perm.AccessModeOwner
} else if pkg.Owner.Visibility == structs.VisibleTypePublic || pkg.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
accessMode = perm.AccessModeRead
}
} else if pkg.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
accessMode = perm.AccessModeRead
}
}
return accessMode, nil
}
// PackageContexter initializes a package context for a request.
func PackageContexter() func(next http.Handler) http.Handler {
renderer := templates.HTMLRenderer()

72
services/packages/perm.go Normal file
View file

@ -0,0 +1,72 @@
// Copyright 2026 The Forgejo Authors.
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package packages
import (
"context"
"forgejo.org/models/organization"
"forgejo.org/models/perm"
"forgejo.org/models/unit"
user_model "forgejo.org/models/user"
"forgejo.org/modules/setting"
api "forgejo.org/modules/structs"
)
func DeterminePackageAccessMode(ctx context.Context, owner, doer *user_model.User) (perm.AccessMode, error) {
if setting.Service.RequireSignInView && (doer == nil || doer.IsGhost()) {
return perm.AccessModeNone, nil
}
if doer != nil && !doer.IsGhost() && !doer.IsAccessAllowed(ctx) {
return perm.AccessModeNone, nil
}
// TODO: ActionUser permission check
accessMode := perm.AccessModeNone
if owner.IsOrganization() {
org := organization.OrgFromUser(owner)
if doer != nil && !doer.IsGhost() {
// 1. If user is logged in, check all team packages permissions
var err error
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx, doer.ID)
if err != nil {
return accessMode, err
}
// If access mode is less than write check every team for more permissions
// The minimum possible access mode is read for org members
if accessMode < perm.AccessModeWrite {
teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
if err != nil {
return accessMode, err
}
for _, t := range teams {
perm := t.UnitAccessMode(ctx, unit.TypePackages)
if accessMode < perm {
accessMode = perm
}
}
}
}
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, owner, doer) {
// 2. If user is unauthorized or no org member, check if org is visible
accessMode = perm.AccessModeRead
}
} else {
if doer != nil && !doer.IsGhost() {
// 1. Check if user is package owner
if doer.ID == owner.ID {
accessMode = perm.AccessModeOwner
} else if owner.Visibility == api.VisibleTypePublic || owner.Visibility == api.VisibleTypeLimited { // 2. Check if package owner is public or limited
accessMode = perm.AccessModeRead
}
} else if owner.Visibility == api.VisibleTypePublic { // 3. Check if package owner is public
accessMode = perm.AccessModeRead
}
}
return accessMode, nil
}