mirror of
https://github.com/gogs/gogs.git
synced 2026-05-06 12:46:26 +02:00
all: unwrap database.PermissionsStore interface (#7701)
This commit is contained in:
@@ -123,7 +123,6 @@ func NewConnection(w logger.Writer) (*gorm.DB, error) {
|
||||
}
|
||||
|
||||
// Initialize stores, sorted in alphabetical order.
|
||||
Perms = NewPermsStore(db)
|
||||
Repos = NewReposStore(db)
|
||||
TwoFactors = &twoFactorsStore{DB: db}
|
||||
Users = NewUsersStore(db)
|
||||
@@ -176,3 +175,7 @@ func (db *DB) Notices() *NoticesStore {
|
||||
func (db *DB) Organizations() *OrganizationsStore {
|
||||
return newOrganizationsStoreStore(db.db)
|
||||
}
|
||||
|
||||
func (db *DB) Permissions() *PermissionsStore {
|
||||
return newPermissionsStore(db.db)
|
||||
}
|
||||
|
||||
@@ -8,14 +8,6 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func SetMockPermsStore(t *testing.T, mock PermsStore) {
|
||||
before := Perms
|
||||
Perms = mock
|
||||
t.Cleanup(func() {
|
||||
Perms = before
|
||||
})
|
||||
}
|
||||
|
||||
func SetMockReposStore(t *testing.T, mock ReposStore) {
|
||||
before := Repos
|
||||
Repos = mock
|
||||
|
||||
@@ -7,24 +7,11 @@ package database
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
// PermsStore is the persistent interface for permissions.
|
||||
type PermsStore interface {
|
||||
// AccessMode returns the access mode of given user has to the repository.
|
||||
AccessMode(ctx context.Context, userID, repoID int64, opts AccessModeOptions) AccessMode
|
||||
// Authorize returns true if the user has as good as desired access mode to the
|
||||
// repository.
|
||||
Authorize(ctx context.Context, userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool
|
||||
// SetRepoPerms does a full update to which users have which level of access to
|
||||
// given repository. Keys of the "accessMap" are user IDs.
|
||||
SetRepoPerms(ctx context.Context, repoID int64, accessMap map[int64]AccessMode) error
|
||||
}
|
||||
|
||||
var Perms PermsStore
|
||||
|
||||
// Access represents the highest access level of a user has to a repository. The
|
||||
// only access type that is not in this table is the real owner of a repository.
|
||||
// In case of an organization repository, the members of the owners team are in
|
||||
@@ -74,16 +61,13 @@ func ParseAccessMode(permission string) AccessMode {
|
||||
}
|
||||
}
|
||||
|
||||
var _ PermsStore = (*permsStore)(nil)
|
||||
|
||||
type permsStore struct {
|
||||
*gorm.DB
|
||||
// PermissionsStore is the storage layer for repository permissions.
|
||||
type PermissionsStore struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewPermsStore returns a persistent interface for permissions with given
|
||||
// database connection.
|
||||
func NewPermsStore(db *gorm.DB) PermsStore {
|
||||
return &permsStore{DB: db}
|
||||
func newPermissionsStore(db *gorm.DB) *PermissionsStore {
|
||||
return &PermissionsStore{db: db}
|
||||
}
|
||||
|
||||
type AccessModeOptions struct {
|
||||
@@ -91,7 +75,8 @@ type AccessModeOptions struct {
|
||||
Private bool // Whether the repository is private.
|
||||
}
|
||||
|
||||
func (s *permsStore) AccessMode(ctx context.Context, userID, repoID int64, opts AccessModeOptions) (mode AccessMode) {
|
||||
// AccessMode returns the access mode of given user has to the repository.
|
||||
func (s *PermissionsStore) AccessMode(ctx context.Context, userID, repoID int64, opts AccessModeOptions) (mode AccessMode) {
|
||||
if repoID <= 0 {
|
||||
return AccessModeNone
|
||||
}
|
||||
@@ -111,9 +96,9 @@ func (s *permsStore) AccessMode(ctx context.Context, userID, repoID int64, opts
|
||||
}
|
||||
|
||||
access := new(Access)
|
||||
err := s.WithContext(ctx).Where("user_id = ? AND repo_id = ?", userID, repoID).First(access).Error
|
||||
err := s.db.WithContext(ctx).Where("user_id = ? AND repo_id = ?", userID, repoID).First(access).Error
|
||||
if err != nil {
|
||||
if err != gorm.ErrRecordNotFound {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
log.Error("Failed to get access [user_id: %d, repo_id: %d]: %v", userID, repoID, err)
|
||||
}
|
||||
return mode
|
||||
@@ -121,11 +106,15 @@ func (s *permsStore) AccessMode(ctx context.Context, userID, repoID int64, opts
|
||||
return access.Mode
|
||||
}
|
||||
|
||||
func (s *permsStore) Authorize(ctx context.Context, userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool {
|
||||
// Authorize returns true if the user has as good as desired access mode to the
|
||||
// repository.
|
||||
func (s *PermissionsStore) Authorize(ctx context.Context, userID, repoID int64, desired AccessMode, opts AccessModeOptions) bool {
|
||||
return desired <= s.AccessMode(ctx, userID, repoID, opts)
|
||||
}
|
||||
|
||||
func (s *permsStore) SetRepoPerms(ctx context.Context, repoID int64, accessMap map[int64]AccessMode) error {
|
||||
// SetRepoPerms does a full update to which users have which level of access to
|
||||
// given repository. Keys of the "accessMap" are user IDs.
|
||||
func (s *PermissionsStore) SetRepoPerms(ctx context.Context, repoID int64, accessMap map[int64]AccessMode) error {
|
||||
records := make([]*Access, 0, len(accessMap))
|
||||
for userID, mode := range accessMap {
|
||||
records = append(records, &Access{
|
||||
@@ -135,7 +124,7 @@ func (s *permsStore) SetRepoPerms(ctx context.Context, repoID int64, accessMap m
|
||||
})
|
||||
}
|
||||
|
||||
return s.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
err := tx.Where("repo_id = ?", repoID).Delete(new(Access)).Error
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -19,13 +19,13 @@ func TestPerms(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
db := &permsStore{
|
||||
DB: newTestDB(t, "permsStore"),
|
||||
s := &PermissionsStore{
|
||||
db: newTestDB(t, "PermissionsStore"),
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
test func(t *testing.T, ctx context.Context, db *permsStore)
|
||||
test func(t *testing.T, ctx context.Context, s *PermissionsStore)
|
||||
}{
|
||||
{"AccessMode", permsAccessMode},
|
||||
{"Authorize", permsAuthorize},
|
||||
@@ -33,10 +33,10 @@ func TestPerms(t *testing.T) {
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
err := clearTables(t, db.DB)
|
||||
err := clearTables(t, s.db)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
tc.test(t, ctx, db)
|
||||
tc.test(t, ctx, s)
|
||||
})
|
||||
if t.Failed() {
|
||||
break
|
||||
@@ -44,16 +44,16 @@ func TestPerms(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func permsAccessMode(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
func permsAccessMode(t *testing.T, ctx context.Context, s *PermissionsStore) {
|
||||
// Set up permissions
|
||||
err := db.SetRepoPerms(ctx, 1,
|
||||
err := s.SetRepoPerms(ctx, 1,
|
||||
map[int64]AccessMode{
|
||||
2: AccessModeWrite,
|
||||
3: AccessModeAdmin,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
err = db.SetRepoPerms(ctx, 2,
|
||||
err = s.SetRepoPerms(ctx, 2,
|
||||
map[int64]AccessMode{
|
||||
1: AccessModeRead,
|
||||
},
|
||||
@@ -149,15 +149,15 @@ func permsAccessMode(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
mode := db.AccessMode(ctx, test.userID, test.repoID, test.opts)
|
||||
mode := s.AccessMode(ctx, test.userID, test.repoID, test.opts)
|
||||
assert.Equal(t, test.wantAccessMode, mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func permsAuthorize(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
func permsAuthorize(t *testing.T, ctx context.Context, s *PermissionsStore) {
|
||||
// Set up permissions
|
||||
err := db.SetRepoPerms(ctx, 1,
|
||||
err := s.SetRepoPerms(ctx, 1,
|
||||
map[int64]AccessMode{
|
||||
1: AccessModeRead,
|
||||
2: AccessModeWrite,
|
||||
@@ -230,7 +230,7 @@ func permsAuthorize(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
authorized := db.Authorize(ctx, test.userID, repo.ID, test.desired,
|
||||
authorized := s.Authorize(ctx, test.userID, repo.ID, test.desired,
|
||||
AccessModeOptions{
|
||||
OwnerID: repo.OwnerID,
|
||||
Private: repo.IsPrivate,
|
||||
@@ -241,7 +241,7 @@ func permsAuthorize(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func permsSetRepoPerms(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
func permsSetRepoPerms(t *testing.T, ctx context.Context, s *PermissionsStore) {
|
||||
for _, update := range []struct {
|
||||
repoID int64
|
||||
accessMap map[int64]AccessMode
|
||||
@@ -280,14 +280,14 @@ func permsSetRepoPerms(t *testing.T, ctx context.Context, db *permsStore) {
|
||||
},
|
||||
},
|
||||
} {
|
||||
err := db.SetRepoPerms(ctx, update.repoID, update.accessMap)
|
||||
err := s.SetRepoPerms(ctx, update.repoID, update.accessMap)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var accesses []*Access
|
||||
err := db.Order("user_id, repo_id").Find(&accesses).Error
|
||||
err := s.db.Order("user_id, repo_id").Find(&accesses).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
// Ignore ID fields
|
||||
@@ -392,7 +392,7 @@ func (repo *Repository) APIFormatLegacy(permission *api.Permission, user ...*Use
|
||||
if repo.IsFork {
|
||||
p := &api.Permission{Pull: true}
|
||||
if len(user) != 0 {
|
||||
accessMode := Perms.AccessMode(
|
||||
accessMode := Handle.Permissions().AccessMode(
|
||||
context.TODO(),
|
||||
user[0].ID,
|
||||
repo.ID,
|
||||
@@ -530,7 +530,7 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) {
|
||||
// GetAssigneeByID returns the user that has write access of repository by given ID.
|
||||
func (repo *Repository) GetAssigneeByID(userID int64) (*User, error) {
|
||||
ctx := context.TODO()
|
||||
if !Perms.Authorize(
|
||||
if !Handle.Permissions().Authorize(
|
||||
ctx,
|
||||
userID,
|
||||
repo.ID,
|
||||
@@ -592,7 +592,7 @@ func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) strin
|
||||
}
|
||||
|
||||
func (repo *Repository) HasAccess(userID int64) bool {
|
||||
return Perms.Authorize(context.TODO(), userID, repo.ID, AccessModeRead,
|
||||
return Handle.Permissions().Authorize(context.TODO(), userID, repo.ID, AccessModeRead,
|
||||
AccessModeOptions{
|
||||
OwnerID: repo.OwnerID,
|
||||
Private: repo.IsPrivate,
|
||||
|
||||
@@ -176,7 +176,7 @@ func UpdateOrgProtectBranch(repo *Repository, protectBranch *ProtectBranch, whit
|
||||
userIDs := tool.StringsToInt64s(strings.Split(whitelistUserIDs, ","))
|
||||
validUserIDs = make([]int64, 0, len(userIDs))
|
||||
for _, userID := range userIDs {
|
||||
if !Perms.Authorize(context.TODO(), userID, repo.ID, AccessModeWrite,
|
||||
if !Handle.Permissions().Authorize(context.TODO(), userID, repo.ID, AccessModeWrite,
|
||||
AccessModeOptions{
|
||||
OwnerID: repo.OwnerID,
|
||||
Private: repo.IsPrivate,
|
||||
|
||||
@@ -165,10 +165,10 @@ func reposGetByCollaboratorID(t *testing.T, ctx context.Context, db *reposStore)
|
||||
repo2, err := db.Create(ctx, 2, CreateRepoOptions{Name: "repo2"})
|
||||
require.NoError(t, err)
|
||||
|
||||
permsStore := NewPermsStore(db.DB)
|
||||
err = permsStore.SetRepoPerms(ctx, repo1.ID, map[int64]AccessMode{3: AccessModeRead})
|
||||
permissionsStore := newPermissionsStore(db.DB)
|
||||
err = permissionsStore.SetRepoPerms(ctx, repo1.ID, map[int64]AccessMode{3: AccessModeRead})
|
||||
require.NoError(t, err)
|
||||
err = permsStore.SetRepoPerms(ctx, repo2.ID, map[int64]AccessMode{4: AccessModeAdmin})
|
||||
err = permissionsStore.SetRepoPerms(ctx, repo2.ID, map[int64]AccessMode{4: AccessModeAdmin})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("user 3 is a collaborator of repo1", func(t *testing.T) {
|
||||
@@ -193,12 +193,12 @@ func reposGetByCollaboratorIDWithAccessMode(t *testing.T, ctx context.Context, d
|
||||
repo3, err := db.Create(ctx, 2, CreateRepoOptions{Name: "repo3"})
|
||||
require.NoError(t, err)
|
||||
|
||||
permsStore := NewPermsStore(db.DB)
|
||||
err = permsStore.SetRepoPerms(ctx, repo1.ID, map[int64]AccessMode{3: AccessModeRead})
|
||||
permissionsStore := newPermissionsStore(db.DB)
|
||||
err = permissionsStore.SetRepoPerms(ctx, repo1.ID, map[int64]AccessMode{3: AccessModeRead})
|
||||
require.NoError(t, err)
|
||||
err = permsStore.SetRepoPerms(ctx, repo2.ID, map[int64]AccessMode{3: AccessModeAdmin, 4: AccessModeWrite})
|
||||
err = permissionsStore.SetRepoPerms(ctx, repo2.ID, map[int64]AccessMode{3: AccessModeAdmin, 4: AccessModeWrite})
|
||||
require.NoError(t, err)
|
||||
err = permsStore.SetRepoPerms(ctx, repo3.ID, map[int64]AccessMode{4: AccessModeWrite})
|
||||
err = permissionsStore.SetRepoPerms(ctx, repo3.ID, map[int64]AccessMode{4: AccessModeWrite})
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := db.GetByCollaboratorIDWithAccessMode(ctx, 3)
|
||||
|
||||
@@ -754,7 +754,7 @@ func DeleteDeployKey(doer *User, id int64) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByID: %v", err)
|
||||
}
|
||||
if !Perms.Authorize(context.TODO(), doer.ID, repo.ID, AccessModeAdmin,
|
||||
if !Handle.Permissions().Authorize(context.TODO(), doer.ID, repo.ID, AccessModeAdmin,
|
||||
AccessModeOptions{
|
||||
OwnerID: repo.OwnerID,
|
||||
Private: repo.IsPrivate,
|
||||
|
||||
Reference in New Issue
Block a user