Преглед изворни кода

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.
Peter Smit пре 10 година
родитељ
комит
4e79adf6b5
12 измењених фајлова са 235 додато и 681 уклоњено
  1. 20 21
      cmd/serve.go
  2. 113 63
      models/access.go
  3. 6 0
      models/migrations/migrations.go
  4. 26 216
      models/org.go
  5. 13 190
      models/repo.go
  6. 2 54
      models/user.go
  7. 1 1
      modules/middleware/org.go
  8. 37 118
      modules/middleware/repo.go
  9. 1 1
      routers/api/v1/repo.go
  10. 8 8
      routers/org/teams.go
  11. 5 5
      routers/repo/http.go
  12. 3 4
      routers/user/home.go

+ 20 - 21
cmd/serve.go

@@ -8,7 +8,6 @@ import (
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
-	"path"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 	"time"
 	"time"
@@ -59,19 +58,19 @@ func parseCmd(cmd string) (string, string) {
 }
 }
 
 
 var (
 var (
-	COMMANDS_READONLY = map[string]models.AccessType{
-		"git-upload-pack":    models.WRITABLE,
-		"git upload-pack":    models.WRITABLE,
-		"git-upload-archive": models.WRITABLE,
+	COMMANDS_READONLY = map[string]models.AccessMode{
+		"git-upload-pack":    models.WriteAccess,
+		"git upload-pack":    models.WriteAccess,
+		"git-upload-archive": models.WriteAccess,
 	}
 	}
 
 
-	COMMANDS_WRITE = map[string]models.AccessType{
-		"git-receive-pack": models.READABLE,
-		"git receive-pack": models.READABLE,
+	COMMANDS_WRITE = map[string]models.AccessMode{
+		"git-receive-pack": models.ReadAccess,
+		"git receive-pack": models.ReadAccess,
 	}
 	}
 )
 )
 
 
-func In(b string, sl map[string]models.AccessType) bool {
+func In(b string, sl map[string]models.AccessMode) bool {
 	_, e := sl[b]
 	_, e := sl[b]
 	return e
 	return e
 }
 }
@@ -130,9 +129,19 @@ func runServ(k *cli.Context) {
 	}
 	}
 
 
 	// Access check.
 	// Access check.
