aboutsummaryrefslogtreecommitdiffstats
path: root/models/access.go
diff options
context:
space:
mode:
authorPeter Smit <peter@smitmail.eu>2015-02-05 15:29:08 +0200
committerPeter Smit <peter@smitmail.eu>2015-02-06 13:18:11 +0200
commit4e79adf6b5bf7ec7bc3b2b47469baafd1cb0b774 (patch)
tree7c9ffe3d741408b5b3c33974b5143b9a50646e02 /models/access.go
parent03af37554e34582e8c5a9d98ec9f2d3c9884f0d8 (diff)
downloadgitea-4e79adf6b5bf7ec7bc3b2b47469baafd1cb0b774.tar.gz
gitea-4e79adf6b5bf7ec7bc3b2b47469baafd1cb0b774.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.go176
1 files changed, 113 insertions, 63 deletions
diff --git a/models/access.go b/models/access.go
index 64bb921409..ee678a0701 100644
--- a/models/access.go
+++ b/models/access.go
@@ -4,92 +4,80 @@
package models
-import (
- "strings"
- "time"
+//import (
+// "github.com/go-xorm/xorm"
+//)
- "github.com/go-xorm/xorm"
-)
-
-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"`
-}
-
-// AddAccess adds new access record.
-func AddAccess(access *Access) error {
- access.UserName = strings.ToLower(access.UserName)
- access.RepoName = strings.ToLower(access.RepoName)
- _, err := x.Insert(access)
- return err
+func maxAccessMode(modes ...AccessMode) AccessMode {
+ max := NoAccess
+ for _, mode := range modes {
+ if mode > max {
+ max = mode
+ }
+ }
+ return max
}
-// UpdateAccess updates access information.
-func UpdateAccess(access *Access) error {
- access.UserName = strings.ToLower(access.UserName)
- access.RepoName = strings.ToLower(access.RepoName)
- _, err := x.Id(access.Id).Update(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
}
-// DeleteAccess deletes access record.
-func DeleteAccess(access *Access) error {
- _, err := x.Delete(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
}
-// UpdateAccess updates access information with session for rolling back.
-func UpdateAccessWithSession(sess *xorm.Session, access *Access) error {
- if _, err := sess.Id(access.Id).Update(access); err != nil {
- sess.Rollback()
- 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
-}
-// 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
+ if u != nil {
+ if u.Id == r.OwnerId {
+ return OwnerAccess, 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
}
@@ -102,3 +90,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
+
+}