diff --git a/models/action.go b/models/action.go index 8ecdf1de..bbbe2134 100644 --- a/models/action.go +++ b/models/action.go @@ -182,14 +182,14 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, } // NewRepoAction adds new action for creating repository. -func NewRepoAction(user *User, repo *Repository) (err error) { - if err = NotifyWatchers(&Action{ActUserId: user.Id, ActUserName: user.Name, ActEmail: user.Email, +func NewRepoAction(u *User, repo *Repository) (err error) { + if err = NotifyWatchers(&Action{ActUserId: u.Id, ActUserName: u.Name, ActEmail: u.Email, OpType: OP_CREATE_REPO, RepoId: repo.Id, RepoName: repo.Name, IsPrivate: repo.IsPrivate}); err != nil { - log.Error("action.NewRepoAction(notify watchers): %d/%s", user.Id, repo.Name) + log.Error("action.NewRepoAction(notify watchers): %d/%s", u.Id, repo.Name) return err } - log.Trace("action.NewRepoAction: %s/%s", user.LowerName, repo.LowerName) + log.Trace("action.NewRepoAction: %s/%s", u.LowerName, repo.LowerName) return err } diff --git a/models/org.go b/models/org.go index 1cfe1798..227151ab 100644 --- a/models/org.go +++ b/models/org.go @@ -12,6 +12,8 @@ const ( ORG_ADMIN ) +const OWNER_TEAM = "Owner" + // Team represents a organization team. type Team struct { Id int64 @@ -19,6 +21,7 @@ type Team struct { Name string Description string Authorize AuthorizeType + RepoIds string `xorm:"TEXT"` NumMembers int NumRepos int } @@ -29,6 +32,15 @@ func NewTeam(t *Team) error { return err } +func UpdateTeam(t *Team) error { + if len(t.Description) > 255 { + t.Description = t.Description[:255] + } + + _, err := x.Id(t.Id).AllCols().Update(t) + return err +} + // ________ ____ ___ // \_____ \_______ ____ | | \______ ___________ // / | \_ __ \/ ___\| | / ___// __ \_ __ \ @@ -53,6 +65,13 @@ func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) { return ous, err } +// GetOrgUsersByOrgId returns all organization-user relations by organization ID. +func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) { + ous := make([]*OrgUser, 0, 10) + err := x.Where("org_id=?", orgId).Find(&ous) + return ous, err +} + // ___________ ____ ___ // \__ ___/___ _____ _____ | | \______ ___________ // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \ @@ -67,3 +86,21 @@ type TeamUser struct { OrgId int64 `xorm:"INDEX"` TeamId int64 } + +// GetTeamMembers returns all members in given team of organization. +func GetTeamMembers(orgId, teamId int64) ([]*User, error) { + tus := make([]*TeamUser, 0, 10) + err := x.Where("org_id=?", orgId).And("team_id=?", teamId).Find(&tus) + if err != nil { + return nil, err + } + + us := make([]*User, len(tus)) + for i, tu := range tus { + us[i], err = GetUserById(tu.Uid) + if err != nil { + return nil, err + } + } + return us, nil +} diff --git a/models/repo.go b/models/repo.go index f0e46c71..9cf90a94 100644 --- a/models/repo.go +++ b/models/repo.go @@ -454,21 +454,27 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep return initRepoCommit(tmpDir, user.NewGitSig()) } -// CreateRepository creates a repository for given user or orgnaziation. -func CreateRepository(user *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) { +// CreateRepository creates a repository for given user or organization. +func CreateRepository(u *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) { if !IsLegalName(name) { return nil, ErrRepoNameIllegal } - isExist, err := IsRepositoryExist(user, name) + isExist, err := IsRepositoryExist(u, name) if err != nil { return nil, err } else if isExist { return nil, ErrRepoAlreadyExist } + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return nil, err + } + repo := &Repository{ - OwnerId: user.Id, + OwnerId: u.Id, Name: name, LowerName: strings.ToLower(name), Description: desc, @@ -479,69 +485,85 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir repo.DefaultBranch = "master" } - repoPath := RepoPath(user.Name, repo.Name) - - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return nil, err - } - if _, err = sess.Insert(repo); err != nil { - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(repo): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(1): %v", user.Name, repo.Name, err2)) - } sess.Rollback() return nil, err } + var t *Team // Owner team. + mode := WRITABLE if mirror { mode = READABLE } - access := Access{ - UserName: user.LowerName, - RepoName: strings.ToLower(path.Join(user.Name, repo.Name)), + access := &Access{ + UserName: u.LowerName, + RepoName: strings.ToLower(path.Join(u.Name, repo.Name)), Mode: mode, } - if _, err = sess.Insert(&access); err != nil { - sess.Rollback() - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(access): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(2): %v", user.Name, repo.Name, err2)) + // Give access to all members in owner team. + if u.IsOrganization() { + t, err = u.GetOwnerTeam() + if err != nil { + sess.Rollback() + return nil, err + } + us, err := GetTeamMembers(u.Id, t.Id) + if err != nil { + sess.Rollback() + return nil, err + } + for _, u := range us { + 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 } - return nil, err } rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, user.Id); err != nil { + if _, err = sess.Exec(rawSql, u.Id); err != nil { sess.Rollback() - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(repo count): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2)) - } return nil, err } + // Update owner team info and count. + if u.IsOrganization() { + t.RepoIds += "$" + base.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 { - sess.Rollback() - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(commit): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2)) - } return nil, err } - if err = WatchRepo(user.Id, repo.Id, true); err != nil { - log.Error("repo.CreateRepository(WatchRepo): %v", err) + if u.IsOrganization() { + ous, err := GetOrgUsersByOrgId(u.Id) + if err != nil { + log.Error("repo.CreateRepository(GetOrgUsersByOrgId): %v", err) + } else { + for _, ou := range ous { + if err = WatchRepo(ou.Uid, repo.Id, true); err != nil { + log.Error("repo.CreateRepository(WatchRepo): %v", err) + } + } + } + } + if err = WatchRepo(u.Id, repo.Id, true); err != nil { + log.Error("repo.CreateRepository(WatchRepo2): %v", err) } - if err = NewRepoAction(user, repo); err != nil { + if err = NewRepoAction(u, repo); err != nil { log.Error("repo.CreateRepository(NewRepoAction): %v", err) } @@ -550,7 +572,13 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir return repo, nil } - if err = initRepository(repoPath, user, repo, initReadme, lang, license); err != 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("repo.CreateRepository(initRepository): %v", err) + return nil, errors.New(fmt.Sprintf( + "delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)) + } return nil, err } diff --git a/models/user.go b/models/user.go index 2388be9a..f67911ca 100644 --- a/models/user.go +++ b/models/user.go @@ -123,11 +123,14 @@ func (u *User) GetOrganizations() error { return nil } -// Member represents user is member of organization. -type Member struct { - Id int64 - OrgId int64 `xorm:"unique(member) index"` - UserId int64 `xorm:"unique(member)"` +// GetOwnerTeam returns owner team of organization. +func (org *User) GetOwnerTeam() (*Team, error) { + t := &Team{ + OrgId: org.Id, + Name: OWNER_TEAM, + } + _, err := x.Get(t) + return t, err } // IsUserExist checks if given user name exist, @@ -249,7 +252,7 @@ func CreateOrganization(org, owner *User) (*User, error) { // Create default owner team. t := &Team{ OrgId: org.Id, - Name: "Owner", + Name: OWNER_TEAM, Authorize: ORG_ADMIN, NumMembers: 1, } diff --git a/modules/auth/repo.go b/modules/auth/repo.go index 92ba64a2..999f33fe 100644 --- a/modules/auth/repo.go +++ b/modules/auth/repo.go @@ -22,9 +22,10 @@ import ( // \/ \/|__| \/ \/ type CreateRepoForm struct { + Uid int64 `form:"uid" binding:"Required"` RepoName string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"` Private bool `form:"private"` - Description string `form:"desc" binding:"MaxSize(100)"` + Description string `form:"desc" binding:"MaxSize(255)"` Language string `form:"language"` License string `form:"license"` InitReadme bool `form:"initReadme"` @@ -50,7 +51,7 @@ type MigrateRepoForm struct { RepoName string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"` Mirror bool `form:"mirror"` Private bool `form:"private"` - Description string `form:"desc" binding:"MaxSize(100)"` + Description string `form:"desc" binding:"MaxSize(255)"` } func (f *MigrateRepoForm) Name(field string) string { diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 6d241699..d9645642 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -63,11 +63,26 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { return } - repo, err := models.CreateRepository(ctx.User, form.RepoName, form.Description, + u := ctx.User + // Not equal means current user is an organization. + if u.Id != form.Uid { + var err error + u, err = models.GetUserById(form.Uid) + if err != nil { + if err == models.ErrUserNotExist { + ctx.Handle(404, "home.Dashboard(GetUserById)", err) + } else { + ctx.Handle(500, "home.Dashboard(GetUserById)", err) + } + return + } + } + + repo, err := models.CreateRepository(u, form.RepoName, form.Description, form.Language, form.License, form.Private, false, form.InitReadme) if err == nil { - log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName) - ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName) + log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName) + ctx.Redirect("/" + u.Name + "/" + form.RepoName) return } else if err == models.ErrRepoAlreadyExist { ctx.RenderWithErr("Repository name has already been used", CREATE, &form) @@ -78,7 +93,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { } if repo != nil { - if errDelete := models.DeleteRepository(ctx.User.Id, repo.Id, ctx.User.Name); errDelete != nil { + if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil { log.Error("repo.CreatePost(DeleteRepository): %v", errDelete) } } diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index 0eee1e57..38b32a3b 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -38,12 +38,7 @@ - - - +