+	repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
+	if err != nil {
+		if err == models.ErrRepoNotExist {
+			println("Gogs: given repository does not exist")
+			log.GitLogger.Fatal(2, "Repository does not exist: %s/%s", repoUser.Name, repoName)
+		}
+		println("Gogs: internal error:", err.Error())
+		log.GitLogger.Fatal(2, "Fail to get repository: %v", err)
+	}
+
 	switch {
 	switch {
 	case isWrite:
 	case isWrite:
-		has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.WRITABLE)
+		has, err := models.HasAccess(user, repo, models.WriteAccess)
 		if err != nil {
 		if err != nil {
 			println("Gogs: internal error:", err.Error())
 			println("Gogs: internal error:", err.Error())
 			log.GitLogger.Fatal(2, "Fail to check write access:", err)
 			log.GitLogger.Fatal(2, "Fail to check write access:", err)
@@ -141,21 +150,11 @@ func runServ(k *cli.Context) {
 			log.GitLogger.Fatal(2, "User %s has no right to write repository %s", user.Name, repoPath)
 			log.GitLogger.Fatal(2, "User %s has no right to write repository %s", user.Name, repoPath)
 		}
 		}
 	case isRead:
 	case isRead:
-		repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
-		if err != nil {
-			if err == models.ErrRepoNotExist {
-				println("Gogs: given repository does not exist")
-				log.GitLogger.Fatal(2, "Repository does not exist: %s/%s", repoUser.Name, repoName)
-			}
-			println("Gogs: internal error:", err.Error())
-			log.GitLogger.Fatal(2, "Fail to get repository: %v", err)
-		}
-
 		if !repo.IsPrivate {
 		if !repo.IsPrivate {
 			break
 			break
 		}
 		}
 
 
-		has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.READABLE)
+		has, err := models.HasAccess(user, repo, models.ReadAccess)
 		if err != nil {
 		if err != nil {
 			println("Gogs: internal error:", err.Error())
 			println("Gogs: internal error:", err.Error())
 			log.GitLogger.Fatal(2, "Fail to check read access:", err)
 			log.GitLogger.Fatal(2, "Fail to check read access:", err)

+ 113 - 63
models/access.go

@@ -4,92 +4,80 @@
 
 
 package models
 package models
 
 
-import (
-	"strings"
-	"time"
+//import (
+//	"github.com/go-xorm/xorm"
+//)
 
 
-	"github.com/go-xorm/xorm"
-)
-
-type AccessType int
+type AccessMode int
 
 
 const (
 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,
 // GetAccessibleRepositories finds all repositories where a user has access to,
 // besides his own.
 // besides his own.
-func (u *User) GetAccessibleRepositories() (map[*Repository]AccessType, error) {
+func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) {
 	accesses := make([]*Access, 0, 10)
 	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
 		return nil, err
 	}
 	}
 
 
-	repos := make(map[*Repository]AccessType, len(accesses))
+	repos := make(map[*Repository]AccessMode, len(accesses))
 	for _, access := range accesses {
 	for _, access := range accesses {
-		repo, err := GetRepositoryByRef(access.RepoName)
+		repo, err := GetRepositoryById(access.RepoID)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -102,3 +90,65 @@ func (u *User) GetAccessibleRepositories() (map[*Repository]AccessType, error) {
 
 
 	return repos, nil
 	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
+
+}

+ 6 - 0
models/migrations/migrations.go

@@ -21,6 +21,7 @@ type Version struct {
 // If you want to "retire" a migration, replace it with "expiredMigration"
 // If you want to "retire" a migration, replace it with "expiredMigration"
 var migrations = []migration{
 var migrations = []migration{
 	accessToCollaboration,
 	accessToCollaboration,
+	accessRefactor,
 }
 }
 
 
 // Migrate database to current version
 // Migrate database to current version
@@ -158,3 +159,8 @@ func accessToCollaboration(x *xorm.Engine) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+func accessRefactor(x *xorm.Engine) error {
+	//TODO
+	return nil
+}

+ 26 - 216
models/org.go

@@ -6,9 +6,7 @@ package models
 
 
 import (
 import (
 	"errors"
 	"errors"
-	"fmt"
 	"os"
 	"os"
-	"path"
 	"strings"
 	"strings"
 
 
 	"github.com/Unknwon/com"
 	"github.com/Unknwon/com"
@@ -137,7 +135,7 @@ func CreateOrganization(org, owner *User) (*User, error) {
 		OrgId:      org.Id,
 		OrgId:      org.Id,
 		LowerName:  strings.ToLower(OWNER_TEAM),
 		LowerName:  strings.ToLower(OWNER_TEAM),
 		Name:       OWNER_TEAM,
 		Name:       OWNER_TEAM,
-		Authorize:  ORG_ADMIN,
+		Authorize:  OwnerAccess,
 		NumMembers: 1,
 		NumMembers: 1,
 	}
 	}
 	if _, err = sess.Insert(t); err != nil {
 	if _, err = sess.Insert(t); err != nil {
@@ -372,10 +370,10 @@ func RemoveOrgUser(orgId, uid int64) error {
 		return err
 		return err
 	}
 	}
 	access := &Access{
 	access := &Access{
-		UserName: u.LowerName,
+		UserID: u.Id,
 	}
 	}
 	for _, repo := range org.Repos {
 	for _, repo := range org.Repos {
-		access.RepoName = path.Join(org.LowerName, repo.LowerName)
+		access.RepoID = repo.Id
 		if _, err = sess.Delete(access); err != nil {
 		if _, err = sess.Delete(access); err != nil {
 			sess.Rollback()
 			sess.Rollback()
 			return err
 			return err
@@ -406,21 +404,6 @@ func RemoveOrgUser(orgId, uid int64) error {
 //   |____| \___  >____  /__|_|  /
 //   |____| \___  >____  /__|_|  /
 //              \/     \/      \/
 //              \/     \/      \/
 
 
-type AuthorizeType int
-
-const (
-	ORG_READABLE AuthorizeType = iota + 1
-	ORG_WRITABLE
-	ORG_ADMIN
-)
-
-func AuthorizeToAccessType(auth AuthorizeType) AccessType {
-	if auth == ORG_READABLE {
-		return READABLE
-	}
-	return WRITABLE
-}
-
 const OWNER_TEAM = "Owners"
 const OWNER_TEAM = "Owners"
 
 
 // Team represents a organization team.
 // Team represents a organization team.
@@ -430,7 +413,7 @@ type Team struct {
 	LowerName   string
 	LowerName   string
 	Name        string
 	Name        string
 	Description string
 	Description string
-	Authorize   AuthorizeType
+	Authorize   AccessMode
 	RepoIds     string        `xorm:"TEXT"`
 	RepoIds     string        `xorm:"TEXT"`
 	Repos       []*Repository `xorm:"-"`
 	Repos       []*Repository `xorm:"-"`
 	Members     []*User       `xorm:"-"`
 	Members     []*User       `xorm:"-"`
@@ -485,25 +468,6 @@ func (t *Team) RemoveMember(uid int64) error {
 	return RemoveTeamMember(t.OrgId, t.Id, uid)
 	return RemoveTeamMember(t.OrgId, t.Id, uid)
 }
 }
 
 
-// addAccessWithAuthorize inserts or updates access with given mode.
-func addAccessWithAuthorize(sess *xorm.Session, access *Access, mode AccessType) error {
-	has, err := x.Get(access)
-	if err != nil {
-		return fmt.Errorf("fail to get access: %v", err)
-	}
-	access.Mode = mode
-	if has {
-		if _, err = sess.Id(access.Id).Update(access); err != nil {
-			return fmt.Errorf("fail to update access: %v", err)
-		}
-	} else {
-		if _, err = sess.Insert(access); err != nil {
-			return fmt.Errorf("fail to insert access: %v", err)
-		}
-	}
-	return nil
-}
-
 // AddRepository adds new repository to team of organization.
 // AddRepository adds new repository to team of organization.
 func (t *Team) AddRepository(repo *Repository) (err error) {
 func (t *Team) AddRepository(repo *Repository) (err error) {
 	idStr := "$" + com.ToStr(repo.Id) + "|"
 	idStr := "$" + com.ToStr(repo.Id) + "|"
@@ -532,26 +496,12 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
 		return err
 		return err
 	}
 	}
 
 
-	// Give access to team members.
-	mode := AuthorizeToAccessType(t.Authorize)
+	if err = repo.RecalcAccessSess(); err != nil {
+		sess.Rollback()
+		return err
+	}
 
 
 	for _, u := range t.Members {
 	for _, u := range t.Members {
-		auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
-		if err != nil {
-			sess.Rollback()
-			return err
-		}
-
-		access := &Access{
-			UserName: u.LowerName,
-			RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
-		}
-		if auth < t.Authorize {
-			if err = addAccessWithAuthorize(sess, access, mode); err != nil {
-				sess.Rollback()
-				return err
-			}
-		}
 		if err = WatchRepo(u.Id, repo.Id, true); err != nil {
 		if err = WatchRepo(u.Id, repo.Id, true); err != nil {
 			sess.Rollback()
 			sess.Rollback()
 			return err
 			return err
@@ -560,6 +510,11 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
 	return sess.Commit()
 	return sess.Commit()
 }
 }
 
 
+func (t *Team) HasRepository(r *Repository) bool {
+	idStr := "$" + com.ToStr(r.Id) + "|"
+	return strings.Contains(t.RepoIds, idStr)
+}
+
 // RemoveRepository removes repository from team of organization.
 // RemoveRepository removes repository from team of organization.
 func (t *Team) RemoveRepository(repoId int64) error {
 func (t *Team) RemoveRepository(repoId int64) error {
 	idStr := "$" + com.ToStr(repoId) + "|"
 	idStr := "$" + com.ToStr(repoId) + "|"
@@ -591,32 +546,16 @@ func (t *Team) RemoveRepository(repoId int64) error {
 		return err
 		return err
 	}
 	}
 
 
-	// Remove access to team members.
+	if err = repo.RecalcAccessSess(); err != nil {
+		sess.Rollback()
+		return err
+	}
+
 	for _, u := range t.Members {
 	for _, u := range t.Members {
-		auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
-		if err != nil {
+		if err = WatchRepo(u.Id, repo.Id, false); err != nil {
 			sess.Rollback()
 			sess.Rollback()
 			return err
 			return err
 		}
 		}
-
-		access := &Access{
-			UserName: u.LowerName,
-			RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
-		}
-		if auth == 0 {
-			if _, err = sess.Delete(access); err != nil {
-				sess.Rollback()
-				return fmt.Errorf("fail to delete access: %v", err)
-			} else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
-				sess.Rollback()
-				return err
-			}
-		} else if auth < t.Authorize {
-			if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
-				sess.Rollback()
-				return err
-			}
-		}
 	}
 	}
 
 
 	return sess.Commit()
 	return sess.Commit()
@@ -690,30 +629,6 @@ func GetTeamById(teamId int64) (*Team, error) {
 	return t, nil
 	return t, nil
 }
 }
 
 
-// GetHighestAuthorize returns highest repository authorize level for given user and team.
-func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error) {
-	ts, err := GetUserTeams(orgId, uid)
-	if err != nil {
-		return 0, err
-	}
-
-	var auth AuthorizeType = 0
-	for _, t := range ts {
-		// Not current team and has given repository.
-		if t.Id != teamId && strings.Contains(t.RepoIds, "$"+com.ToStr(repoId)+"|") {
-			// Fast return.
-			if t.Authorize == ORG_WRITABLE {
-				return ORG_WRITABLE, nil
-			}
-			if t.Authorize > auth {
-				auth = t.Authorize
-			}
-		}
-	}
-
-	return auth, nil
-}
-
 // UpdateTeam updates information of team.
 // UpdateTeam updates information of team.
 func UpdateTeam(t *Team, authChanged bool) (err error) {
 func UpdateTeam(t *Team, authChanged bool) (err error) {
 	if !IsLegalName(t.Name) {
 	if !IsLegalName(t.Name) {
@@ -731,45 +646,14 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
 	}
 	}
 
 
 	// Update access for team members if needed.
 	// Update access for team members if needed.
-	if authChanged && !t.IsOwnerTeam() {
+	if authChanged {
 		if err = t.GetRepositories(); err != nil {
 		if err = t.GetRepositories(); err != nil {
 			return err
 			return err
-		} else if err = t.GetMembers(); err != nil {
-			return err
-		}
-
-		// Get organization.
-		org, err := GetUserById(t.OrgId)
-		if err != nil {
-			return err
 		}
 		}
 
 
-		// Update access.
-		mode := AuthorizeToAccessType(t.Authorize)
-
 		for _, repo := range t.Repos {
 		for _, repo := range t.Repos {
-			for _, u := range t.Members {
-				// ORG_WRITABLE is the highest authorize level for now.
-				// Skip checking others if current team has this level.
-				if t.Authorize < ORG_WRITABLE {
-					auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
-					if err != nil {
-						sess.Rollback()
-						return err
-					}
-					if auth >= t.Authorize {
-						continue // Other team has higher or same authorize level.
-					}
-				}
-
-				access := &Access{
-					UserName: u.LowerName,
-					RepoName: path.Join(org.LowerName, repo.LowerName),
-				}
-				if err = addAccessWithAuthorize(sess, access, mode); err != nil {
-					sess.Rollback()
-					return err
-				}
+			if err = repo.RecalcAccessSess(); err != nil {
+				return err
 			}
 			}
 		}
 		}
 	}
 	}
@@ -805,29 +689,8 @@ func DeleteTeam(t *Team) error {
 
 
 	// Delete all accesses.
 	// Delete all accesses.
 	for _, repo := range t.Repos {
 	for _, repo := range t.Repos {
-		for _, u := range t.Members {
-			auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
-			if err != nil {
-				sess.Rollback()
-				return err
-			}
-
-			access := &Access{
-				UserName: u.LowerName,
-				RepoName: path.Join(org.LowerName, repo.LowerName),
-			}
-			if auth == 0 {
-				if _, err = sess.Delete(access); err != nil {
-					sess.Rollback()
-					return fmt.Errorf("fail to delete access: %v", err)
-				}
-			} else if auth < t.Authorize {
-				// Downgrade authorize level.
-				if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
-					sess.Rollback()
-					return err
-				}
-			}
+		if err = repo.RecalcAccessSess(); err != nil {
+			return err
 		}
 		}
 	}
 	}
 
 
@@ -921,18 +784,6 @@ func AddTeamMember(orgId, teamId, uid int64) error {
 		return err
 		return err
 	}
 	}
 
 
-	// Get organization.
-	org, err := GetUserById(orgId)
-	if err != nil {
-		return err
-	}
-
-	// Get user.
-	u, err := GetUserById(uid)
-	if err != nil {
-		return err
-	}
-
 	sess := x.NewSession()
 	sess := x.NewSession()
 	defer sess.Close()
 	defer sess.Close()
 	if err = sess.Begin(); err != nil {
 	if err = sess.Begin(); err != nil {
@@ -954,24 +805,11 @@ func AddTeamMember(orgId, teamId, uid int64) error {
 	}
 	}
 
 
 	// Give access to team repositories.
 	// Give access to team repositories.
-	mode := AuthorizeToAccessType(t.Authorize)
 	for _, repo := range t.Repos {
 	for _, repo := range t.Repos {
-		auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId)
-		if err != nil {
+		if err = repo.RecalcAccessSess(); err != nil {
 			sess.Rollback()
 			sess.Rollback()
 			return err
 			return err
 		}
 		}
-
-		access := &Access{
-			UserName: u.LowerName,
-			RepoName: path.Join(org.LowerName, repo.LowerName),
-		}
-		if auth < t.Authorize {
-			if err = addAccessWithAuthorize(sess, access, mode); err != nil {
-				sess.Rollback()
-				return err
-			}
-		}
 	}
 	}
 
 
 	// We make sure it exists before.
 	// We make sure it exists before.
@@ -1021,12 +859,6 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
 		return err
 		return err
 	}
 	}
 
 
-	// Get user.
-	u, err := GetUserById(uid)
-	if err != nil {
-		return err
-	}
-
 	tu := &TeamUser{
 	tu := &TeamUser{
 		Uid:    uid,
 		Uid:    uid,
 		OrgId:  orgId,
 		OrgId:  orgId,
@@ -1043,32 +875,10 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
 
 
 	// Delete access to team repositories.
 	// Delete access to team repositories.
 	for _, repo := range t.Repos {
 	for _, repo := range t.Repos {
-		auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId)
-		if err != nil {
+		if err = repo.RecalcAccessSess(); err != nil {
 			sess.Rollback()
 			sess.Rollback()
 			return err
 			return err
 		}
 		}
-
-		access := &Access{
-			UserName: u.LowerName,
-			RepoName: path.Join(org.LowerName, repo.LowerName),
-		}
-		// Delete access if this is the last team user belongs to.
-		if auth == 0 {
-			if _, err = sess.Delete(access); err != nil {
-				sess.Rollback()
-				return fmt.Errorf("fail to delete access: %v", err)
-			} else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
-				sess.Rollback()
-				return err
-			}
-		} else if auth < t.Authorize {
-			// Downgrade authorize level.
-			if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
-				sess.Rollback()
-				return err
-			}
-		}
 	}
 	}
 
 
 	// This must exist.
 	// This must exist.

+ 13 - 190
models/repo.go

@@ -206,14 +206,6 @@ func (repo *Repository) IsOwnedBy(u *User) bool {
 	return repo.OwnerId == u.Id
 	return repo.OwnerId == u.Id
 }
 }
 
 
-func (repo *Repository) HasAccess(uname string) bool {
-	if err := repo.GetOwner(); err != nil {
-		return false
-	}
-	has, _ := HasAccess(uname, path.Join(repo.Owner.Name, repo.Name), READABLE)
-	return has
-}
-
 // DescriptionHtml does special handles to description and return HTML string.
 // DescriptionHtml does special handles to description and return HTML string.
 func (repo *Repository) DescriptionHtml() template.HTML {
 func (repo *Repository) DescriptionHtml() template.HTML {
 	sanitize := func(s string) string {
 	sanitize := func(s string) string {
@@ -553,36 +545,11 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror
 
 
 	var t *Team // Owner team.
 	var t *Team // Owner team.
 
 
-	mode := WRITABLE
-	if mirror {
-		mode = READABLE
-	}
-	access := &Access{
-		UserName: u.LowerName,
-		RepoName: path.Join(u.LowerName, repo.LowerName),
-		Mode:     mode,
-	}
+	// TODO fix code for mirrors?
+
 	// Give access to all members in owner team.
 	// Give access to all members in owner team.
 	if u.IsOrganization() {
 	if u.IsOrganization() {
-		t, err = u.GetOwnerTeam()
-		if err != nil {
-			sess.Rollback()
-			return nil, err
-		}
-		if err = t.GetMembers(); err != nil {
-			sess.Rollback()
-			return nil, err
-		}
-		for _, u := range t.Members {
-			access.Id = 0
-			access.UserName = u.LowerName
-			if _, err = sess.Insert(access); err != nil {
-				sess.Rollback()
-				return nil, err
-			}
-		}
-	} else {
-		if _, err = sess.Insert(access); err != nil {
+		if err = repo.RecalcAccessSess(); err != nil {
 			sess.Rollback()
 			sess.Rollback()
 			return nil, err
 			return nil, err
 		}
 		}
@@ -712,37 +679,10 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error {
 	}
 	}
 
 
 	owner := repo.Owner
 	owner := repo.Owner
-	oldRepoLink := path.Join(owner.LowerName, repo.LowerName)
-	// Delete all access first if current owner is an organization.
-	if owner.IsOrganization() {
-		if _, err = sess.Where("repo_name=?", oldRepoLink).Delete(new(Access)); err != nil {
-			sess.Rollback()
-			return fmt.Errorf("fail to delete current accesses: %v", err)
-		}
-	} else {
-		// Delete current owner access.
-		if _, err = sess.Where("repo_name=?", oldRepoLink).And("user_name=?", owner.LowerName).
-			Delete(new(Access)); err != nil {
-			sess.Rollback()
-			return fmt.Errorf("fail to delete access(owner): %v", err)
-		}
-		// In case new owner has access.
-		if _, err = sess.Where("repo_name=?", oldRepoLink).And("user_name=?", newUser.LowerName).
-			Delete(new(Access)); err != nil {
-			sess.Rollback()
-			return fmt.Errorf("fail to delete access(new user): %v", err)
-		}
-	}
-
-	// Change accesses to new repository path.
-	if _, err = sess.Where("repo_name=?", oldRepoLink).
-		Update(&Access{RepoName: path.Join(newUser.LowerName, repo.LowerName)}); err != nil {
-		sess.Rollback()
-		return fmt.Errorf("fail to update access(change reponame): %v", err)
-	}
 
 
 	// Update repository.
 	// Update repository.
 	repo.OwnerId = newUser.Id
 	repo.OwnerId = newUser.Id
+	repo.Owner = newUser
 	if _, err := sess.Id(repo.Id).Update(repo); err != nil {
 	if _, err := sess.Id(repo.Id).Update(repo); err != nil {
 		sess.Rollback()
 		sess.Rollback()
 		return err
 		return err
@@ -759,53 +699,8 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error {
 		return err
 		return err
 	}
 	}
 
 
-	mode := WRITABLE
-	if repo.IsMirror {
-		mode = READABLE
-	}
-	// New owner is organization.
-	if newUser.IsOrganization() {
-		access := &Access{
-			RepoName: path.Join(newUser.LowerName, repo.LowerName),
-			Mode:     mode,
-		}
-
-		// Give access to all members in owner team.
-		t, err := newUser.GetOwnerTeam()
-		if err != nil {
-			sess.Rollback()
-			return err
-		}
-		if err = t.GetMembers(); err != nil {
-			sess.Rollback()
-			return err
-		}
-		for _, u := range t.Members {
-			access.Id = 0
-			access.UserName = u.LowerName
-			if _, err = sess.Insert(access); err != nil {
-				sess.Rollback()
-				return err
-			}
-		}
-
-		// Update owner team info and count.
-		t.RepoIds += "$" + com.ToStr(repo.Id) + "|"
-		t.NumRepos++
-		if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
-			sess.Rollback()
-			return err
-		}
-	} else {
-		access := &Access{
-			RepoName: path.Join(newUser.LowerName, repo.LowerName),
-			UserName: newUser.LowerName,
-			Mode:     mode,
-		}
-		if _, err = sess.Insert(access); err != nil {
-			sess.Rollback()
-			return fmt.Errorf("fail to insert access: %v", err)
-		}
+	if err = repo.RecalcAccessSess(); err != nil {
+		return err
 	}
 	}
 
 
 	// Change repository directory name.
 	// Change repository directory name.
@@ -838,32 +733,8 @@ func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error)
 		return ErrRepoNameIllegal
 		return ErrRepoNameIllegal
 	}
 	}
 
 
-	// Update accesses.
-	accesses := make([]Access, 0, 10)
-	if err = x.Find(&accesses, &Access{RepoName: userName + "/" + oldRepoName}); err != nil {
-		return err
-	}
-
-	sess := x.NewSession()
-	defer sess.Close()
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	for i := range accesses {
-		accesses[i].RepoName = userName + "/" + newRepoName
-		if err = UpdateAccessWithSession(sess, &accesses[i]); err != nil {
-			return err
-		}
-	}
-
 	// Change repository directory name.
 	// Change repository directory name.
-	if err = os.Rename(RepoPath(userName, oldRepoName), RepoPath(userName, newRepoName)); err != nil {
-		sess.Rollback()
-		return err
-	}
-
-	return sess.Commit()
+	return os.Rename(RepoPath(userName, oldRepoName), RepoPath(userName, newRepoName))
 }
 }
 
 
 func UpdateRepository(repo *Repository) error {
 func UpdateRepository(repo *Repository) error {
@@ -912,7 +783,7 @@ func DeleteRepository(uid, repoId int64, userName string) error {
 	}
 	}
 
 
 	// Delete all access.
 	// Delete all access.
-	if _, err := sess.Delete(&Access{RepoName: strings.ToLower(path.Join(userName, repo.Name))}); err != nil {
+	if _, err := sess.Delete(&Access{RepoID: repo.Id}); err != nil {
 		sess.Rollback()
 		sess.Rollback()
 		return err
 		return err
 	}
 	}
@@ -1105,7 +976,7 @@ func (r *Repository) AddCollaborator(u *User) error {
 		return err
 		return err
 	}
 	}
 
 
-	return AddAccess(&Access{UserName: u.LowerName, RepoName: path.Join(r.Owner.LowerName, r.LowerName), Mode: WRITABLE})
+	return r.RecalcAccessSess()
 }
 }
 
 
 // Delete collaborator and accompanying access
 // Delete collaborator and accompanying access
@@ -1116,25 +987,7 @@ func (r *Repository) DeleteCollaborator(u *User) error {
 		return err
 		return err
 	}
 	}
 
 
-	if err := r.GetOwner(); err != nil {
-		return err
-	}
-
-	needDelete := true
-	if r.Owner.IsOrganization() {
-		auth, err := GetHighestAuthorize(r.Owner.Id, u.Id, r.Id, 0)
-		if err != nil {
-			return err
-		}
-		if auth > 0 {
-			needDelete = false
-		}
-	}
-	if needDelete {
-		return DeleteAccess(&Access{UserName: u.LowerName, RepoName: path.Join(r.Owner.LowerName, r.LowerName), Mode: WRITABLE})
-	}
-
-	return nil
+	return r.RecalcAccessSess()
 }
 }
 
 
 type SearchOption struct {
 type SearchOption struct {
@@ -1443,40 +1296,10 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	var t *Team // Owner team.
-
-	mode := WRITABLE
-
-	access := &Access{
-		UserName: u.LowerName,
-		RepoName: path.Join(u.LowerName, repo.LowerName),
-		Mode:     mode,
-	}
-	// Give access to all members in owner team.
-	if u.IsOrganization() {
-		t, err = u.GetOwnerTeam()
-		if err != nil {
-			sess.Rollback()
-			return nil, err
-		}
-		if err = t.GetMembers(); err != nil {
-			sess.Rollback()
-			return nil, err
-		}
-		for _, u := range t.Members {
-			access.Id = 0
-			access.UserName = u.LowerName
-			if _, err = sess.Insert(access); err != nil {
-				sess.Rollback()
-				return nil, err
-			}
-		}
-	} else {
-		if _, err = sess.Insert(access); err != nil {
-			sess.Rollback()
-			return nil, err
-		}
+	if err = repo.RecalcAccessSess(); err != nil {
+		return nil, err
 	}
 	}
+	var t *Team // Owner team.
 
 
 	if _, err = sess.Exec(
 	if _, err = sess.Exec(
 		"UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {
 		"UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {

+ 2 - 54
models/user.go

@@ -396,59 +396,7 @@ func ChangeUserName(u *User, newUserName string) (err error) {
 		return ErrUserNameIllegal
 		return ErrUserNameIllegal
 	}
 	}
 
 
-	newUserName = strings.ToLower(newUserName)
-
-	// Update accesses of user.
-	accesses := make([]Access, 0, 10)
-	if err = x.Find(&accesses, &Access{UserName: u.LowerName}); err != nil {
-		return err
-	}
-
-	sess := x.NewSession()
-	defer sess.Close()
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	for i := range accesses {
-		accesses[i].UserName = newUserName
-		if strings.HasPrefix(accesses[i].RepoName, u.LowerName+"/") {
-			accesses[i].RepoName = strings.Replace(accesses[i].RepoName, u.LowerName, newUserName, 1)
-		}
-		if err = UpdateAccessWithSession(sess, &accesses[i]); err != nil {
-			return err
-		}
-	}
-
-	repos, err := GetRepositories(u.Id, true)
-	if err != nil {
-		return err
-	}
-	for i := range repos {
-		accesses = make([]Access, 0, 10)
-		// Update accesses of user repository.
-		if err = x.Find(&accesses, &Access{RepoName: u.LowerName + "/" + repos[i].LowerName}); err != nil {
-			return err
-		}
-
-		for j := range accesses {
-			// if the access is not the user's access (already updated above)
-			if accesses[j].UserName != u.LowerName {
-				accesses[j].RepoName = newUserName + "/" + repos[i].LowerName
-				if err = UpdateAccessWithSession(sess, &accesses[j]); err != nil {
-					return err
-				}
-			}
-		}
-	}
-
-	// Change user directory name.
-	if err = os.Rename(UserPath(u.LowerName), UserPath(newUserName)); err != nil {
-		sess.Rollback()
-		return err
-	}
-
-	return sess.Commit()
+	return os.Rename(UserPath(u.LowerName), UserPath(newUserName))
 }
 }
 
 
 // UpdateUser updates user's information.
 // UpdateUser updates user's information.
@@ -521,7 +469,7 @@ func DeleteUser(u *User) error {
 		return err
 		return err
 	}
 	}
 	// Delete all accesses.
 	// Delete all accesses.
-	if _, err = x.Delete(&Access{UserName: u.LowerName}); err != nil {
+	if _, err = x.Delete(&Access{UserID: u.Id}); err != nil {
 		return err
 		return err
 	}
 	}
 	// Delete all alternative email addresses
 	// Delete all alternative email addresses

+ 1 - 1
modules/middleware/org.go

@@ -87,7 +87,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
 				return
 				return
 			}
 			}
 			ctx.Data["Team"] = ctx.Org.Team
 			ctx.Data["Team"] = ctx.Org.Team
-			ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize == models.ORG_ADMIN
+			ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize >= models.AdminAccess
 		}
 		}
 		ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam
 		ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam
 		if requireAdminTeam && !ctx.Org.IsAdminTeam {
 		if requireAdminTeam && !ctx.Org.IsAdminTeam {

+ 37 - 118
modules/middleware/repo.go

@@ -5,7 +5,6 @@
 package middleware
 package middleware
 
 
 import (
 import (
-	"errors"
 	"fmt"
 	"fmt"
 	"net/url"
 	"net/url"
 	"strings"
 	"strings"
@@ -29,17 +28,10 @@ func ApiRepoAssignment() macaron.Handler {
 			err error
 			err error
 		)
 		)
 
 
-		// Collaborators who have write access can be seen as owners.
-		if ctx.IsSigned {
-			ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
-			if err != nil {
-				ctx.JSON(500, &base.ApiJsonErr{"HasAccess: " + err.Error(), base.DOC_URL})
-				return
-			}
-			ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
-		}
-
-		if !ctx.Repo.IsTrueOwner {
+		// Check if the user is the same as the repository owner
+		if ctx.IsSigned && u.LowerName == strings.ToLower(userName) {
+			u = ctx.User
+		} else {
 			u, err = models.GetUserByName(userName)
 			u, err = models.GetUserByName(userName)
 			if err != nil {
 			if err != nil {
 				if err == models.ErrUserNotExist {
 				if err == models.ErrUserNotExist {
@@ -49,64 +41,38 @@ func ApiRepoAssignment() macaron.Handler {
 				}
 				}
 				return
 				return
 			}
 			}
-		} else {
-			u = ctx.User
 		}
 		}
 		ctx.Repo.Owner = u
 		ctx.Repo.Owner = u
 
 
-		// Organization owner team members are true owners as well.
-		if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
-			ctx.Repo.IsTrueOwner = true
-		}
-
 		// Get repository.
 		// Get repository.
 		repo, err := models.GetRepositoryByName(u.Id, repoName)
 		repo, err := models.GetRepositoryByName(u.Id, repoName)
 		if err != nil {
 		if err != nil {
 			if err == models.ErrRepoNotExist {
 			if err == models.ErrRepoNotExist {
 				ctx.Error(404)
 				ctx.Error(404)
-				return
+			} else {
+				ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
 			}
 			}
-			ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
 			return
 			return
 		} else if err = repo.GetOwner(); err != nil {
 		} else if err = repo.GetOwner(); err != nil {
 			ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
 			ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
 			return
 			return
 		}
 		}
 
 
-		// Check if the mirror repository owner(mirror repository doesn't have access).
-		if ctx.IsSigned && !ctx.Repo.IsOwner {
-			if repo.OwnerId == ctx.User.Id {
-				ctx.Repo.IsOwner = true
-			}
-			// Check if current user has admin permission to repository.
-			if u.IsOrganization() {
-				auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
-				if err != nil {
-					ctx.JSON(500, &base.ApiJsonErr{"GetHighestAuthorize: " + err.Error(), base.DOC_URL})
-					return
-				}
-				if auth == models.ORG_ADMIN {
-					ctx.Repo.IsOwner = true
-					ctx.Repo.IsAdmin = true
-				}
+		if ctx.IsSigned {
+			mode, err := models.AccessLevel(ctx.User, repo)
+			if err != nil {
+				ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL})
+				return
 			}
 			}
+			ctx.Repo.IsOwner = mode >= models.WriteAccess
+			ctx.Repo.IsAdmin = mode >= models.ReadAccess
+			ctx.Repo.IsTrueOwner = mode >= models.OwnerAccess
 		}
 		}
 
 
 		// Check access.
 		// Check access.
 		if repo.IsPrivate && !ctx.Repo.IsOwner {
 		if repo.IsPrivate && !ctx.Repo.IsOwner {
-			if ctx.User == nil {
-				ctx.Error(404)
-				return
-			}
-
-			hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
-			if err != nil {
-				ctx.JSON(500, &base.ApiJsonErr{"HasAccess: " + err.Error(), base.DOC_URL})
-				return
-			} else if !hasAccess {
-				ctx.Error(404)
-				return
-			}
+			ctx.Error(404)
+			return
 		}
 		}
 		ctx.Repo.HasAccess = true
 		ctx.Repo.HasAccess = true
 
 
@@ -242,101 +208,54 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
 			refName = ctx.Params(":path")
 			refName = ctx.Params(":path")
 		}
 		}
 
 
