mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-06-21 04:37:13 -04:00
Refactoring of the Access Table
This commit does a lot of the work of refactoring the access table in a table with id's instead of strings. The result does compile, but has not been tested. It may eat your kittens.
This commit is contained in:
parent
2804784df9
commit
0a4cda0dd4
12 changed files with 246 additions and 733 deletions
177
models/access.go
177
models/access.go
|
@ -4,95 +4,76 @@
|
|||
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AccessType int
|
||||
type AccessMode int
|
||||
|
||||
const (
|
||||
READABLE AccessType = iota + 1
|
||||
WRITABLE
|
||||
NoAccess AccessMode = iota
|
||||
ReadAccess
|
||||
WriteAccess
|
||||
AdminAccess
|
||||
OwnerAccess
|
||||
)
|
||||
|
||||
// Access represents the accessibility of user to repository.
|
||||
func maxAccessMode(modes ...AccessMode) AccessMode {
|
||||
max := NoAccess
|
||||
for _, mode := range modes {
|
||||
if mode > max {
|
||||
max = mode
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// Access represents the highest access level of a user to the 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 this table.
|
||||
type Access struct {
|
||||
Id int64
|
||||
UserName string `xorm:"UNIQUE(s)"`
|
||||
RepoName string `xorm:"UNIQUE(s)"` // <user name>/<repo name>
|
||||
Mode AccessType `xorm:"UNIQUE(s)"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
Mode AccessMode
|
||||
}
|
||||
|
||||
func addAccess(e Engine, access *Access) error {
|
||||
access.UserName = strings.ToLower(access.UserName)
|
||||
access.RepoName = strings.ToLower(access.RepoName)
|
||||
_, err := e.Insert(access)
|
||||
return err
|
||||
// HasAccess returns true if someone has the request access level. User can be nil!
|
||||
func HasAccess(u *User, r *Repository, testMode AccessMode) (bool, error) {
|
||||
mode, err := AccessLevel(u, r)
|
||||
return testMode <= mode, err
|
||||
}
|
||||
|
||||
// AddAccess adds new access record.
|
||||
func AddAccess(access *Access) error {
|
||||
return addAccess(x, access)
|
||||
}
|
||||
|
||||
func updateAccess(e Engine, access *Access) error {
|
||||
if _, err := e.Id(access.Id).Update(access); err != nil {
|
||||
return err
|
||||
// Return the Access a user has to a repository. Will return NoneAccess if the
|
||||
// user does not have access. User can be nil!
|
||||
func AccessLevel(u *User, r *Repository) (AccessMode, error) {
|
||||
mode := NoAccess
|
||||
if !r.IsPrivate {
|
||||
mode = ReadAccess
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAccess updates access information.
|
||||
func UpdateAccess(access *Access) error {
|
||||
access.UserName = strings.ToLower(access.UserName)
|
||||
access.RepoName = strings.ToLower(access.RepoName)
|
||||
return updateAccess(x, access)
|
||||
}
|
||||
if u != nil {
|
||||
if u.Id == r.OwnerId {
|
||||
return OwnerAccess, nil
|
||||
}
|
||||
|
||||
func deleteAccess(e Engine, access *Access) error {
|
||||
_, err := e.Delete(access)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteAccess deletes access record.
|
||||
func DeleteAccess(access *Access) error {
|
||||
return deleteAccess(x, access)
|
||||
}
|
||||
|
||||
// HasAccess returns true if someone can read or write to given repository.
|
||||
// The repoName should be in format <username>/<reponame>.
|
||||
func HasAccess(uname, repoName string, mode AccessType) (bool, error) {
|
||||
if len(repoName) == 0 {
|
||||
return false, nil
|
||||
a := &Access{UserID: u.Id, RepoID: r.Id}
|
||||
if has, err := x.Get(a); !has || err != nil {
|
||||
return mode, err
|
||||
}
|
||||
return a.Mode, nil
|
||||
}
|
||||
access := &Access{
|
||||
UserName: strings.ToLower(uname),
|
||||
RepoName: strings.ToLower(repoName),
|
||||
}
|
||||
has, err := x.Get(access)
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if !has {
|
||||
return false, nil
|
||||
} else if mode > access.Mode {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
|
||||
return mode, nil
|
||||
}
|
||||
|
||||
// GetAccessibleRepositories finds all repositories where a user has access to,
|
||||
// besides his own.
|
||||
func (u *User) GetAccessibleRepositories() (map[*Repository]AccessType, error) {
|
||||
func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) {
|
||||
accesses := make([]*Access, 0, 10)
|
||||
if err := x.Find(&accesses, &Access{UserName: u.LowerName}); err != nil {
|
||||
if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repos := make(map[*Repository]AccessType, len(accesses))
|
||||
repos := make(map[*Repository]AccessMode, len(accesses))
|
||||
for _, access := range accesses {
|
||||
repo, err := GetRepositoryByRef(access.RepoName)
|
||||
repo, err := GetRepositoryById(access.RepoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -106,3 +87,65 @@ func (u *User) GetAccessibleRepositories() (map[*Repository]AccessType, error) {
|
|||
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// Recalculate all accesses for repository
|
||||
func (r *Repository) RecalcAccessSess() error {
|
||||
accessMap := make(map[int64]AccessMode, 20)
|
||||
|
||||
// Give all collaborators write access
|
||||
collaborators, err := r.GetCollaborators()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, c := range collaborators {
|
||||
accessMap[c.Id] = WriteAccess
|
||||
}
|
||||
|
||||
if err := r.GetOwner(); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Owner.IsOrganization() {
|
||||
if err = r.Owner.GetTeams(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, team := range r.Owner.Teams {
|
||||
if !(team.IsOwnerTeam() || team.HasRepository(r)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = team.GetMembers(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, u := range team.Members {
|
||||
accessMap[u.Id] = maxAccessMode(accessMap[u.Id], team.Authorize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minMode := ReadAccess
|
||||
if !r.IsPrivate {
|
||||
minMode = WriteAccess
|
||||
}
|
||||
|
||||
newAccesses := make([]Access, 0, len(accessMap))
|
||||
for userID, mode := range accessMap {
|
||||
if userID == r.OwnerId || mode <= minMode {
|
||||
continue
|
||||
}
|
||||
newAccesses = append(newAccesses, Access{UserID: userID, RepoID: r.Id, Mode: mode})
|
||||
}
|
||||
|
||||
// Delete old accesses for repository
|
||||
if _, err = x.Delete(&Access{RepoID: r.Id}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// And insert the new ones
|
||||
if _, err = x.Insert(newAccesses); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue