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:
Peter Smit 2015-02-05 15:29:08 +02:00
parent 2804784df9
commit 0a4cda0dd4
12 changed files with 246 additions and 733 deletions

View file

@ -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
}