-		// Collaborators who have write access can be seen as owners.
-		if ctx.IsSigned {
-			ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
-			if err != nil {
-				ctx.Handle(500, "HasAccess", err)
-				return
-			}
-			ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
-		}
-
-		if !ctx.Repo.IsTrueOwner {
+		// Check if the user is the same as the repository owner
+		if ctx.IsSigned && u.LowerName == strings.ToLower(userName) {
+			u = ctx.User
+		} else {
 			u, err = models.GetUserByName(userName)
 			u, err = models.GetUserByName(userName)
 			if err != nil {
 			if err != nil {
 				if err == models.ErrUserNotExist {
 				if err == models.ErrUserNotExist {
-					ctx.Handle(404, "GetUserByName", err)
-				} else if redirect {
-					log.Error(4, "GetUserByName", err)
-					ctx.Redirect(setting.AppSubUrl + "/")
+					ctx.Error(404)
 				} else {
 				} else {
-					ctx.Handle(500, "GetUserByName", err)
+					ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL})
 				}
 				}
 				return
 				return
 			}
 			}
-		} else {
-			u = ctx.User
-		}
-
-		if u == nil {
-			if redirect {
-				ctx.Redirect(setting.AppSubUrl + "/")
-				return
-			}
-			ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository"))
-			return
 		}
 		}
 		ctx.Repo.Owner = u
 		ctx.Repo.Owner = u
 
 
