From 4e79adf6b5bf7ec7bc3b2b47469baafd1cb0b774 Mon Sep 17 00:00:00 2001 From: Peter Smit Date: Thu, 5 Feb 2015 15:29:08 +0200 Subject: 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. --- modules/middleware/repo.go | 155 +++++++++++---------------------------------- 1 file changed, 37 insertions(+), 118 deletions(-) (limited to 'modules/middleware/repo.go') diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index d143d8a8..66e6f3a5 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -5,7 +5,6 @@ package middleware import ( - "errors" "fmt" "net/url" "strings" @@ -29,17 +28,10 @@ func ApiRepoAssignment() macaron.Handler { 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) if err != nil { if err == models.ErrUserNotExist { @@ -49,64 +41,38 @@ func ApiRepoAssignment() macaron.Handler { } return } - } else { - u = ctx.User } 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. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { 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 } else if err = repo.GetOwner(); err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL}) 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. 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 @@ -242,101 +208,54 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { 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) if err != nil { 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 { - ctx.Handle(500, "GetUserByName", err) + ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL}) } 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 - // 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. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { 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 } else if err = repo.GetOwner(); err != nil { - ctx.Handle(500, "GetOwner", err) + ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL}) 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. 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.Data["HasAccess"] = true if repo.IsMirror { -- cgit v1.2.3 From 0d158e569b0c19614b5e946849e8b7a8e4a75015 Mon Sep 17 00:00:00 2001 From: Peter Smit Date: Mon, 9 Feb 2015 13:36:33 +0200 Subject: Change constants to UPPERCASE_WITH_UNDERSCORE style --- cmd/serve.go | 14 +++++++------- models/access.go | 24 ++++++++++++------------ models/org.go | 2 +- modules/middleware/org.go | 2 +- modules/middleware/repo.go | 12 ++++++------ routers/api/v1/repo.go | 2 +- routers/org/teams.go | 12 ++++++------ routers/repo/http.go | 12 ++++++------ routers/user/home.go | 4 ++-- 9 files changed, 42 insertions(+), 42 deletions(-) (limited to 'modules/middleware/repo.go') diff --git a/cmd/serve.go b/cmd/serve.go index d9d1a06b..90e1045c 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -59,14 +59,14 @@ func parseCmd(cmd string) (string, string) { var ( COMMANDS_READONLY = map[string]models.AccessMode{ - "git-upload-pack": models.WriteAccess, - "git upload-pack": models.WriteAccess, - "git-upload-archive": models.WriteAccess, + "git-upload-pack": models.ACCESS_MODE_WRITE, + "git upload-pack": models.ACCESS_MODE_WRITE, + "git-upload-archive": models.ACCESS_MODE_WRITE, } COMMANDS_WRITE = map[string]models.AccessMode{ - "git-receive-pack": models.ReadAccess, - "git receive-pack": models.ReadAccess, + "git-receive-pack": models.ACCESS_MODE_READ, + "git receive-pack": models.ACCESS_MODE_READ, } ) @@ -141,7 +141,7 @@ func runServ(k *cli.Context) { switch { case isWrite: - has, err := models.HasAccess(user, repo, models.WriteAccess) + has, err := models.HasAccess(user, repo, models.ACCESS_MODE_WRITE) if err != nil { println("Gogs: internal error:", err.Error()) log.GitLogger.Fatal(2, "Fail to check write access:", err) @@ -154,7 +154,7 @@ func runServ(k *cli.Context) { break } - has, err := models.HasAccess(user, repo, models.ReadAccess) + has, err := models.HasAccess(user, repo, models.ACCESS_MODE_READ) if err != nil { println("Gogs: internal error:", err.Error()) log.GitLogger.Fatal(2, "Fail to check read access:", err) diff --git a/models/access.go b/models/access.go index ee678a07..916711f7 100644 --- a/models/access.go +++ b/models/access.go @@ -11,15 +11,15 @@ package models type AccessMode int const ( - NoAccess AccessMode = iota - ReadAccess - WriteAccess - AdminAccess - OwnerAccess + ACCESS_MODE_NONE AccessMode = iota + ACCESS_MODE_READ + ACCESS_MODE_WRITE + ACCESS_MODE_ADMIN + ACCESS_MODE_OWNER ) func maxAccessMode(modes ...AccessMode) AccessMode { - max := NoAccess + max := ACCESS_MODE_NONE for _, mode := range modes { if mode > max { max = mode @@ -47,14 +47,14 @@ func HasAccess(u *User, r *Repository, testMode AccessMode) (bool, error) { // 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 + mode := ACCESS_MODE_NONE if !r.IsPrivate { - mode = ReadAccess + mode = ACCESS_MODE_READ } if u != nil { if u.Id == r.OwnerId { - return OwnerAccess, nil + return ACCESS_MODE_OWNER, nil } a := &Access{UserID: u.Id, RepoID: r.Id} @@ -101,7 +101,7 @@ func (r *Repository) RecalcAccessSess() error { return err } for _, c := range collaborators { - accessMap[c.Id] = WriteAccess + accessMap[c.Id] = ACCESS_MODE_WRITE } if err := r.GetOwner(); err != nil { @@ -126,9 +126,9 @@ func (r *Repository) RecalcAccessSess() error { } } - minMode := ReadAccess + minMode := ACCESS_MODE_READ if !r.IsPrivate { - minMode = WriteAccess + minMode = ACCESS_MODE_WRITE } newAccesses := make([]Access, 0, len(accessMap)) diff --git a/models/org.go b/models/org.go index 5e3bb0e0..f6d472a6 100644 --- a/models/org.go +++ b/models/org.go @@ -135,7 +135,7 @@ func CreateOrganization(org, owner *User) (*User, error) { OrgId: org.Id, LowerName: strings.ToLower(OWNER_TEAM), Name: OWNER_TEAM, - Authorize: OwnerAccess, + Authorize: ACCESS_MODE_OWNER, NumMembers: 1, } if _, err = sess.Insert(t); err != nil { diff --git a/modules/middleware/org.go b/modules/middleware/org.go index cbce5486..0e544fe4 100644 --- a/modules/middleware/org.go +++ b/modules/middleware/org.go @@ -87,7 +87,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { return } ctx.Data["Team"] = ctx.Org.Team - ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize >= models.AdminAccess + ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize >= models.ACCESS_MODE_ADMIN } ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam if requireAdminTeam && !ctx.Org.IsAdminTeam { diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 66e6f3a5..bc1d1f96 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -64,9 +64,9 @@ func ApiRepoAssignment() macaron.Handler { 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 + ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE + ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ + ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER } // Check access. @@ -244,9 +244,9 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { 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 + ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE + ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ + ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER } // Check access. diff --git a/routers/api/v1/repo.go b/routers/api/v1/repo.go index 78c9f9a6..f5128e47 100644 --- a/routers/api/v1/repo.go +++ b/routers/api/v1/repo.go @@ -255,7 +255,7 @@ func ListMyRepos(ctx *middleware.Context) { return } - repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{false, access >= models.WriteAccess, true}) + repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{false, access >= models.ACCESS_MODE_WRITE, true}) // FIXME: cache result to reduce DB query? if repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(ctx.User.Id) { diff --git a/routers/org/teams.go b/routers/org/teams.go index 4fef02c9..a315abe0 100644 --- a/routers/org/teams.go +++ b/routers/org/teams.go @@ -171,11 +171,11 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) { var auth models.AccessMode switch form.Permission { case "read": - auth = models.ReadAccess + auth = models.ACCESS_MODE_READ case "write": - auth = models.WriteAccess + auth = models.ACCESS_MODE_WRITE case "admin": - auth = models.AdminAccess + auth = models.ACCESS_MODE_ADMIN default: ctx.Error(401) return @@ -252,11 +252,11 @@ func EditTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) { var auth models.AccessMode switch form.Permission { case "read": - auth = models.ReadAccess + auth = models.ACCESS_MODE_READ case "write": - auth = models.WriteAccess + auth = models.ACCESS_MODE_WRITE case "admin": - auth = models.AdminAccess + auth = models.ACCESS_MODE_ADMIN default: ctx.Error(401) return diff --git a/routers/repo/http.go b/routers/repo/http.go index 716c7127..4173c7a9 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -115,9 +115,9 @@ func Http(ctx *middleware.Context) { } if !isPublicPull { - var tp = models.WriteAccess + var tp = models.ACCESS_MODE_WRITE if isPull { - tp = models.ReadAccess + tp = models.ACCESS_MODE_READ } has, err := models.HasAccess(authUser, repo, tp) @@ -125,8 +125,8 @@ func Http(ctx *middleware.Context) { ctx.Handle(401, "no basic auth and digit auth", nil) return } else if !has { - if tp == models.ReadAccess { - has, err = models.HasAccess(authUser, repo, models.WriteAccess) + if tp == models.ACCESS_MODE_READ { + has, err = models.HasAccess(authUser, repo, models.ACCESS_MODE_WRITE) if err != nil || !has { ctx.Handle(401, "no basic auth and digit auth", nil) return @@ -268,7 +268,7 @@ func serviceRpc(rpc string, hr handler) { access := hasAccess(r, hr.Config, dir, rpc, true) if access == false { - renderNoAccess(w) + renderACCESS_MODE_NONE(w) return } @@ -495,7 +495,7 @@ func renderNotFound(w http.ResponseWriter) { w.Write([]byte("Not Found")) } -func renderNoAccess(w http.ResponseWriter) { +func renderACCESS_MODE_NONE(w http.ResponseWriter) { w.WriteHeader(http.StatusForbidden) w.Write([]byte("Forbidden")) } diff --git a/routers/user/home.go b/routers/user/home.go index 82325cb7..ce82ae77 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -103,7 +103,7 @@ func Dashboard(ctx *middleware.Context) { feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { if act.IsPrivate { - if has, _ := models.HasAccess(ctx.User, &models.Repository{Id: act.RepoId, IsPrivate: true}, models.ReadAccess); !has { + if has, _ := models.HasAccess(ctx.User, &models.Repository{Id: act.RepoId, IsPrivate: true}, models.ACCESS_MODE_READ); !has { continue } } @@ -211,7 +211,7 @@ func Profile(ctx *middleware.Context) { continue } if has, _ := models.HasAccess(ctx.User, &models.Repository{Id: act.RepoId, IsPrivate: true}, - models.ReadAccess); !has { + models.ACCESS_MODE_READ); !has { continue } } -- cgit v1.2.3 From 0a4cda0dd4d7c906668d9d2e283fbe9ebe2e1608 Mon Sep 17 00:00:00 2001 From: Peter Smit Date: Thu, 5 Feb 2015 15:29:08 +0200 Subject: 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. --- cmd/serve.go | 41 ++++--- models/access.go | 175 +++++++++++++++++----------- models/migrations/migrations.go | 10 +- models/org.go | 245 +++++---------------------------------- models/repo.go | 251 ++++------------------------------------ models/user.go | 59 +--------- modules/middleware/org.go | 2 +- modules/middleware/repo.go | 155 ++++++------------------- routers/api/v1/repo.go | 2 +- routers/org/teams.go | 16 +-- routers/repo/http.go | 10 +- routers/user/home.go | 7 +- 12 files changed, 243 insertions(+), 730 deletions(-) (limited to 'modules/middleware/repo.go') diff --git a/cmd/serve.go b/cmd/serve.go index e957d45d..62e5d143 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -8,7 +8,6 @@ import ( "fmt" "os" "os/exec" - "path" "path/filepath" "strings" "time" @@ -67,19 +66,19 @@ func parseCmd(cmd string) (string, string) { } 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] return e } @@ -144,9 +143,19 @@ func runServ(k *cli.Context) { } // 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 { 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 { println("Gogs: internal error:", err.Error()) log.GitLogger.Fatal(2, "Fail to check write access:", err) @@ -155,21 +164,11 @@ func runServ(k *cli.Context) { log.GitLogger.Fatal(2, "User %s has no right to write repository %s", user.Name, repoPath) } 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 { break } - has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.READABLE) + has, err := models.HasAccess(user, repo, models.ReadAccess) if err != nil { println("Gogs: internal error:", err.Error()) log.GitLogger.Fatal(2, "Fail to check read access:", err) diff --git a/models/access.go b/models/access.go index 6df1da29..d85f24cd 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)"` // / - 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 /. -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 + +} diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 814564e9..1510bafd 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -47,10 +47,11 @@ type Version struct { } // This is a sequence of migrations. Add new migrations to the bottom of the list. -// If you want to "retire" a migration, remove it from the top of the list and -// update _MIN_VER_DB accordingly +// If you want to "retire" a migration, remove it from the top of the list and +// update _MIN_VER_DB accordingly var migrations = []Migration{ NewMigration("generate collaboration from access", accessToCollaboration), // V0 -> V1 + NewMigration("refactor access table to use id's", accessRefactor), // V1 -> V2 } // Migrate database to current version @@ -206,3 +207,8 @@ func accessToCollaboration(x *xorm.Engine) error { return sess.Commit() } + +func accessRefactor(x *xorm.Engine) error { + //TODO + return nil +} diff --git a/models/org.go b/models/org.go index 3d37a37d..775caa86 100644 --- a/models/org.go +++ b/models/org.go @@ -6,9 +6,7 @@ package models import ( "errors" - "fmt" "os" - "path" "strings" "github.com/Unknwon/com" @@ -136,7 +134,7 @@ func CreateOrganization(org, owner *User) (*User, error) { OrgId: org.Id, LowerName: strings.ToLower(OWNER_TEAM), Name: OWNER_TEAM, - Authorize: ORG_ADMIN, + Authorize: OwnerAccess, NumMembers: 1, } if _, err = sess.Insert(t); err != nil { @@ -371,10 +369,10 @@ func RemoveOrgUser(orgId, uid int64) error { return err } access := &Access{ - UserName: u.LowerName, + UserID: u.Id, } for _, repo := range org.Repos { - access.RepoName = path.Join(org.LowerName, repo.LowerName) + access.RepoID = repo.Id if _, err = sess.Delete(access); err != nil { sess.Rollback() return err @@ -405,21 +403,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" // Team represents a organization team. @@ -429,7 +412,7 @@ type Team struct { LowerName string Name string Description string - Authorize AuthorizeType + Authorize AccessMode RepoIds string `xorm:"TEXT"` Repos []*Repository `xorm:"-"` Members []*User `xorm:"-"` @@ -484,25 +467,6 @@ func (t *Team) RemoveMember(uid int64) error { return RemoveTeamMember(t.OrgId, t.Id, uid) } -// addAccessWithAuthorize inserts or updates access with given mode. -func addAccessWithAuthorize(e Engine, access *Access, mode AccessType) error { - has, err := e.Get(access) - if err != nil { - return fmt.Errorf("fail to get access: %v", err) - } - access.Mode = mode - if has { - if _, err = e.Id(access.Id).Update(access); err != nil { - return fmt.Errorf("fail to update access: %v", err) - } - } else { - if _, err = e.Insert(access); err != nil { - return fmt.Errorf("fail to insert access: %v", err) - } - } - return nil -} - // AddRepository adds new repository to team of organization. func (t *Team) AddRepository(repo *Repository) (err error) { idStr := "$" + com.ToStr(repo.Id) + "|" @@ -531,27 +495,13 @@ func (t *Team) AddRepository(repo *Repository) (err error) { 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 { - auth, err := getHighestAuthorize(sess, 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(sess, u.Id, repo.Id, true); err != nil { + if err = WatchRepo(u.Id, repo.Id, true); err != nil { sess.Rollback() return err } @@ -559,6 +509,11 @@ func (t *Team) AddRepository(repo *Repository) (err error) { 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. func (t *Team) RemoveRepository(repoId int64) error { idStr := "$" + com.ToStr(repoId) + "|" @@ -590,32 +545,16 @@ func (t *Team) RemoveRepository(repoId int64) error { return err } - // Remove access to team members. + if err = repo.RecalcAccessSess(); err != nil { + sess.Rollback() + return err + } + for _, u := range t.Members { - auth, err := getHighestAuthorize(sess, t.OrgId, u.Id, repo.Id, t.Id) - if err != nil { + if err = WatchRepo(u.Id, repo.Id, false); err != nil { sess.Rollback() 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(sess, 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() @@ -693,34 +632,6 @@ func GetTeamById(teamId int64) (*Team, error) { return getTeamById(x, teamId) } -func getHighestAuthorize(e Engine, orgId, uid, repoId, teamId int64) (AuthorizeType, error) { - ts, err := getUserTeams(e, 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 -} - -// GetHighestAuthorize returns highest repository authorize level for given user and team. -func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error) { - return getHighestAuthorize(x, orgId, uid, repoId, teamId) -} - // UpdateTeam updates information of team. func UpdateTeam(t *Team, authChanged bool) (err error) { if !IsLegalName(t.Name) { @@ -738,45 +649,14 @@ func UpdateTeam(t *Team, authChanged bool) (err error) { } // Update access for team members if needed. - if authChanged && !t.IsOwnerTeam() { + if authChanged { if err = t.GetRepositories(); err != nil { 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 _, 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 } } } @@ -812,29 +692,8 @@ func DeleteTeam(t *Team) error { // Delete all accesses. 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 } } @@ -936,18 +795,6 @@ func AddTeamMember(orgId, teamId, uid int64) error { 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() defer sess.Close() if err = sess.Begin(); err != nil { @@ -969,24 +816,11 @@ func AddTeamMember(orgId, teamId, uid int64) error { } // Give access to team repositories. - mode := AuthorizeToAccessType(t.Authorize) for _, repo := range t.Repos { - auth, err := getHighestAuthorize(sess, t.OrgId, u.Id, repo.Id, teamId) - if err != nil { + if err = repo.RecalcAccessSess(); err != nil { sess.Rollback() 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. @@ -1036,12 +870,6 @@ func removeTeamMember(e Engine, orgId, teamId, uid int64) error { return err } - // Get user. - u, err := GetUserById(uid) - if err != nil { - return err - } - tu := &TeamUser{ Uid: uid, OrgId: orgId, @@ -1056,28 +884,9 @@ func removeTeamMember(e Engine, orgId, teamId, uid int64) error { // Delete access to team repositories. for _, repo := range t.Repos { - auth, err := getHighestAuthorize(e, t.OrgId, u.Id, repo.Id, teamId) - if err != nil { + if err = repo.RecalcAccessSess(); err != nil { 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 = e.Delete(access); err != nil { - return fmt.Errorf("fail to delete access: %v", err) - } else if err = watchRepo(e, u.Id, repo.Id, false); err != nil { - return err - } - } else if auth < t.Authorize { - // Downgrade authorize level. - if err = addAccessWithAuthorize(e, access, AuthorizeToAccessType(auth)); err != nil { - return err - } - } } // This must exist. diff --git a/models/repo.go b/models/repo.go index 35ee871f..5a669d9d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -206,14 +206,6 @@ func (repo *Repository) IsOwnedBy(u *User) bool { 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. func (repo *Repository) DescriptionHtml() template.HTML { sanitize := func(s string) string { @@ -548,36 +540,11 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror 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. 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() return nil, err } @@ -707,37 +674,10 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error { } 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. repo.OwnerId = newUser.Id + repo.Owner = newUser if _, err := sess.Id(repo.Id).Update(repo); err != nil { sess.Rollback() return err @@ -754,53 +694,8 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error { 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. @@ -833,33 +728,8 @@ func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) 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 = updateAccess(sess, &accesses[i]); err != nil { - sess.Rollback() - return err - } - } - // 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 { @@ -908,7 +778,7 @@ func DeleteRepository(uid, repoId int64, userName string) error { } // 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() return err } @@ -1228,41 +1098,30 @@ type Collaboration struct { // Add collaborator and accompanying access func (r *Repository) AddCollaborator(u *User) error { collaboration := &Collaboration{RepoID: r.Id, UserID: u.Id} + has, err := x.Get(collaboration) if err != nil { return err - } else if has { - return nil } - - if err = r.GetOwner(); err != nil { - return err + if has { + return nil } - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + if _, err = x.InsertOne(collaboration); err != nil { return err } - if _, err = sess.InsertOne(collaboration); err != nil { - sess.Rollback() - return err - } else if err = addAccess(sess, &Access{ - UserName: u.LowerName, - RepoName: path.Join(r.Owner.LowerName, r.LowerName), - Mode: WRITABLE}); err != nil { - sess.Rollback() + if err = r.GetOwner(); err != nil { return err } - return sess.Commit() + return r.RecalcAccessSess() } // GetCollaborators returns the collaborators for a repository func (r *Repository) GetCollaborators() ([]*User, error) { - collaborations := make([]*Collaboration, 0, 5) - if err := x.Where("repo_id=?", r.Id).Find(&collaborations); err != nil { + collaborations := make([]*Collaboration, 0) + if err := x.Find(&collaborations, &Collaboration{RepoID: r.Id}); err != nil { return nil, err } @@ -1278,50 +1137,14 @@ func (r *Repository) GetCollaborators() ([]*User, error) { } // Delete collaborator and accompanying access -func (r *Repository) DeleteCollaborator(u *User) (err error) { +func (r *Repository) DeleteCollaborator(u *User) error { collaboration := &Collaboration{RepoID: r.Id, UserID: u.Id} - has, err := x.Get(collaboration) - if err != nil { - return err - } else if !has { - return nil - } - if err = r.GetOwner(); err != nil { - return err - } - - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { + if has, err := x.Delete(collaboration); err != nil || has == 0 { return err } - needDelete := true - if r.Owner.IsOrganization() { - auth, err := getHighestAuthorize(sess, r.Owner.Id, u.Id, r.Id, 0) - if err != nil { - sess.Rollback() - return err - } - if auth > 0 { - needDelete = false - } - } - if needDelete { - if err = deleteAccess(sess, &Access{ - UserName: u.LowerName, - RepoName: path.Join(r.Owner.LowerName, r.LowerName), - Mode: WRITABLE}); err != nil { - sess.Rollback() - return err - } else if _, err = sess.Delete(collaboration); err != nil { - sess.Rollback() - return err - } - } - - return sess.Commit() + return r.RecalcAccessSess() } // __ __ __ .__ @@ -1495,40 +1318,10 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor 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( "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { diff --git a/models/user.go b/models/user.go index 5606cea3..9a6f93a4 100644 --- a/models/user.go +++ b/models/user.go @@ -395,62 +395,7 @@ func ChangeUserName(u *User, newUserName string) (err error) { if !IsLegalName(newUserName) { 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 = updateAccess(sess, &accesses[i]); err != nil { - sess.Rollback() - 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 = updateAccess(sess, &accesses[j]); err != nil { - sess.Rollback() - 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. @@ -523,7 +468,7 @@ func DeleteUser(u *User) error { return err } // 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 } // Delete all alternative email addresses diff --git a/modules/middleware/org.go b/modules/middleware/org.go index e6872586..cbce5486 100644 --- a/modules/middleware/org.go +++ b/modules/middleware/org.go @@ -87,7 +87,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler { return } 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 if requireAdminTeam && !ctx.Org.IsAdminTeam { diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 1ab158dd..8cc62904 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -5,7 +5,6 @@ package middleware import ( - "errors" "fmt" "net/url" "strings" @@ -29,17 +28,10 @@ func ApiRepoAssignment() macaron.Handler { 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) if err != nil { if err == models.ErrUserNotExist { @@ -49,64 +41,38 @@ func ApiRepoAssignment() macaron.Handler { } return } - } else { - u = ctx.User } 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. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { 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 } else if err = repo.GetOwner(); err != nil { ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL}) 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. 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 @@ -242,101 +208,54 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { 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) if err != nil { 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 { - ctx.Handle(500, "GetUserByName", err) + ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL}) } 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 - // 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. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { 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 } else if err = repo.GetOwner(); err != nil { - ctx.Handle(500, "GetOwner", err) + ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL}) 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. 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.Data["HasAccess"] = true if repo.IsMirror { diff --git a/routers/api/v1/repo.go b/routers/api/v1/repo.go index 469e4808..78c9f9a6 100644 --- a/routers/api/v1/repo.go +++ b/routers/api/v1/repo.go @@ -255,7 +255,7 @@ func ListMyRepos(ctx *middleware.Context) { 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? if repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(ctx.User.Id) { diff --git a/routers/org/teams.go b/routers/org/teams.go index 9dd9b8e2..f5f94be0 100644 --- a/routers/org/teams.go +++ b/routers/org/teams.go @@ -165,14 +165,14 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) { } // Validate permission level. - var auth models.AuthorizeType + var auth models.AccessMode switch form.Permission { case "read": - auth = models.ORG_READABLE + auth = models.ReadAccess case "write": - auth = models.ORG_WRITABLE + auth = models.WriteAccess case "admin": - auth = models.ORG_ADMIN + auth = models.AdminAccess default: ctx.Error(401) return @@ -246,14 +246,14 @@ func EditTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) { isAuthChanged := false if !t.IsOwnerTeam() { // Validate permission level. - var auth models.AuthorizeType + var auth models.AccessMode switch form.Permission { case "read": - auth = models.ORG_READABLE + auth = models.ReadAccess case "write": - auth = models.ORG_WRITABLE + auth = models.WriteAccess case "admin": - auth = models.ORG_ADMIN + auth = models.AdminAccess default: ctx.Error(401) return diff --git a/routers/repo/http.go b/routers/repo/http.go index f5dc0c9d..c6742af3 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -137,18 +137,18 @@ func Http(ctx *middleware.Context) { } if !isPublicPull { - var tp = models.WRITABLE + var tp = models.WriteAccess 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 { ctx.Handle(401, "no basic auth and digit auth", nil) return } 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 { ctx.Handle(401, "no basic auth and digit auth", nil) return diff --git a/routers/user/home.go b/routers/user/home.go index 5b02154c..82325cb7 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -103,8 +103,7 @@ func Dashboard(ctx *middleware.Context) { feeds := make([]*models.Action, 0, len(actions)) for _, act := range actions { 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 } } @@ -211,8 +210,8 @@ func Profile(ctx *middleware.Context) { if !ctx.IsSigned { 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 } } -- cgit v1.2.3 From 6d0f3a07d4fa3189b0b7c4e366bddb6d72ef7e68 Mon Sep 17 00:00:00 2001 From: Unknwon Date: Fri, 13 Feb 2015 00:58:46 -0500 Subject: code fix #941 caution: undertest --- cmd/serve.go | 11 +- models/access.go | 66 ++++++----- models/action.go | 42 ++++--- models/models.go | 10 ++ models/org.go | 110 +++++++++-------- models/repo.go | 286 +++++++++++++++++++++++---------------------- models/user.go | 10 +- modules/middleware/repo.go | 16 +-- routers/repo/http.go | 4 +- routers/user/home.go | 7 +- 10 files changed, 306 insertions(+), 256 deletions(-) (limited to 'modules/middleware/repo.go') diff --git a/cmd/serve.go b/cmd/serve.go index 54b37148..e8e5c186 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -83,16 +83,16 @@ func In(b string, sl map[string]models.AccessMode) bool { return e } -func runServ(k *cli.Context) { - if k.IsSet("config") { - setting.CustomConf = k.String("config") +func runServ(c *cli.Context) { + if c.IsSet("config") { + setting.CustomConf = c.String("config") } setup("serv.log") - if len(k.Args()) < 1 { + if len(c.Args()) < 1 { log.GitLogger.Fatal(2, "Not enough arguments") } - keys := strings.Split(k.Args()[0], "-") + keys := strings.Split(c.Args()[0], "-") if len(keys) != 2 { println("Gogs: auth file format error") log.GitLogger.Fatal(2, "Invalid auth file format: %s", os.Args[2]) @@ -116,6 +116,7 @@ func runServ(k *cli.Context) { cmd := os.Getenv("SSH_ORIGINAL_COMMAND") if cmd == "" { println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.") + println("If this is what you do not expect, please log in with password and setup Gogs under another user.") return } diff --git a/models/access.go b/models/access.go index 174aca98..e9742b31 100644 --- a/models/access.go +++ b/models/access.go @@ -14,16 +14,6 @@ const ( ACCESS_MODE_OWNER ) -func maxAccessMode(modes ...AccessMode) AccessMode { - max := ACCESS_MODE_NONE - 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. @@ -34,12 +24,6 @@ type Access struct { Mode AccessMode } -// 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 -} - // 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) { @@ -63,6 +47,12 @@ func AccessLevel(u *User, r *Repository) (AccessMode, error) { return mode, nil } +// 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 +} + // GetAccessibleRepositories finds all repositories where a user has access to, // besides his own. func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { @@ -88,12 +78,21 @@ func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { return repos, nil } -// Recalculate all accesses for repository -func (r *Repository) RecalcAccessSess() error { +func maxAccessMode(modes ...AccessMode) AccessMode { + max := ACCESS_MODE_NONE + for _, mode := range modes { + if mode > max { + max = mode + } + } + return max +} + +func (repo *Repository) recalculateAccesses(e Engine) error { accessMap := make(map[int64]AccessMode, 20) // Give all collaborators write access - collaborators, err := r.GetCollaborators() + collaborators, err := repo.getCollaborators(e) if err != nil { return err } @@ -101,20 +100,20 @@ func (r *Repository) RecalcAccessSess() error { accessMap[c.Id] = ACCESS_MODE_WRITE } - if err := r.GetOwner(); err != nil { + if err := repo.getOwner(e); err != nil { return err } - if r.Owner.IsOrganization() { - if err = r.Owner.GetTeams(); err != nil { + if repo.Owner.IsOrganization() { + if err = repo.Owner.getTeams(e); err != nil { return err } - for _, team := range r.Owner.Teams { - if !(team.IsOwnerTeam() || team.HasRepository(r)) { + for _, team := range repo.Owner.Teams { + if !(team.IsOwnerTeam() || team.HasRepository(repo)) { continue } - if err = team.GetMembers(); err != nil { + if err = team.getMembers(e); err != nil { return err } for _, u := range team.Members { @@ -124,28 +123,35 @@ func (r *Repository) RecalcAccessSess() error { } minMode := ACCESS_MODE_READ - if !r.IsPrivate { + if !repo.IsPrivate { minMode = ACCESS_MODE_WRITE } newAccesses := make([]Access, 0, len(accessMap)) for userID, mode := range accessMap { - if userID == r.OwnerId || mode <= minMode { + if userID == repo.OwnerId || mode <= minMode { continue } - newAccesses = append(newAccesses, Access{UserID: userID, RepoID: r.Id, Mode: mode}) + newAccesses = append(newAccesses, Access{ + UserID: userID, + RepoID: repo.Id, + Mode: mode}) } // Delete old accesses for repository - if _, err = x.Delete(&Access{RepoID: r.Id}); err != nil { + if _, err = e.Delete(&Access{RepoID: repo.Id}); err != nil { return err } // And insert the new ones - if _, err = x.Insert(newAccesses); err != nil { + if _, err = e.Insert(newAccesses); err != nil { return err } return nil +} +// RecalculateAccesses recalculates all accesses for repository. +func (r *Repository) RecalculateAccesses() error { + return r.recalculateAccesses(x) } diff --git a/models/action.go b/models/action.go index 5cba2f51..9ba661f1 100644 --- a/models/action.go +++ b/models/action.go @@ -412,21 +412,29 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, return nil } -// NewRepoAction adds new action for creating repository. -func NewRepoAction(u *User, repo *Repository) (err error) { - if err = NotifyWatchers(&Action{ActUserId: u.Id, ActUserName: u.Name, ActEmail: u.Email, - OpType: CREATE_REPO, RepoId: repo.Id, RepoUserName: repo.Owner.Name, RepoName: repo.Name, - IsPrivate: repo.IsPrivate}); err != nil { - log.Error(4, "NotifyWatchers: %d/%s", u.Id, repo.Name) - return err +func newRepoAction(e Engine, u *User, repo *Repository) (err error) { + if err = notifyWatchers(e, &Action{ + ActUserId: u.Id, + ActUserName: u.Name, + ActEmail: u.Email, + OpType: CREATE_REPO, + RepoId: repo.Id, + RepoUserName: repo.Owner.Name, + RepoName: repo.Name, + IsPrivate: repo.IsPrivate}); err != nil { + return fmt.Errorf("notify watchers '%d/%s'", u.Id, repo.Id) } log.Trace("action.NewRepoAction: %s/%s", u.Name, repo.Name) return err } -// TransferRepoAction adds new action for transferring repository. -func TransferRepoAction(u, newUser *User, repo *Repository) (err error) { +// NewRepoAction adds new action for creating repository. +func NewRepoAction(u *User, repo *Repository) (err error) { + return newRepoAction(x, u, repo) +} + +func transferRepoAction(e Engine, u, newUser *User, repo *Repository) (err error) { action := &Action{ ActUserId: u.Id, ActUserName: u.Name, @@ -438,20 +446,24 @@ func TransferRepoAction(u, newUser *User, repo *Repository) (err error) { IsPrivate: repo.IsPrivate, Content: path.Join(repo.Owner.LowerName, repo.LowerName), } - if err = NotifyWatchers(action); err != nil { - log.Error(4, "NotifyWatchers: %d/%s", u.Id, repo.Name) - return err + if err = notifyWatchers(e, action); err != nil { + return fmt.Errorf("notify watchers '%d/%s'", u.Id, repo.Id) } // Remove watch for organization. if repo.Owner.IsOrganization() { - if err = WatchRepo(repo.Owner.Id, repo.Id, false); err != nil { - log.Error(4, "WatchRepo", err) + if err = watchRepo(e, repo.Owner.Id, repo.Id, false); err != nil { + return fmt.Errorf("watch repository: %v", err) } } log.Trace("action.TransferRepoAction: %s/%s", u.Name, repo.Name) - return err + return nil +} + +// TransferRepoAction adds new action for transferring repository. +func TransferRepoAction(u, newUser *User, repo *Repository) (err error) { + return transferRepoAction(x, u, newUser, repo) } // GetFeeds returns action list of given user in given context. diff --git a/models/models.go b/models/models.go index 141e3ac4..1cb72296 100644 --- a/models/models.go +++ b/models/models.go @@ -24,12 +24,22 @@ import ( type Engine interface { Delete(interface{}) (int64, error) Exec(string, ...interface{}) (sql.Result, error) + Find(interface{}, ...interface{}) error Get(interface{}) (bool, error) Insert(...interface{}) (int64, error) + InsertOne(interface{}) (int64, error) Id(interface{}) *xorm.Session + Sql(string, ...interface{}) *xorm.Session Where(string, ...interface{}) *xorm.Session } +func sessionRelease(sess *xorm.Session) { + if !sess.IsCommitedOrRollbacked { + sess.Rollback() + } + sess.Close() +} + var ( x *xorm.Engine tables []interface{} diff --git a/models/org.go b/models/org.go index d667fb26..42b14bf0 100644 --- a/models/org.go +++ b/models/org.go @@ -32,19 +32,31 @@ func (org *User) IsOrgMember(uid int64) bool { return IsOrganizationMember(org.Id, uid) } +func (org *User) getTeam(e Engine, name string) (*Team, error) { + return getTeam(e, org.Id, name) +} + // GetTeam returns named team of organization. func (org *User) GetTeam(name string) (*Team, error) { - return GetTeam(org.Id, name) + return org.getTeam(x, name) +} + +func (org *User) getOwnerTeam(e Engine) (*Team, error) { + return org.getTeam(e, OWNER_TEAM) } // GetOwnerTeam returns owner team of organization. func (org *User) GetOwnerTeam() (*Team, error) { - return org.GetTeam(OWNER_TEAM) + return org.getOwnerTeam(x) +} + +func (org *User) getTeams(e Engine) error { + return e.Where("org_id=?", org.Id).Find(&org.Teams) } // GetTeams returns all teams that belong to organization. func (org *User) GetTeams() error { - return x.Where("org_id=?", org.Id).Find(&org.Teams) + return org.getTeams(x) } // GetMembers returns all members of organization. @@ -430,8 +442,7 @@ func (t *Team) IsMember(uid int64) bool { return IsTeamMember(t.OrgId, t.Id, uid) } -// GetRepositories returns all repositories in team of organization. -func (t *Team) GetRepositories() error { +func (t *Team) getRepositories(e Engine) error { idStrs := strings.Split(t.RepoIds, "|") t.Repos = make([]*Repository, 0, len(idStrs)) for _, str := range idStrs { @@ -442,7 +453,7 @@ func (t *Team) GetRepositories() error { if id == 0 { continue } - repo, err := GetRepositoryById(id) + repo, err := getRepositoryById(e, id) if err != nil { return err } @@ -451,10 +462,19 @@ func (t *Team) GetRepositories() error { return nil } +// GetRepositories returns all repositories in team of organization. +func (t *Team) GetRepositories() error { + return t.getRepositories(x) +} + +func (t *Team) getMembers(e Engine) (err error) { + t.Members, err = getTeamMembers(e, t.Id) + return err +} + // GetMembers returns all members in team of organization. func (t *Team) GetMembers() (err error) { - t.Members, err = GetTeamMembers(t.OrgId, t.Id) - return err + return t.getMembers(x) } // AddMember adds new member to team of organization. @@ -483,7 +503,7 @@ func (t *Team) AddRepository(repo *Repository) (err error) { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } @@ -491,26 +511,23 @@ func (t *Team) AddRepository(repo *Repository) (err error) { t.NumRepos++ t.RepoIds += idStr if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() return err } - if err = repo.RecalcAccessSess(); err != nil { - sess.Rollback() + if err = repo.recalculateAccesses(sess); err != nil { return err } for _, u := range t.Members { - if err = WatchRepo(u.Id, repo.Id, true); err != nil { - sess.Rollback() + if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { return err } } return sess.Commit() } -func (t *Team) HasRepository(r *Repository) bool { - idStr := "$" + com.ToStr(r.Id) + "|" +func (t *Team) HasRepository(repo *Repository) bool { + idStr := "$" + com.ToStr(repo.Id) + "|" return strings.Contains(t.RepoIds, idStr) } @@ -533,7 +550,7 @@ func (t *Team) RemoveRepository(repoId int64) error { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } @@ -541,18 +558,15 @@ func (t *Team) RemoveRepository(repoId int64) error { t.NumRepos-- t.RepoIds = strings.Replace(t.RepoIds, idStr, "", 1) if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() return err } - if err = repo.RecalcAccessSess(); err != nil { - sess.Rollback() + if err = repo.recalculateAccesses(sess); err != nil { return err } for _, u := range t.Members { - if err = WatchRepo(u.Id, repo.Id, false); err != nil { - sess.Rollback() + if err = watchRepo(sess, u.Id, repo.Id, false); err != nil { return err } } @@ -601,13 +615,12 @@ func NewTeam(t *Team) error { return sess.Commit() } -// GetTeam returns team by given team name and organization. -func GetTeam(orgId int64, name string) (*Team, error) { +func getTeam(e Engine, orgId int64, name string) (*Team, error) { t := &Team{ OrgId: orgId, LowerName: strings.ToLower(name), } - has, err := x.Get(t) + has, err := e.Get(t) if err != nil { return nil, err } else if !has { @@ -616,6 +629,11 @@ func GetTeam(orgId int64, name string) (*Team, error) { return t, nil } +// GetTeam returns team by given team name and organization. +func GetTeam(orgId int64, name string) (*Team, error) { + return getTeam(x, orgId, name) +} + func getTeamById(e Engine, teamId int64) (*Team, error) { t := new(Team) has, err := e.Id(teamId).Get(t) @@ -643,19 +661,19 @@ func UpdateTeam(t *Team, authChanged bool) (err error) { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } // Update access for team members if needed. if authChanged { - if err = t.GetRepositories(); err != nil { + if err = t.getRepositories(sess); err != nil { return err } for _, repo := range t.Repos { - if err = repo.RecalcAccessSess(); err != nil { + if err = repo.recalculateAccesses(sess); err != nil { return err } } @@ -663,7 +681,6 @@ func UpdateTeam(t *Team, authChanged bool) (err error) { t.LowerName = strings.ToLower(t.Name) if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() return err } return sess.Commit() @@ -685,32 +702,29 @@ func DeleteTeam(t *Team) error { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } // Delete all accesses. for _, repo := range t.Repos { - if err = repo.RecalcAccessSess(); err != nil { + if err = repo.recalculateAccesses(sess); err != nil { return err } } // Delete team-user. if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.Id).Delete(new(TeamUser)); err != nil { - sess.Rollback() return err } // Delete team. if _, err = sess.Id(t.Id).Delete(new(Team)); err != nil { - sess.Rollback() return err } // Update organization number of teams. if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams - 1 WHERE id = ?", t.OrgId); err != nil { - sess.Rollback() return err } @@ -742,13 +756,17 @@ func IsTeamMember(orgId, teamId, uid int64) bool { return isTeamMember(x, orgId, teamId, uid) } -// GetTeamMembers returns all members in given team of organization. -func GetTeamMembers(orgId, teamId int64) ([]*User, error) { +func getTeamMembers(e Engine, teamID int64) ([]*User, error) { us := make([]*User, 0, 10) - err := x.Sql("SELECT * FROM `user` JOIN `team_user` ON `team_user`.`team_id` = ? AND `team_user`.`uid` = `user`.`id`", teamId).Find(&us) + err := e.Sql("SELECT * FROM `user` JOIN `team_user` ON `team_user`.`team_id` = ? AND `team_user`.`uid` = `user`.`id`", teamID).Find(&us) return us, err } +// GetTeamMembers returns all members in given team of organization. +func GetTeamMembers(teamID int64) ([]*User, error) { + return getTeamMembers(x, teamID) +} + func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) { tus := make([]*TeamUser, 0, 5) if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil { @@ -796,7 +814,7 @@ func AddTeamMember(orgId, teamId, uid int64) error { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } @@ -808,26 +826,21 @@ func AddTeamMember(orgId, teamId, uid int64) error { } if _, err = sess.Insert(tu); err != nil { - sess.Rollback() return err } else if _, err = sess.Id(t.Id).Update(t); err != nil { - sess.Rollback() return err } // Give access to team repositories. for _, repo := range t.Repos { - if err = repo.RecalcAccessSess(); err != nil { - sess.Rollback() + if err = repo.recalculateAccesses(sess); err != nil { return err } } // We make sure it exists before. ou := new(OrgUser) - _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou) - if err != nil { - sess.Rollback() + if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil { return err } ou.NumTeams++ @@ -835,7 +848,6 @@ func AddTeamMember(orgId, teamId, uid int64) error { ou.IsOwner = true } if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil { - sess.Rollback() return err } @@ -860,12 +872,12 @@ func removeTeamMember(e Engine, orgId, teamId, uid int64) error { t.NumMembers-- - if err = t.GetRepositories(); err != nil { + if err = t.getRepositories(e); err != nil { return err } // Get organization. - org, err := GetUserById(orgId) + org, err := getUserById(e, orgId) if err != nil { return err } @@ -884,7 +896,7 @@ func removeTeamMember(e Engine, orgId, teamId, uid int64) error { // Delete access to team repositories. for _, repo := range t.Repos { - if err = repo.RecalcAccessSess(); err != nil { + if err = repo.recalculateAccesses(e); err != nil { return err } } diff --git a/models/repo.go b/models/repo.go index 5a669d9d..75e29b09 100644 --- a/models/repo.go +++ b/models/repo.go @@ -167,13 +167,17 @@ type Repository struct { Updated time.Time `xorm:"UPDATED"` } -func (repo *Repository) GetOwner() (err error) { +func (repo *Repository) getOwner(e Engine) (err error) { if repo.Owner == nil { - repo.Owner, err = GetUserById(repo.OwnerId) + repo.Owner, err = getUserById(e, repo.OwnerId) } return err } +func (repo *Repository) GetOwner() (err error) { + return repo.getOwner(x) +} + func (repo *Repository) GetMirror() (err error) { repo.Mirror, err = GetMirror(repo.Id) return err @@ -403,7 +407,7 @@ func createUpdateHook(repoPath string) error { } // InitRepository initializes README and .gitignore if needed. -func initRepository(f string, u *User, repo *Repository, initReadme bool, repoLang, license string) error { +func initRepository(e Engine, f string, u *User, repo *Repository, initReadme bool, repoLang, license string) error { repoPath := RepoPath(u.Name, repo.Name) // Create bare new repository. @@ -493,12 +497,12 @@ func initRepository(f string, u *User, repo *Repository, initReadme bool, repoLa if len(fileName) == 0 { // Re-fetch the repository from database before updating it (else it would // override changes that were done earlier with sql) - if repo, err = GetRepositoryById(repo.Id); err != nil { + if repo, err = getRepositoryById(e, repo.Id); err != nil { return err } repo.IsBare = true repo.DefaultBranch = "master" - return UpdateRepository(repo) + return updateRepository(e, repo) } // Apply changes and commit. @@ -518,12 +522,6 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror return nil, ErrRepoAlreadyExist } - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return nil, err - } - repo := &Repository{ OwnerId: u.Id, Owner: u, @@ -533,8 +531,13 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror IsPrivate: private, } + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return nil, err + } + if _, err = sess.Insert(repo); err != nil { - sess.Rollback() return nil, err } @@ -544,15 +547,12 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror // Give access to all members in owner team. if u.IsOrganization() { - if err = repo.RecalcAccessSess(); err != nil { - sess.Rollback() + if err = repo.recalculateAccesses(sess); err != nil { return nil, err } } - if _, err = sess.Exec( - "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { - sess.Rollback() + if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { return nil, err } @@ -561,63 +561,54 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror t.RepoIds += "$" + com.ToStr(repo.Id) + "|" t.NumRepos++ if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() return nil, err } } - if err = sess.Commit(); err != nil { - return nil, err - } - if u.IsOrganization() { - t, err := u.GetOwnerTeam() + t, err := u.getOwnerTeam(sess) if err != nil { - log.Error(4, "GetOwnerTeam: %v", err) - } else { - if err = t.GetMembers(); err != nil { - log.Error(4, "GetMembers: %v", err) - } else { - for _, u := range t.Members { - if err = WatchRepo(u.Id, repo.Id, true); err != nil { - log.Error(4, "WatchRepo2: %v", err) - } - } + return nil, fmt.Errorf("get owner team: %v", err) + } else if err = t.getMembers(sess); err != nil { + return nil, fmt.Errorf("get team members: %v", err) + } + + for _, u := range t.Members { + if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { + return nil, fmt.Errorf("watch repository: %v", err) } } } else { - if err = WatchRepo(u.Id, repo.Id, true); err != nil { - log.Error(4, "WatchRepo3: %v", err) + if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { + return nil, fmt.Errorf("watch repository 2: %v", err) } } - if err = NewRepoAction(u, repo); err != nil { - log.Error(4, "NewRepoAction: %v", err) + if err = newRepoAction(sess, u, repo); err != nil { + return nil, fmt.Errorf("new repository action: %v", err) } // No need for init mirror. - if mirror { - return repo, nil - } - - repoPath := RepoPath(u.Name, repo.Name) - if err = initRepository(repoPath, u, repo, initReadme, lang, license); err != nil { - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error(4, "initRepository: %v", err) - return nil, fmt.Errorf( - "delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2) + if !mirror { + repoPath := RepoPath(u.Name, repo.Name) + if err = initRepository(sess, repoPath, u, repo, initReadme, lang, license); err != nil { + if err2 := os.RemoveAll(repoPath); err2 != nil { + log.Error(4, "initRepository: %v", err) + return nil, fmt.Errorf( + "delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2) + } + return nil, fmt.Errorf("initRepository: %v", err) } - return nil, fmt.Errorf("initRepository: %v", err) - } - _, stderr, err := process.ExecDir(-1, - repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath), - "git", "update-server-info") - if err != nil { - return nil, errors.New("CreateRepository(git update-server-info): " + stderr) + _, stderr, err := process.ExecDir(-1, + repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath), + "git", "update-server-info") + if err != nil { + return nil, errors.New("CreateRepository(git update-server-info): " + stderr) + } } - return repo, nil + return repo, sess.Commit() } // CountRepositories returns number of repositories. @@ -668,7 +659,7 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } @@ -679,44 +670,28 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error { repo.OwnerId = newUser.Id repo.Owner = newUser if _, err := sess.Id(repo.Id).Update(repo); err != nil { - sess.Rollback() return err } // Update user repository number. if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", newUser.Id); err != nil { - sess.Rollback() return err - } - - if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?", owner.Id); err != nil { - sess.Rollback() + } else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?", owner.Id); err != nil { return err - } - - if err = repo.RecalcAccessSess(); err != nil { + } else if err = repo.recalculateAccesses(sess); err != nil { return err - } - - // Change repository directory name. - if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newUser.Name, repo.Name)); err != nil { - sess.Rollback() + } else if err = watchRepo(sess, newUser.Id, repo.Id, true); err != nil { return err - } - - if err = sess.Commit(); err != nil { + } else if err = transferRepoAction(sess, u, newUser, repo); err != nil { return err } - if err = WatchRepo(newUser.Id, repo.Id, true); err != nil { - log.Error(4, "WatchRepo", err) - } - - if err = TransferRepoAction(u, newUser, repo); err != nil { + // Change repository directory name. + if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newUser.Name, repo.Name)); err != nil { return err } - return nil + return sess.Commit() } // ChangeRepositoryName changes all corresponding setting from old repository name to new one. @@ -732,7 +707,7 @@ func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) return os.Rename(RepoPath(userName, oldRepoName), RepoPath(userName, newRepoName)) } -func UpdateRepository(repo *Repository) error { +func updateRepository(e Engine, repo *Repository) error { repo.LowerName = strings.ToLower(repo.Name) if len(repo.Description) > 255 { @@ -741,10 +716,14 @@ func UpdateRepository(repo *Repository) error { if len(repo.Website) > 255 { repo.Website = repo.Website[:255] } - _, err := x.Id(repo.Id).AllCols().Update(repo) + _, err := e.Id(repo.Id).AllCols().Update(repo) return err } +func UpdateRepository(repo *Repository) error { + return updateRepository(x, repo) +} + // DeleteRepository deletes a repository for a user or organization. func DeleteRepository(uid, repoId int64, userName string) error { repo := &Repository{Id: repoId, OwnerId: uid} @@ -898,10 +877,9 @@ func GetRepositoryByName(uid int64, repoName string) (*Repository, error) { return repo, err } -// GetRepositoryById returns the repository by given id if exists. -func GetRepositoryById(id int64) (*Repository, error) { +func getRepositoryById(e Engine, id int64) (*Repository, error) { repo := &Repository{} - has, err := x.Id(id).Get(repo) + has, err := e.Id(id).Get(repo) if err != nil { return nil, err } else if !has { @@ -910,6 +888,11 @@ func GetRepositoryById(id int64) (*Repository, error) { return repo, nil } +// GetRepositoryById returns the repository by given id if exists. +func GetRepositoryById(id int64) (*Repository, error) { + return getRepositoryById(x, id) +} + // GetRepositories returns a list of repositories of given user. func GetRepositories(uid int64, private bool) ([]*Repository, error) { repos := make([]*Repository, 0, 10) @@ -1096,38 +1079,43 @@ type Collaboration struct { } // Add collaborator and accompanying access -func (r *Repository) AddCollaborator(u *User) error { - collaboration := &Collaboration{RepoID: r.Id, UserID: u.Id} +func (repo *Repository) AddCollaborator(u *User) error { + collaboration := &Collaboration{ + RepoID: repo.Id, + UserID: u.Id, + } has, err := x.Get(collaboration) if err != nil { return err - } - if has { + } else if has { return nil } - if _, err = x.InsertOne(collaboration); err != nil { + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { return err } - if err = r.GetOwner(); err != nil { + if _, err = sess.InsertOne(collaboration); err != nil { + return err + } else if err = repo.recalculateAccesses(sess); err != nil { return err } - return r.RecalcAccessSess() + return sess.Commit() } -// GetCollaborators returns the collaborators for a repository -func (r *Repository) GetCollaborators() ([]*User, error) { +func (repo *Repository) getCollaborators(e Engine) ([]*User, error) { collaborations := make([]*Collaboration, 0) - if err := x.Find(&collaborations, &Collaboration{RepoID: r.Id}); err != nil { + if err := e.Find(&collaborations, &Collaboration{RepoID: repo.Id}); err != nil { return nil, err } users := make([]*User, len(collaborations)) for i, c := range collaborations { - user, err := GetUserById(c.UserID) + user, err := getUserById(e, c.UserID) if err != nil { return nil, err } @@ -1136,15 +1124,31 @@ func (r *Repository) GetCollaborators() ([]*User, error) { return users, nil } +// GetCollaborators returns the collaborators for a repository +func (repo *Repository) GetCollaborators() ([]*User, error) { + return repo.getCollaborators(x) +} + // Delete collaborator and accompanying access -func (r *Repository) DeleteCollaborator(u *User) error { - collaboration := &Collaboration{RepoID: r.Id, UserID: u.Id} +func (repo *Repository) DeleteCollaborator(u *User) (err error) { + collaboration := &Collaboration{ + RepoID: repo.Id, + UserID: u.Id, + } + + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return err + } - if has, err := x.Delete(collaboration); err != nil || has == 0 { + if has, err := sess.Delete(collaboration); err != nil || has == 0 { + return err + } else if err = repo.recalculateAccesses(sess); err != nil { return err } - return r.RecalcAccessSess() + return sess.Commit() } // __ __ __ .__ @@ -1193,25 +1197,28 @@ func WatchRepo(uid, repoId int64, watch bool) (err error) { return watchRepo(x, uid, repoId, watch) } -// GetWatchers returns all watchers of given repository. -func GetWatchers(rid int64) ([]*Watch, error) { +func getWatchers(e Engine, rid int64) ([]*Watch, error) { watches := make([]*Watch, 0, 10) - err := x.Find(&watches, &Watch{RepoId: rid}) + err := e.Find(&watches, &Watch{RepoId: rid}) return watches, err } -// NotifyWatchers creates batch of actions for every watcher. -func NotifyWatchers(act *Action) error { +// GetWatchers returns all watchers of given repository. +func GetWatchers(rid int64) ([]*Watch, error) { + return getWatchers(x, rid) +} + +func notifyWatchers(e Engine, act *Action) error { // Add feeds for user self and all watchers. - watches, err := GetWatchers(act.RepoId) + watches, err := getWatchers(e, act.RepoId) if err != nil { - return errors.New("repo.NotifyWatchers(get watches): " + err.Error()) + return fmt.Errorf("get watchers: %v", err) } // Add feed for actioner. act.UserId = act.ActUserId - if _, err = x.InsertOne(act); err != nil { - return errors.New("repo.NotifyWatchers(create action): " + err.Error()) + if _, err = e.InsertOne(act); err != nil { + return fmt.Errorf("insert new actioner: %v", err) } for i := range watches { @@ -1221,13 +1228,18 @@ func NotifyWatchers(act *Action) error { act.Id = 0 act.UserId = watches[i].UserId - if _, err = x.InsertOne(act); err != nil { - return errors.New("repo.NotifyWatchers(create action): " + err.Error()) + if _, err = e.InsertOne(act); err != nil { + return fmt.Errorf("insert new action: %v", err) } } return nil } +// NotifyWatchers creates batch of actions for every watcher. +func NotifyWatchers(act *Action) error { + return notifyWatchers(x, act) +} + // _________ __ // / _____// |______ _______ // \_____ \\ __\__ \\_ __ \ @@ -1296,12 +1308,6 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor } } - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return nil, err - } - repo := &Repository{ OwnerId: u.Id, Owner: u, @@ -1313,19 +1319,23 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor ForkId: oldRepo.Id, } + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return nil, err + } + if _, err = sess.Insert(repo); err != nil { - sess.Rollback() return nil, err } - if err = repo.RecalcAccessSess(); err != nil { + if err = repo.recalculateAccesses(sess); err != nil { return nil, err } + var t *Team // Owner team. - if _, err = sess.Exec( - "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { - sess.Rollback() + if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { return nil, err } @@ -1334,50 +1344,42 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor t.RepoIds += "$" + com.ToStr(repo.Id) + "|" t.NumRepos++ if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() return nil, err } } if u.IsOrganization() { - t, err := u.GetOwnerTeam() + t, err := u.getOwnerTeam(sess) if err != nil { - log.Error(4, "GetOwnerTeam: %v", err) + return nil, fmt.Errorf("get owner team: %v", err) } else { - if err = t.GetMembers(); err != nil { - log.Error(4, "GetMembers: %v", err) + if err = t.getMembers(sess); err != nil { + return nil, fmt.Errorf("get team members: %v", err) } else { for _, u := range t.Members { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { - log.Error(4, "WatchRepo2: %v", err) + return nil, fmt.Errorf("watch repository: %v", err) } } } } } else { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { - log.Error(4, "WatchRepo3: %v", err) + return nil, fmt.Errorf("watch repository 2: %v", err) } } - if err = NewRepoAction(u, repo); err != nil { - log.Error(4, "NewRepoAction: %v", err) + if err = newRepoAction(sess, u, repo); err != nil { + return nil, fmt.Errorf("new repository action: %v", err) } - if _, err = sess.Exec( - "UPDATE `repository` SET num_forks = num_forks + 1 WHERE id = ?", oldRepo.Id); err != nil { - sess.Rollback() + if _, err = sess.Exec("UPDATE `repository` SET num_forks = num_forks + 1 WHERE id = ?", oldRepo.Id); err != nil { return nil, err } oldRepoPath, err := oldRepo.RepoPath() if err != nil { - sess.Rollback() - return nil, fmt.Errorf("fail to get repo path(%s): %v", oldRepo.Name, err) - } - - if err = sess.Commit(); err != nil { - return nil, err + return nil, fmt.Errorf("get old repository path: %v", err) } repoPath := RepoPath(u.Name, repo.Name) @@ -1385,15 +1387,15 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name), "git", "clone", "--bare", oldRepoPath, repoPath) if err != nil { - return nil, errors.New("ForkRepository(git clone): " + stderr) + return nil, fmt.Errorf("git clone: %v", stderr) } _, stderr, err = process.ExecDir(-1, repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath), "git", "update-server-info") if err != nil { - return nil, errors.New("ForkRepository(git update-server-info): " + stderr) + return nil, fmt.Errorf("git update-server-info: %v", err) } - return repo, nil + return repo, sess.Commit() } diff --git a/models/user.go b/models/user.go index 7e3dc260..37e77dd3 100644 --- a/models/user.go +++ b/models/user.go @@ -521,10 +521,9 @@ func GetUserByKeyId(keyId int64) (*User, error) { return user, nil } -// GetUserById returns the user object by given ID if exists. -func GetUserById(id int64) (*User, error) { +func getUserById(e Engine, id int64) (*User, error) { u := new(User) - has, err := x.Id(id).Get(u) + has, err := e.Id(id).Get(u) if err != nil { return nil, err } else if !has { @@ -533,6 +532,11 @@ func GetUserById(id int64) (*User, error) { return u, nil } +// GetUserById returns the user object by given ID if exists. +func GetUserById(id int64) (*User, error) { + return getUserById(x, id) +} + // GetUserByName returns user by given name. func GetUserByName(name string) (*User, error) { if len(name) == 0 { diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 8465af83..ea41b0dd 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -28,7 +28,7 @@ func ApiRepoAssignment() macaron.Handler { err error ) - // Check if the user is the same as the repository owner + // Check if the user is the same as the repository owner. if ctx.IsSigned && u.LowerName == strings.ToLower(userName) { u = ctx.User } else { @@ -216,9 +216,9 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { u, err = models.GetUserByName(userName) if err != nil { if err == models.ErrUserNotExist { - ctx.Error(404) + ctx.Handle(404, "GetUserByName", err) } else { - ctx.JSON(500, &base.ApiJsonErr{"GetUserByName: " + err.Error(), base.DOC_URL}) + ctx.Handle(500, "GetUserByName", err) } return } @@ -229,20 +229,20 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { - ctx.Error(404) + ctx.Handle(404, "GetRepositoryByName", err) } else { - ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL}) + ctx.Handle(500, "GetRepositoryByName", err) } return } else if err = repo.GetOwner(); err != nil { - ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL}) + ctx.Handle(500, "GetOwner", err) return } if ctx.IsSigned { mode, err := models.AccessLevel(ctx.User, repo) if err != nil { - ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL}) + ctx.Handle(500, "AccessLevel", err) return } ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE @@ -252,7 +252,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { // Check access. if repo.IsPrivate && !ctx.Repo.IsOwner { - ctx.Error(404) + ctx.Handle(404, "no access right", err) return } ctx.Repo.HasAccess = true diff --git a/routers/repo/http.go b/routers/repo/http.go index a209c2b2..034b5a7b 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -288,7 +288,7 @@ func serviceRpc(rpc string, hr handler) { access := hasAccess(r, hr.Config, dir, rpc, true) if access == false { - renderACCESS_MODE_NONE(w) + renderNoAccess(w) return } @@ -515,7 +515,7 @@ func renderNotFound(w http.ResponseWriter) { w.Write([]byte("Not Found")) } -func renderACCESS_MODE_NONE(w http.ResponseWriter) { +func renderNoAccess(w http.ResponseWriter) { w.WriteHeader(http.StatusForbidden) w.Write([]byte("Forbidden")) } diff --git a/routers/user/home.go b/routers/user/home.go index ce82ae77..35407534 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -210,8 +210,11 @@ func Profile(ctx *middleware.Context) { if !ctx.IsSigned { continue } - if has, _ := models.HasAccess(ctx.User, &models.Repository{Id: act.RepoId, IsPrivate: true}, - models.ACCESS_MODE_READ); !has { + if has, _ := models.HasAccess(ctx.User, + &models.Repository{ + Id: act.RepoId, + IsPrivate: true, + }, models.ACCESS_MODE_READ); !has { continue } } -- cgit v1.2.3 From 6b7d35eade921058654207abf30bd718389d11f1 Mon Sep 17 00:00:00 2001 From: Unknwon Date: Fri, 13 Feb 2015 02:14:57 -0500 Subject: fix mirror issues uncaught #941 --- gogs.go | 2 +- models/repo.go | 115 ++++++++++++++++---------------------------- modules/middleware/repo.go | 7 ++- templates/.VERSION | 2 +- templates/org/home.tmpl | 2 +- templates/user/profile.tmpl | 2 +- 6 files changed, 50 insertions(+), 80 deletions(-) (limited to 'modules/middleware/repo.go') diff --git a/gogs.go b/gogs.go index eac59362..247bfbfb 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.5.13.0211 Beta" +const APP_VER = "0.5.14.0213 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/repo.go b/models/repo.go index 75e29b09..fd00823a 100644 --- a/models/repo.go +++ b/models/repo.go @@ -206,6 +206,11 @@ func (repo *Repository) RepoLink() (string, error) { return setting.AppSubUrl + "/" + repo.Owner.Name + "/" + repo.Name, nil } +func (repo *Repository) HasAccess(u *User) bool { + has, _ := HasAccess(u, repo, ACCESS_MODE_READ) + return has +} + func (repo *Repository) IsOwnedBy(u *User) bool { return repo.OwnerId == u.Id } @@ -539,10 +544,10 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror if _, err = sess.Insert(repo); err != nil { return nil, err + } else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { + return nil, err } - var t *Team // Owner team. - // TODO fix code for mirrors? // Give access to all members in owner team. @@ -550,22 +555,8 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror if err = repo.recalculateAccesses(sess); err != nil { return nil, err } - } - - if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { - return nil, err - } - - // Update owner team info and count. - if u.IsOrganization() { - t.RepoIds += "$" + com.ToStr(repo.Id) + "|" - t.NumRepos++ - if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - return nil, err - } - } - if u.IsOrganization() { + // Update owner team info and count. t, err := u.getOwnerTeam(sess) if err != nil { return nil, fmt.Errorf("get owner team: %v", err) @@ -578,6 +569,12 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror return nil, fmt.Errorf("watch repository: %v", err) } } + + t.RepoIds += "$" + com.ToStr(repo.Id) + "|" + t.NumRepos++ + if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { + return nil, err + } } else { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { return nil, fmt.Errorf("watch repository 2: %v", err) @@ -746,21 +743,11 @@ func DeleteRepository(uid, repoId int64, userName string) error { } sess := x.NewSession() - defer sess.Close() + defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } - if _, err = sess.Delete(&Repository{Id: repoId}); err != nil { - sess.Rollback() - return err - } - - // Delete all access. - if _, err := sess.Delete(&Access{RepoID: repo.Id}); err != nil { - sess.Rollback() - return err - } if org.IsOrganization() { idStr := "$" + com.ToStr(repoId) + "|" for _, t := range org.Teams { @@ -770,34 +757,26 @@ func DeleteRepository(uid, repoId int64, userName string) error { t.NumRepos-- t.RepoIds = strings.Replace(t.RepoIds, idStr, "", 1) if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() return err } } } - if _, err := sess.Delete(&Action{RepoId: repo.Id}); err != nil { - sess.Rollback() + if _, err = sess.Delete(&Repository{Id: repoId}); err != nil { return err - } - if _, err = sess.Delete(&Watch{RepoId: repoId}); err != nil { - sess.Rollback() + } else if _, err := sess.Delete(&Access{RepoID: repo.Id}); err != nil { return err - } - if _, err = sess.Delete(&Mirror{RepoId: repoId}); err != nil { - sess.Rollback() + } else if _, err := sess.Delete(&Action{RepoId: repo.Id}); err != nil { return err - } - if _, err = sess.Delete(&IssueUser{RepoId: repoId}); err != nil { - sess.Rollback() + } else if _, err = sess.Delete(&Watch{RepoId: repoId}); err != nil { return err - } - if _, err = sess.Delete(&Milestone{RepoId: repoId}); err != nil { - sess.Rollback() + } else if _, err = sess.Delete(&Mirror{RepoId: repoId}); err != nil { return err - } - if _, err = sess.Delete(&Release{RepoId: repoId}); err != nil { - sess.Rollback() + } else if _, err = sess.Delete(&IssueUser{RepoId: repoId}); err != nil { + return err + } else if _, err = sess.Delete(&Milestone{RepoId: repoId}); err != nil { + return err + } else if _, err = sess.Delete(&Release{RepoId: repoId}); err != nil { return err } @@ -805,29 +784,24 @@ func DeleteRepository(uid, repoId int64, userName string) error { if err = x.Iterate(&Issue{RepoId: repoId}, func(idx int, bean interface{}) error { issue := bean.(*Issue) if _, err = sess.Delete(&Comment{IssueId: issue.Id}); err != nil { - sess.Rollback() return err } return nil }); err != nil { - sess.Rollback() return err } if _, err = sess.Delete(&Issue{RepoId: repoId}); err != nil { - sess.Rollback() return err } if repo.IsFork { if _, err = sess.Exec("UPDATE `repository` SET num_forks = num_forks - 1 WHERE id = ?", repo.ForkId); err != nil { - sess.Rollback() return err } } if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?", uid); err != nil { - sess.Rollback() return err } @@ -839,6 +813,7 @@ func DeleteRepository(uid, repoId int64, userName string) error { log.Error(4, "Fail to add notice: %v", err) } } + return sess.Commit() } @@ -1331,38 +1306,30 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor if err = repo.recalculateAccesses(sess); err != nil { return nil, err - } - - var t *Team // Owner team. - - if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { + } else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { return nil, err } - // Update owner team info and count. - if u.IsOrganization() { - t.RepoIds += "$" + com.ToStr(repo.Id) + "|" - t.NumRepos++ - if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - return nil, err - } - } - if u.IsOrganization() { + // Update owner team info and count. t, err := u.getOwnerTeam(sess) if err != nil { return nil, fmt.Errorf("get owner team: %v", err) - } else { - if err = t.getMembers(sess); err != nil { - return nil, fmt.Errorf("get team members: %v", err) - } else { - for _, u := range t.Members { - if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { - return nil, fmt.Errorf("watch repository: %v", err) - } - } + } else if err = t.getMembers(sess); err != nil { + return nil, fmt.Errorf("get team members: %v", err) + } + + for _, u := range t.Members { + if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { + return nil, fmt.Errorf("watch repository: %v", err) } } + + t.RepoIds += "$" + com.ToStr(repo.Id) + "|" + t.NumRepos++ + if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { + return nil, err + } } else { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { return nil, fmt.Errorf("watch repository 2: %v", err) diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index ea41b0dd..bd298819 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -29,7 +29,7 @@ func ApiRepoAssignment() macaron.Handler { ) // Check if the user is the same as the repository owner. - if ctx.IsSigned && u.LowerName == strings.ToLower(userName) { + if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) { u = ctx.User } else { u, err = models.GetUserByName(userName) @@ -210,7 +210,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { } // Check if the user is the same as the repository owner - if ctx.IsSigned && u.LowerName == strings.ToLower(userName) { + if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) { u = ctx.User } else { u, err = models.GetUserByName(userName) @@ -248,6 +248,9 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER + if !ctx.Repo.IsTrueOwner && ctx.Repo.Owner.IsOrganization() { + ctx.Repo.IsTrueOwner = ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) + } } // Check access. diff --git a/templates/.VERSION b/templates/.VERSION index 2aad3653..3e22111f 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.5.13.0211 Beta \ No newline at end of file +0.5.14.0213 Beta \ No newline at end of file diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index bb160b57..4929a881 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -27,7 +27,7 @@
{{range .Repos}} - {{if .HasAccess $.SignedUser.Name}} + {{if .HasAccess $.SignedUser}}
  • {{.NumStars}}
  • diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 44c22123..fd33a406 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -74,7 +74,7 @@
    {{range .Repos}} - {{if or (not .IsPrivate) (.HasAccess $.SignedUserName)}} + {{if or (not .IsPrivate) (.HasAccess $.SignedUser)}}
    • {{.NumStars}}
    • -- cgit v1.2.3 From ed89b39984a9191380263eaf357c3a9c71770674 Mon Sep 17 00:00:00 2001 From: Peter Smit Date: Mon, 16 Feb 2015 12:51:56 +0200 Subject: Updating context and fixing permission issues The boolean flags in the repo context have been replaced with mode and two methods Also, the permissions have been brought more in line with https://help.github.com/articles/permission-levels-for-an-organization-repository/ , Admin Team members are able to change settings of their repositories. --- cmd/web.go | 4 ++-- modules/middleware/context.go | 55 +++++++++++++++++++++++++------------------ modules/middleware/repo.go | 47 +++++++++++++----------------------- routers/api/v1/repo_file.go | 2 +- routers/repo/issue.go | 14 +++++------ routers/repo/release.go | 10 ++++---- routers/repo/repo.go | 2 +- templates/repo/header.tmpl | 2 +- templates/repo/sidebar.tmpl | 2 +- templates/repo/toolbar.tmpl | 2 +- 10 files changed, 68 insertions(+), 72 deletions(-) (limited to 'modules/middleware/repo.go') diff --git a/cmd/web.go b/cmd/web.go index 3284acb9..8b3b03c4 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -319,7 +319,7 @@ func runWeb(ctx *cli.Context) { m.Get("/template/*", dev.TemplatePreview) } - reqTrueOwner := middleware.RequireTrueOwner() + reqAdmin := middleware.RequireAdmin() // Organization. m.Group("/org", func() { @@ -394,7 +394,7 @@ func runWeb(ctx *cli.Context) { m.Post("/:name", repo.GitHooksEditPost) }, middleware.GitHookService()) }) - }, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner) + }, reqSignIn, middleware.RepoAssignment(true), reqAdmin) m.Group("/:username/:reponame", func() { m.Get("/action/:action", repo.Action) diff --git a/modules/middleware/context.go b/modules/middleware/context.go index 28be3a30..a2661096 100644 --- a/modules/middleware/context.go +++ b/modules/middleware/context.go @@ -38,29 +38,7 @@ type Context struct { IsSigned bool IsBasicAuth bool - Repo struct { - IsOwner bool - IsTrueOwner bool - IsWatching bool - IsBranch bool - IsTag bool - IsCommit bool - IsAdmin bool // Current user is admin level. - HasAccess bool - Repository *models.Repository - Owner *models.User - Commit *git.Commit - Tag *git.Tag - GitRepo *git.Repository - BranchName string - TagName string - TreeName string - CommitId string - RepoLink string - CloneLink models.CloneLink - CommitsCount int - Mirror *models.Mirror - } + Repo RepoContext Org struct { IsOwner bool @@ -73,6 +51,37 @@ type Context struct { } } +type RepoContext struct { + AccessMode models.AccessMode + IsWatching bool + IsBranch bool + IsTag bool + IsCommit bool + Repository *models.Repository + Owner *models.User + Commit *git.Commit + Tag *git.Tag + GitRepo *git.Repository + BranchName string + TagName string + TreeName string + CommitId string + RepoLink string + CloneLink models.CloneLink + CommitsCount int + Mirror *models.Mirror +} + +// Return if the current user has write access for this repository +func (r RepoContext) IsOwner() bool { + return r.AccessMode >= models.ACCESS_MODE_WRITE +} + +// Return if the current user has read access for this repository +func (r RepoContext) HasAccess() bool { + return r.AccessMode >= models.ACCESS_MODE_READ +} + // HasError returns true if error occurs in form validation. func (ctx *Context) HasApiError() bool { hasErr, ok := ctx.Data["HasError"] diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index bd298819..5c863dc0 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -58,24 +58,19 @@ func ApiRepoAssignment() macaron.Handler { return } - 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.ACCESS_MODE_WRITE - ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ - ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER + mode, err := models.AccessLevel(ctx.User, repo) + if err != nil { + ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL}) + return } + ctx.Repo.AccessMode = mode + // Check access. - if repo.IsPrivate && !ctx.Repo.IsOwner { + if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE { ctx.Error(404) return } - ctx.Repo.HasAccess = true ctx.Repo.Repository = repo } @@ -239,26 +234,18 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { return } - if ctx.IsSigned { - mode, err := models.AccessLevel(ctx.User, repo) - if err != nil { - ctx.Handle(500, "AccessLevel", err) - return - } - ctx.Repo.IsOwner = mode >= models.ACCESS_MODE_WRITE - ctx.Repo.IsAdmin = mode >= models.ACCESS_MODE_READ - ctx.Repo.IsTrueOwner = mode >= models.ACCESS_MODE_OWNER - if !ctx.Repo.IsTrueOwner && ctx.Repo.Owner.IsOrganization() { - ctx.Repo.IsTrueOwner = ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) - } + mode, err := models.AccessLevel(ctx.User, repo) + if err != nil { + ctx.Handle(500, "AccessLevel", err) + return } + ctx.Repo.AccessMode = mode // Check access. - if repo.IsPrivate && !ctx.Repo.IsOwner { + if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE { ctx.Handle(404, "no access right", err) return } - ctx.Repo.HasAccess = true ctx.Data["HasAccess"] = true @@ -306,8 +293,8 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { ctx.Data["Title"] = u.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner - ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner - ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner + ctx.Data["IsRepositoryOwner"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_WRITE + ctx.Data["IsRepositoryAdmin"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_ADMIN ctx.Data["DisableSSH"] = setting.DisableSSH ctx.Repo.CloneLink, err = repo.CloneLink() @@ -362,9 +349,9 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler { } } -func RequireTrueOwner() macaron.Handler { +func RequireAdmin() macaron.Handler { return func(ctx *Context) { - if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin { + if ctx.Repo.AccessMode < models.ACCESS_MODE_ADMIN { if !ctx.IsSigned { ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl) ctx.Redirect(setting.AppSubUrl + "/user/login") diff --git a/routers/api/v1/repo_file.go b/routers/api/v1/repo_file.go index a049904f..73f97b2c 100644 --- a/routers/api/v1/repo_file.go +++ b/routers/api/v1/repo_file.go @@ -12,7 +12,7 @@ import ( ) func GetRepoRawFile(ctx *middleware.Context) { - if ctx.Repo.Repository.IsPrivate && !ctx.Repo.HasAccess { + if !ctx.Repo.HasAccess() { ctx.Error(404) return } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index bf39d9ab..40e93389 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -230,7 +230,7 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { } // Only collaborators can assign. - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { form.AssigneeId = 0 } issue := &models.Issue{ @@ -434,7 +434,7 @@ func ViewIssue(ctx *middleware.Context) { ctx.Data["Title"] = issue.Name ctx.Data["Issue"] = issue ctx.Data["Comments"] = comments - ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id) + ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner() || (ctx.IsSigned && issue.PosterId == ctx.User.Id) ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false ctx.HTML(200, ISSUE_VIEW) @@ -457,7 +457,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) { return } - if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner { + if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner() { ctx.Error(403) return } @@ -484,7 +484,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) { } func UpdateIssueLabel(ctx *middleware.Context) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Error(403) return } @@ -560,7 +560,7 @@ func UpdateIssueLabel(ctx *middleware.Context) { } func UpdateIssueMilestone(ctx *middleware.Context) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Error(403) return } @@ -606,7 +606,7 @@ func UpdateIssueMilestone(ctx *middleware.Context) { } func UpdateAssignee(ctx *middleware.Context) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Error(403) return } @@ -752,7 +752,7 @@ func Comment(ctx *middleware.Context) { // Check if issue owner changes the status of issue. var newStatus string - if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id { + if ctx.Repo.IsOwner() || issue.PosterId == ctx.User.Id { newStatus = ctx.Query("change_status") } if len(newStatus) > 0 { diff --git a/routers/repo/release.go b/routers/repo/release.go index 591810cc..52d78b19 100644 --- a/routers/repo/release.go +++ b/routers/repo/release.go @@ -41,7 +41,7 @@ func Releases(ctx *middleware.Context) { tags := make([]*models.Release, len(rawTags)) for i, rawTag := range rawTags { for j, rel := range rels { - if rel == nil || (rel.IsDraft && !ctx.Repo.IsOwner) { + if rel == nil || (rel.IsDraft && !ctx.Repo.IsOwner()) { continue } if rel.TagName == rawTag { @@ -140,7 +140,7 @@ func Releases(ctx *middleware.Context) { } func NewRelease(ctx *middleware.Context) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Handle(403, "release.ReleasesNew", nil) return } @@ -153,7 +153,7 @@ func NewRelease(ctx *middleware.Context) { } func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Handle(403, "release.ReleasesNew", nil) return } @@ -211,7 +211,7 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) { } func EditRelease(ctx *middleware.Context) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Handle(403, "release.ReleasesEdit", nil) return } @@ -234,7 +234,7 @@ func EditRelease(ctx *middleware.Context) { } func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) { - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Handle(403, "release.EditReleasePost", nil) return } diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 48f7b09b..00537200 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -343,7 +343,7 @@ func Action(ctx *middleware.Context) { case "unstar": err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false) case "desc": - if !ctx.Repo.IsOwner { + if !ctx.Repo.IsOwner() { ctx.Error(404) return } diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index a0b927be..21f9cea8 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -49,7 +49,7 @@
    • - +
    - -->{{end}}{{if .IsRepositoryTrueOwner}} + -->{{end}}{{if .IsRepositoryAdmin}}
  • Settings
  • {{end}}
-- cgit v1.2.3