diff options
author | Peter Smit <peter@smitmail.eu> | 2015-02-05 15:29:08 +0200 |
---|---|---|
committer | Peter Smit <peter@smitmail.eu> | 2015-02-12 14:14:45 +0200 |
commit | 0a4cda0dd4d7c906668d9d2e283fbe9ebe2e1608 (patch) | |
tree | 7068350836e187523f0bcf741695c84c0eab42a9 /models/access.go | |
parent | 2804784df93f392ed76a85d8e7153c66964f1ba5 (diff) | |
download | gitea-0a4cda0dd4d7c906668d9d2e283fbe9ebe2e1608.tar.gz gitea-0a4cda0dd4d7c906668d9d2e283fbe9ebe2e1608.zip |
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.
Diffstat (limited to 'models/access.go')
-rw-r--r-- | models/access.go | 175 |
1 files changed, 109 insertions, 66 deletions
diff --git a/models/access.go b/models/access.go index 6df1da29bc..d85f24cd06 100644 --- a/models/access.go +++ b/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. -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"` +func maxAccessMode(modes ...AccessMode) AccessMode { + max := NoAccess + for _, mode := range modes { + if mode > max { + max = mode + } + } + return max } -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 +// 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 `xorm:"pk autoincr"` + UserID int64 `xorm:"UNIQUE(s)"` + RepoID int64 `xorm:"UNIQUE(s)"` + Mode AccessMode } -// AddAccess adds new access record. -func AddAccess(access *Access) error { - return addAccess(x, access) +// 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 } -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) -} - -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) -} + if u != nil { + if u.Id == r.OwnerId { + return OwnerAccess, nil + } -// 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 - } - 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 + a := &Access{UserID: u.Id, RepoID: r.Id} + if has, err := x.Get(a); !has || err != nil { + return mode, err + } + return a.Mode, 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 + +} |