-		// Organization owner team members are true owners as well.
-		if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
-			ctx.Repo.IsTrueOwner = true
-		}
-
 		// Get repository.
 		// Get repository.
 		repo, err := models.GetRepositoryByName(u.Id, repoName)
 		repo, err := models.GetRepositoryByName(u.Id, repoName)
 		if err != nil {
 		if err != nil {
 			if err == models.ErrRepoNotExist {
 			if err == models.ErrRepoNotExist {
-				ctx.Handle(404, "GetRepositoryByName", err)
-				return
-			} else if redirect {
-				ctx.Redirect(setting.AppSubUrl + "/")
-				return
+				ctx.Error(404)
+			} else {
+				ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
 			}
 			}
-			ctx.Handle(500, "GetRepositoryByName", err)
 			return
 			return
 		} else if err = repo.GetOwner(); err != nil {
 		} else if err = repo.GetOwner(); err != nil {
-			ctx.Handle(500, "GetOwner", err)
+			ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
 			return
 			return
 		}
 		}
 
 
-		// Check if the mirror repository owner(mirror repository doesn't have access).
-		if ctx.IsSigned && !ctx.Repo.IsOwner {
-			if repo.OwnerId == ctx.User.Id {
-				ctx.Repo.IsOwner = true
-			}
-			// Check if current user has admin permission to repository.
-			if u.IsOrganization() {
-				auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
-				if err != nil {
-					ctx.Handle(500, "GetHighestAuthorize", err)
-					return
-				}
-				if auth == models.ORG_ADMIN {
-					ctx.Repo.IsOwner = true
-					ctx.Repo.IsAdmin = true
-				}
+		if ctx.IsSigned {
+			mode, err := models.AccessLevel(ctx.User, repo)
+			if err != nil {
+				ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL})
+				return
 			}
 			}
