aboutsummaryrefslogtreecommitdiff
path: root/models/access.go
diff options
context:
space:
mode:
Diffstat (limited to 'models/access.go')
-rw-r--r--models/access.go188
1 files changed, 135 insertions, 53 deletions
diff --git a/models/access.go b/models/access.go
index 81aa43dc..1e1c0114 100644
--- a/models/access.go
+++ b/models/access.go
@@ -4,77 +4,159 @@
package models
-import (
- "strings"
- "time"
-
- "github.com/go-xorm/xorm"
-)
-
-type AccessType int
+type AccessMode int
const (
- READABLE AccessType = iota + 1
- WRITABLE
+ ACCESS_MODE_NONE AccessMode = iota
+ ACCESS_MODE_READ
+ ACCESS_MODE_WRITE
+ ACCESS_MODE_ADMIN
+ ACCESS_MODE_OWNER
)
-// Access represents the accessibility of user to repository.
+// 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
}
-// 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
+// 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 := ACCESS_MODE_NONE
+ if !r.IsPrivate {
+ mode = ACCESS_MODE_READ
+ }
+
+ if u != nil {
+ if u.Id == r.OwnerId {
+ return ACCESS_MODE_OWNER, 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 mode, nil
}
-// 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
+// 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
}
-// DeleteAccess deletes access record.
-func DeleteAccess(access *Access) error {
- _, err := x.Delete(access)
- return err
+// GetAccessibleRepositories finds all repositories where a user has access to,
+// besides his own.
+func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) {
+ accesses := make([]*Access, 0, 10)
+ if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
+ return nil, err
+ }
+
+ repos := make(map[*Repository]AccessMode, len(accesses))
+ for _, access := range accesses {
+ repo, err := GetRepositoryById(access.RepoID)
+ if err != nil {
+ return nil, err
+ }
+ if err = repo.GetOwner(); err != nil {
+ return nil, err
+ } else if repo.OwnerId == u.Id {
+ continue
+ }
+ repos[repo] = access.Mode
+ }
+
+ return repos, nil
}
-// 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
+func maxAccessMode(modes ...AccessMode) AccessMode {
+ max := ACCESS_MODE_NONE
+ for _, mode := range modes {
+ if mode > max {
+ max = mode
+ }
}
+ return max
+}
+
+func (repo *Repository) recalculateTeamAccesses(e Engine, mode AccessMode) error {
+
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
+func (repo *Repository) recalculateAccesses(e Engine) error {
+ accessMap := make(map[int64]AccessMode, 20)
+
+ // Give all collaborators write access
+ collaborators, err := repo.getCollaborators(e)
+ if err != nil {
+ return err
}
- access := &Access{
- UserName: strings.ToLower(uname),
- RepoName: strings.ToLower(repoName),
+ for _, c := range collaborators {
+ accessMap[c.Id] = ACCESS_MODE_WRITE
}
- 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 err := repo.getOwner(e); err != nil {
+ return err
+ }
+ if repo.Owner.IsOrganization() {
+ if err = repo.Owner.getTeams(e); err != nil {
+ return err
+ }
+
+ for _, team := range repo.Owner.Teams {
+ if !(team.IsOwnerTeam() || team.HasRepository(repo)) {
+ continue
+ } else if team.IsOwnerTeam() {
+ team.Authorize = ACCESS_MODE_OWNER
+ }
+
+ if err = team.getMembers(e); err != nil {
+ return err
+ }
+ for _, u := range team.Members {
+ accessMap[u.Id] = maxAccessMode(accessMap[u.Id], team.Authorize)
+ }
+ }
+ }
+
+ minMode := ACCESS_MODE_READ
+ if !repo.IsPrivate {
+ minMode = ACCESS_MODE_WRITE
+ }
+
+ newAccesses := make([]Access, 0, len(accessMap))
+ for userID, mode := range accessMap {
+ if mode < minMode {
+ continue
+ }
+ newAccesses = append(newAccesses, Access{
+ UserID: userID,
+ RepoID: repo.Id,
+ Mode: mode,
+ })
+ }
+
+ // Delete old accesses and insert new ones for repository.
+ if _, err = e.Delete(&Access{RepoID: repo.Id}); err != nil {
+ return err
+ } else if _, err = e.Insert(newAccesses); err != nil {
+ return err
}
- return true, nil
+
+ return nil
+}
+
+// RecalculateAccesses recalculates all accesses for repository.
+func (r *Repository) RecalculateAccesses() error {
+ return r.recalculateAccesses(x)
}