mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Follow #33127 Fix #8649, fix #639 This is a complete solution. A repo unit could be set to: * Anonymous read (non-signed-in user) * Everyone read (signed-in user) * Everyone write (wiki-only)
		
			
				
	
	
		
			156 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2025 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package setting
 | 
						|
 | 
						|
import (
 | 
						|
	"net/http"
 | 
						|
	"slices"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/models/perm"
 | 
						|
	"code.gitea.io/gitea/models/repo"
 | 
						|
	"code.gitea.io/gitea/models/unit"
 | 
						|
	"code.gitea.io/gitea/modules/setting"
 | 
						|
	"code.gitea.io/gitea/modules/templates"
 | 
						|
	"code.gitea.io/gitea/services/context"
 | 
						|
)
 | 
						|
 | 
						|
const tplRepoSettingsPublicAccess templates.TplName = "repo/settings/public_access"
 | 
						|
 | 
						|
func parsePublicAccessMode(permission string, allowed []string) (ret struct {
 | 
						|
	AnonymousAccessMode, EveryoneAccessMode perm.AccessMode
 | 
						|
},
 | 
						|
) {
 | 
						|
	ret.AnonymousAccessMode = perm.AccessModeNone
 | 
						|
	ret.EveryoneAccessMode = perm.AccessModeNone
 | 
						|
 | 
						|
	// if site admin forces repositories to be private, then do not allow any other access mode,
 | 
						|
	// otherwise the "force private" setting would be bypassed
 | 
						|
	if setting.Repository.ForcePrivate {
 | 
						|
		return ret
 | 
						|
	}
 | 
						|
	if !slices.Contains(allowed, permission) {
 | 
						|
		return ret
 | 
						|
	}
 | 
						|
	switch permission {
 | 
						|
	case paAnonymousRead:
 | 
						|
		ret.AnonymousAccessMode = perm.AccessModeRead
 | 
						|
	case paEveryoneRead:
 | 
						|
		ret.EveryoneAccessMode = perm.AccessModeRead
 | 
						|
	case paEveryoneWrite:
 | 
						|
		ret.EveryoneAccessMode = perm.AccessModeWrite
 | 
						|
	}
 | 
						|
	return ret
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	paNotSet        = "not-set"
 | 
						|
	paAnonymousRead = "anonymous-read"
 | 
						|
	paEveryoneRead  = "everyone-read"
 | 
						|
	paEveryoneWrite = "everyone-write"
 | 
						|
)
 | 
						|
 | 
						|
type repoUnitPublicAccess struct {
 | 
						|
	UnitType          unit.Type
 | 
						|
	FormKey           string
 | 
						|
	DisplayName       string
 | 
						|
	PublicAccessTypes []string
 | 
						|
	UnitPublicAccess  string
 | 
						|
}
 | 
						|
 | 
						|
func repoUnitPublicAccesses(ctx *context.Context) []*repoUnitPublicAccess {
 | 
						|
	accesses := []*repoUnitPublicAccess{
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypeCode,
 | 
						|
			DisplayName:       ctx.Locale.TrString("repo.code"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypeIssues,
 | 
						|
			DisplayName:       ctx.Locale.TrString("issues"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypePullRequests,
 | 
						|
			DisplayName:       ctx.Locale.TrString("pull_requests"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypeReleases,
 | 
						|
			DisplayName:       ctx.Locale.TrString("repo.releases"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypeWiki,
 | 
						|
			DisplayName:       ctx.Locale.TrString("repo.wiki"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead, paEveryoneWrite},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypeProjects,
 | 
						|
			DisplayName:       ctx.Locale.TrString("repo.projects"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypePackages,
 | 
						|
			DisplayName:       ctx.Locale.TrString("repo.packages"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			UnitType:          unit.TypeActions,
 | 
						|
			DisplayName:       ctx.Locale.TrString("repo.actions"),
 | 
						|
			PublicAccessTypes: []string{paAnonymousRead, paEveryoneRead},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, ua := range accesses {
 | 
						|
		ua.FormKey = "repo-unit-access-" + strconv.Itoa(int(ua.UnitType))
 | 
						|
		for _, u := range ctx.Repo.Repository.Units {
 | 
						|
			if u.Type == ua.UnitType {
 | 
						|
				ua.UnitPublicAccess = paNotSet
 | 
						|
				switch {
 | 
						|
				case u.EveryoneAccessMode == perm.AccessModeWrite:
 | 
						|
					ua.UnitPublicAccess = paEveryoneWrite
 | 
						|
				case u.EveryoneAccessMode == perm.AccessModeRead:
 | 
						|
					ua.UnitPublicAccess = paEveryoneRead
 | 
						|
				case u.AnonymousAccessMode == perm.AccessModeRead:
 | 
						|
					ua.UnitPublicAccess = paAnonymousRead
 | 
						|
				}
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return slices.DeleteFunc(accesses, func(ua *repoUnitPublicAccess) bool {
 | 
						|
		return ua.UnitPublicAccess == ""
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func PublicAccess(ctx *context.Context) {
 | 
						|
	ctx.Data["PageIsSettingsPublicAccess"] = true
 | 
						|
	ctx.Data["RepoUnitPublicAccesses"] = repoUnitPublicAccesses(ctx)
 | 
						|
	ctx.Data["GlobalForcePrivate"] = setting.Repository.ForcePrivate
 | 
						|
	if setting.Repository.ForcePrivate {
 | 
						|
		ctx.Flash.Error(ctx.Tr("form.repository_force_private"), true)
 | 
						|
	}
 | 
						|
	ctx.HTML(http.StatusOK, tplRepoSettingsPublicAccess)
 | 
						|
}
 | 
						|
 | 
						|
func PublicAccessPost(ctx *context.Context) {
 | 
						|
	accesses := repoUnitPublicAccesses(ctx)
 | 
						|
	for _, ua := range accesses {
 | 
						|
		formVal := ctx.FormString(ua.FormKey)
 | 
						|
		parsed := parsePublicAccessMode(formVal, ua.PublicAccessTypes)
 | 
						|
		err := repo.UpdateRepoUnitPublicAccess(ctx, &repo.RepoUnit{
 | 
						|
			RepoID:              ctx.Repo.Repository.ID,
 | 
						|
			Type:                ua.UnitType,
 | 
						|
			AnonymousAccessMode: parsed.AnonymousAccessMode,
 | 
						|
			EveryoneAccessMode:  parsed.EveryoneAccessMode,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			ctx.ServerError("UpdateRepoUnitPublicAccess", err)
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
 | 
						|
	ctx.Redirect(ctx.Repo.Repository.Link() + "/settings/public_access")
 | 
						|
}
 |