+			ctx.Repo.IsOwner = mode >= models.WriteAccess
+			ctx.Repo.IsAdmin = mode >= models.ReadAccess
+			ctx.Repo.IsTrueOwner = mode >= models.OwnerAccess
 		}
 		}
 
 
 		// Check access.
 		// Check access.
 		if repo.IsPrivate && !ctx.Repo.IsOwner {
 		if repo.IsPrivate && !ctx.Repo.IsOwner {
-			if ctx.User == nil {
-				ctx.Handle(404, "HasAccess", nil)
-				return
-			}
-
-			hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
-			if err != nil {
-				ctx.Handle(500, "HasAccess", err)
-				return
-			} else if !hasAccess {
-				ctx.Handle(404, "HasAccess", nil)
-				return
-			}
+			ctx.Error(404)
+			return
 		}
 		}
 		ctx.Repo.HasAccess = true
 		ctx.Repo.HasAccess = true
+
 		ctx.Data["HasAccess"] = true
 		ctx.Data["HasAccess"] = true
 
 
 		if repo.IsMirror {
 		if repo.IsMirror {

+ 1 - 1
routers/api/v1/repo.go

@@ -255,7 +255,7 @@ func ListMyRepos(ctx *middleware.Context) {
 			return
 			return
 		}
 		}
 
 
-		repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{false, access >= models.WRITABLE, true})
+		repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{false, access >= models.WriteAccess, true})
 
 
 		// FIXME: cache result to reduce DB query?
 		// FIXME: cache result to reduce DB query?
 		if repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(ctx.User.Id) {
 		if repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(ctx.User.Id) {

+ 8 - 8
routers/org/teams.go

@@ -168,14 +168,14 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
 	}
 	}
 
 
 	// Validate permission level.
 	// Validate permission level.
-	var auth models.AuthorizeType
+	var auth models.AccessMode
 	switch form.Permission {
 	switch form.Permission {
 	case "read":
 	case "read":
-		auth = models.ORG_READABLE
+		auth = models.ReadAccess
 	case "write":
 	case "write":
-		auth = models.ORG_WRITABLE
+		auth = models.WriteAccess
 	case "admin":
 	case "admin":
-		auth = models.ORG_ADMIN
+		auth = models.AdminAccess
 	default:
 	default:
 		ctx.Error(401)
 		ctx.Error(401)
 		return
 		return
@@ -249,14 +249,14 @@ func EditTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
 	isAuthChanged := false
 	isAuthChanged := false
 	if !t.IsOwnerTeam() {
 	if !t.IsOwnerTeam() {
 		// Validate permission level.
 		// Validate permission level.
-		var auth models.AuthorizeType
+		var auth models.AccessMode
 		switch form.Permission {
 		switch form.Permission {
 		case "read":
 		case "read":
-			auth = models.ORG_READABLE
+			auth = models.ReadAccess
 		case "write":
 		case "write":
-			auth = models.ORG_WRITABLE
+			auth = models.WriteAccess
 		case "admin":
 		case "admin":
-			auth = models.ORG_ADMIN
+			auth = models.AdminAccess
 		default:
 		default:
 			ctx.Error(401)
 			ctx.Error(401)
 			return
 			return

+ 5 - 5
routers/repo/http.go

@@ -115,18 +115,18 @@ func Http(ctx *middleware.Context) {
 		}
 		}
 
 
 		if !isPublicPull {
 		if !isPublicPull {
-			var tp = models.WRITABLE
+			var tp = models.WriteAccess
 			if isPull {
 			if isPull {
-				tp = models.READABLE
+				tp = models.ReadAccess
 			}
 			}
 
 
-			has, err := models.HasAccess(authUsername, username+"/"+reponame, tp)
+			has, err := models.HasAccess(authUser, repo, tp)
 			if err != nil {
 			if err != nil {
 				ctx.Handle(401, "no basic auth and digit auth", nil)
 				ctx.Handle(401, "no basic auth and digit auth", nil)
 				return
 				return
 			} else if !has {
 			} else if !has {
-				if tp == models.READABLE {
-					has, err = models.HasAccess(authUsername, username+"/"+reponame, models.WRITABLE)
+				if tp == models.ReadAccess {
+					has, err = models.HasAccess(authUser, repo, models.WriteAccess)
 					if err != nil || !has {
 					if err != nil || !has {
 						ctx.Handle(401, "no basic auth and digit auth", nil)
 						ctx.Handle(401, "no basic auth and digit auth", nil)
 						return
 						return

+ 3 - 4
routers/user/home.go

@@ -103,8 +103,7 @@ func Dashboard(ctx *middleware.Context) {
 	feeds := make([]*models.Action, 0, len(actions))
 	feeds := make([]*models.Action, 0, len(actions))
 	for _, act := range actions {
 	for _, act := range actions {
 		if act.IsPrivate {
 		if act.IsPrivate {
-			if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
-				models.READABLE); !has {
+			if has, _ := models.HasAccess(ctx.User, &models.Repository{Id: act.RepoId, IsPrivate: true}, models.ReadAccess); !has {
 				continue
 				continue
 			}
 			}
 		}
 		}
@@ -211,8 +210,8 @@ func Profile(ctx *middleware.Context) {
 				if !ctx.IsSigned {
 				if !ctx.IsSigned {
 					continue
 					continue
 				}
 				}
-				if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
-					models.READABLE); !has {
+				if has, _ := models.HasAccess(ctx.User, &models.Repository{Id: act.RepoId, IsPrivate: true},
+					models.ReadAccess); !has {
 					continue
 					continue
 				}
 				}
 			}
 			}