diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/access.go | 9 | ||||
-rw-r--r-- | models/action.go | 95 | ||||
-rw-r--r-- | models/git_diff.go | 8 | ||||
-rw-r--r-- | models/issue.go | 47 | ||||
-rw-r--r-- | models/migrations/migrations.go | 152 | ||||
-rw-r--r-- | models/models.go | 22 | ||||
-rw-r--r-- | models/org.go | 55 | ||||
-rw-r--r-- | models/publickey.go | 4 | ||||
-rw-r--r-- | models/repo.go | 176 | ||||
-rw-r--r-- | models/user.go | 3 | ||||
-rw-r--r-- | models/webhook.go | 14 |
11 files changed, 355 insertions, 230 deletions
diff --git a/models/access.go b/models/access.go index 916711f786..174aca987f 100644 --- a/models/access.go +++ b/models/access.go @@ -4,10 +4,6 @@ package models -//import ( -// "github.com/go-xorm/xorm" -//) - type AccessMode int const ( @@ -81,9 +77,10 @@ func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { if err != nil { return nil, err } - err = repo.GetOwner() - if err != nil { + if err = repo.GetOwner(); err != nil { return nil, err + } else if repo.OwnerId == u.Id { + continue } repos[repo] = access.Mode } diff --git a/models/action.go b/models/action.go index 318a5f6ad4..5cba2f515a 100644 --- a/models/action.go +++ b/models/action.go @@ -41,14 +41,21 @@ var ( var ( // Same as Github. See https://help.github.com/articles/closing-issues-via-commit-messages - IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"} - IssueCloseKeywordsPat *regexp.Regexp - IssueReferenceKeywordsPat *regexp.Regexp + IssueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"} + IssueReopenKeywords = []string{"reopen", "reopens", "reopened"} + + IssueCloseKeywordsPat, IssueReopenKeywordsPat *regexp.Regexp + IssueReferenceKeywordsPat *regexp.Regexp ) +func assembleKeywordsPattern(words []string) string { + return fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(words, "|")) +} + func init() { - IssueCloseKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:%s) \S+`, strings.Join(IssueCloseKeywords, "|"))) - IssueReferenceKeywordsPat = regexp.MustCompile(fmt.Sprintf(`(?i)(?:) \S+`)) + IssueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueCloseKeywords)) + IssueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(IssueReopenKeywords)) + IssueReferenceKeywordsPat = regexp.MustCompile(`(?i)(?:)(^| )\S+`) } // Action represents user operation type and other information to repository., @@ -91,7 +98,7 @@ func (a Action) GetRepoName() string { } func (a Action) GetRepoLink() string { - return path.Join(a.RepoUserName, a.RepoName) + return path.Join(setting.AppSubUrl, a.RepoUserName, a.RepoName) } func (a Action) GetBranch() string { @@ -112,13 +119,11 @@ func (a Action) GetIssueInfos() []string { func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, commits []*base.PushCommit) error { for _, c := range commits { - references := IssueReferenceKeywordsPat.FindAllString(c.Message, -1) - - for _, ref := range references { + for _, ref := range IssueReferenceKeywordsPat.FindAllString(c.Message, -1) { ref := ref[strings.IndexByte(ref, byte(' '))+1:] ref = strings.TrimRightFunc(ref, func(c rune) bool { - return !unicode.IsDigit(c) - }) + return !unicode.IsDigit(c) + }) if len(ref) == 0 { continue @@ -128,33 +133,29 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com if ref[0] == '#' { ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref) } else if strings.Contains(ref, "/") == false { - // We don't support User#ID syntax yet + // FIXME: We don't support User#ID syntax yet // return ErrNotImplemented continue } issue, err := GetIssueByRef(ref) - if err != nil { return err } url := fmt.Sprintf("%s/%s/%s/commit/%s", setting.AppSubUrl, repoUserName, repoName, c.Sha1) message := fmt.Sprintf(`<a href="%s">%s</a>`, url, c.Message) - - if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMIT, message, nil); err != nil { + if _, err = CreateComment(userId, issue.RepoId, issue.Id, 0, 0, COMMENT_TYPE_COMMIT, message, nil); err != nil { return err } } - closes := IssueCloseKeywordsPat.FindAllString(c.Message, -1) - - for _, ref := range closes { + for _, ref := range IssueCloseKeywordsPat.FindAllString(c.Message, -1) { ref := ref[strings.IndexByte(ref, byte(' '))+1:] ref = strings.TrimRightFunc(ref, func(c rune) bool { - return !unicode.IsDigit(c) - }) + return !unicode.IsDigit(c) + }) if len(ref) == 0 { continue @@ -171,7 +172,6 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com } issue, err := GetIssueByRef(ref) - if err != nil { return err } @@ -180,7 +180,6 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com if issue.IsClosed { continue } - issue.IsClosed = true if err = UpdateIssue(issue); err != nil { @@ -194,14 +193,60 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com } // If commit happened in the referenced repository, it means the issue can be closed. - if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, CLOSE, "", nil); err != nil { + if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, COMMENT_TYPE_CLOSE, "", nil); err != nil { return err } } } - - } + for _, ref := range IssueReopenKeywordsPat.FindAllString(c.Message, -1) { + ref := ref[strings.IndexByte(ref, byte(' '))+1:] + ref = strings.TrimRightFunc(ref, func(c rune) bool { + return !unicode.IsDigit(c) + }) + + if len(ref) == 0 { + continue + } + + // Add repo name if missing + if ref[0] == '#' { + ref = fmt.Sprintf("%s/%s%s", repoUserName, repoName, ref) + } else if strings.Contains(ref, "/") == false { + // We don't support User#ID syntax yet + // return ErrNotImplemented + + continue + } + + issue, err := GetIssueByRef(ref) + if err != nil { + return err + } + + if issue.RepoId == repoId { + if !issue.IsClosed { + continue + } + issue.IsClosed = false + + if err = UpdateIssue(issue); err != nil { + return err + } else if err = UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil { + return err + } + + if err = ChangeMilestoneIssueStats(issue); err != nil { + return err + } + + // If commit happened in the referenced repository, it means the issue can be closed. + if _, err = CreateComment(userId, repoId, issue.Id, 0, 0, COMMENT_TYPE_REOPEN, "", nil); err != nil { + return err + } + } + } + } return nil } diff --git a/models/git_diff.go b/models/git_diff.go index 7e91626f1d..9d34ed6271 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -60,6 +60,8 @@ type DiffFile struct { Index int Addition, Deletion int Type int + IsCreated bool + IsDeleted bool IsBin bool Sections []*DiffSection } @@ -181,10 +183,16 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff switch { case strings.HasPrefix(scanner.Text(), "new file"): curFile.Type = DIFF_FILE_ADD + curFile.IsDeleted = false + curFile.IsCreated = true case strings.HasPrefix(scanner.Text(), "deleted"): curFile.Type = DIFF_FILE_DEL + curFile.IsCreated = false + curFile.IsDeleted = true case strings.HasPrefix(scanner.Text(), "index"): curFile.Type = DIFF_FILE_CHANGE + curFile.IsCreated = false + curFile.IsDeleted = false } if curFile.Type > 0 { break diff --git a/models/issue.go b/models/issue.go index 8d0525d7c5..3cd71d8aa4 100644 --- a/models/issue.go +++ b/models/issue.go @@ -282,30 +282,33 @@ type IssueUser struct { } // NewIssueUserPairs adds new issue-user pairs for new issue of repository. -func NewIssueUserPairs(repo *Repository, iid, oid, pid, aid int64) (err error) { - iu := &IssueUser{IssueId: iid, RepoId: repo.Id} - - us, err := repo.GetCollaborators() +func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) (err error) { + users, err := repo.GetCollaborators() if err != nil { return err } + iu := &IssueUser{ + IssueId: issueID, + RepoId: repo.Id, + } + isNeedAddPoster := true - for _, u := range us { + for _, u := range users { iu.Uid = u.Id - iu.IsPoster = iu.Uid == pid + iu.IsPoster = iu.Uid == posterID if isNeedAddPoster && iu.IsPoster { isNeedAddPoster = false } - iu.IsAssigned = iu.Uid == aid + iu.IsAssigned = iu.Uid == assigneeID if _, err = x.Insert(iu); err != nil { return err } } if isNeedAddPoster { - iu.Uid = pid + iu.Uid = posterID iu.IsPoster = true - iu.IsAssigned = iu.Uid == aid + iu.IsAssigned = iu.Uid == assigneeID if _, err = x.Insert(iu); err != nil { return err } @@ -859,22 +862,16 @@ type CommentType int const ( // Plain comment, can be associated with a commit (CommitId > 0) and a line (Line > 0) - COMMENT CommentType = iota - - // Reopen action - REOPEN - - // Close action - CLOSE - - // Reference from another issue - ISSUE + COMMENT_TYPE_COMMENT CommentType = iota + COMMENT_TYPE_REOPEN + COMMENT_TYPE_CLOSE + // References. + COMMENT_TYPE_ISSUE // Reference from some commit (not part of a pull request) - COMMIT - + COMMENT_TYPE_COMMIT // Reference from some pull request - PULL + COMMENT_TYPE_PULL ) // Comment represents a comment in commit and issue page. @@ -908,7 +905,7 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen // Check comment type. switch cmtType { - case COMMENT: + case COMMENT_TYPE_COMMENT: rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?" if _, err := sess.Exec(rawSql, issueId); err != nil { sess.Rollback() @@ -929,13 +926,13 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType Commen return nil, err } } - case REOPEN: + case COMMENT_TYPE_REOPEN: rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?" if _, err := sess.Exec(rawSql, repoId); err != nil { sess.Rollback() return nil, err } - case CLOSE: + case COMMENT_TYPE_CLOSE: rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?" if _, err := sess.Exec(rawSql, repoId); err != nil { sess.Rollback() diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 37986b68bd..1510bafdb6 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -1,15 +1,44 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + package migrations import ( - "errors" - "strconv" + "fmt" "strings" "time" + "github.com/Unknwon/com" "github.com/go-xorm/xorm" + + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/setting" ) -type migration func(*xorm.Engine) error +const _MIN_DB_VER = 0 + +type Migration interface { + Description() string + Migrate(*xorm.Engine) error +} + +type migration struct { + description string + migrate func(*xorm.Engine) error +} + +func NewMigration(desc string, fn func(*xorm.Engine) error) Migration { + return &migration{desc, fn} +} + +func (m *migration) Description() string { + return m.description +} + +func (m *migration) Migrate(x *xorm.Engine) error { + return m.migrate(x) +} // The version table. Should have only one row with id==1 type Version struct { @@ -18,23 +47,26 @@ 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, replace it with "expiredMigration" -var migrations = []migration{ - accessToCollaboration, - accessRefactor, +// 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 func Migrate(x *xorm.Engine) error { if err := x.Sync(new(Version)); err != nil { - return err + return fmt.Errorf("sync: %v", err) } currentVersion := &Version{Id: 1} has, err := x.Get(currentVersion) if err != nil { - return err + return fmt.Errorf("get: %v", err) } else if !has { + // If the user table does not exist it is a fresh installation and we + // can skip all migrations needsMigration, err := x.IsTableExist("user") if err != nil { return err @@ -44,22 +76,24 @@ func Migrate(x *xorm.Engine) error { if err != nil { return err } + // If the user table is empty it is a fresh installation and we can + // skip all migrations needsMigration = !isEmpty } if !needsMigration { - currentVersion.Version = int64(len(migrations)) + currentVersion.Version = int64(_MIN_DB_VER + len(migrations)) } if _, err = x.InsertOne(currentVersion); err != nil { - return err + return fmt.Errorf("insert: %v", err) } } v := currentVersion.Version - - for i, migration := range migrations[v:] { - if err = migration(x); err != nil { - return err + for i, m := range migrations[v-_MIN_DB_VER:] { + log.Info("Migration: %s", m.Description()) + if err = m.Migrate(x); err != nil { + return fmt.Errorf("do migrate: %v", err) } currentVersion.Version = v + int64(i) + 1 if _, err = x.Id(1).Update(currentVersion); err != nil { @@ -69,52 +103,59 @@ func Migrate(x *xorm.Engine) error { return nil } -func expiredMigration(x *xorm.Engine) error { - return errors.New("You are migrating from a too old gogs version") -} - -func mustParseInt64(in []byte) int64 { - i, err := strconv.ParseInt(string(in), 10, 64) - if err != nil { - i = 0 - } - return i -} - func accessToCollaboration(x *xorm.Engine) error { type Collaboration struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - Created time.Time `xorm:"CREATED"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + Created time.Time } x.Sync(new(Collaboration)) - sql := `SELECT u.id AS uid, a.repo_name AS repo, a.mode AS mode, a.created as created FROM access a JOIN user u ON a.user_name=u.lower_name` - results, err := x.Query(sql) + results, err := x.Query("SELECT u.id AS `uid`, a.repo_name AS `repo`, a.mode AS `mode`, a.created as `created` FROM `access` a JOIN `user` u ON a.user_name=u.lower_name") if err != nil { return err } - for _, result := range results { - userID := mustParseInt64(result["uid"]) - repoRefName := string(result["repo"]) - mode := mustParseInt64(result["mode"]) - created := result["created"] + sess := x.NewSession() + defer func() { + if sess.IsCommitedOrRollbacked { + sess.Rollback() + } + sess.Close() + }() + if err = sess.Begin(); err != nil { + return err + } - //Collaborators must have write access + offset := strings.Split(time.Now().String(), " ")[2] + for _, result := range results { + mode := com.StrTo(result["mode"]).MustInt64() + // Collaborators must have write access. if mode < 2 { continue } + userID := com.StrTo(result["uid"]).MustInt64() + repoRefName := string(result["repo"]) + + var created time.Time + switch { + case setting.UseSQLite3: + created, _ = time.Parse(time.RFC3339, string(result["created"])) + case setting.UseMySQL: + created, _ = time.Parse("2006-01-02 15:04:05-0700", string(result["created"])+offset) + case setting.UsePostgreSQL: + created, _ = time.Parse("2006-01-02T15:04:05Z-0700", string(result["created"])+offset) + } + // find owner of repository parts := strings.SplitN(repoRefName, "/", 2) ownerName := parts[0] repoName := parts[1] - sql = `SELECT u.id as uid, ou.uid as memberid FROM user u LEFT JOIN org_user ou ON ou.org_id=u.id WHERE u.lower_name=?` - results, err := x.Query(sql, ownerName) + results, err := sess.Query("SELECT u.id as `uid`, ou.uid as `memberid` FROM `user` u LEFT JOIN org_user ou ON ou.org_id=u.id WHERE u.lower_name=?", ownerName) if err != nil { return err } @@ -122,7 +163,7 @@ func accessToCollaboration(x *xorm.Engine) error { continue } - ownerID := mustParseInt64(results[0]["uid"]) + ownerID := com.StrTo(results[0]["uid"]).MustInt64() if ownerID == userID { continue } @@ -130,7 +171,7 @@ func accessToCollaboration(x *xorm.Engine) error { // test if user is member of owning organization isMember := false for _, member := range results { - memberID := mustParseInt64(member["memberid"]) + memberID := com.StrTo(member["memberid"]).MustInt64() // We can skip all cases that a user is member of the owning organization if memberID == userID { isMember = true @@ -140,24 +181,31 @@ func accessToCollaboration(x *xorm.Engine) error { continue } - sql = `SELECT id FROM repository WHERE owner_id=? AND lower_name=?` - results, err = x.Query(sql, ownerID, repoName) + results, err = sess.Query("SELECT id FROM `repository` WHERE owner_id=? AND lower_name=?", ownerID, repoName) if err != nil { return err - } - if len(results) < 1 { + } else if len(results) < 1 { continue } - repoID := results[0]["id"] - - sql = `INSERT INTO collaboration (user_id, repo_id, created) VALUES (?,?,?)` - _, err = x.Exec(sql, userID, repoID, created) + collaboration := &Collaboration{ + UserID: userID, + RepoID: com.StrTo(results[0]["id"]).MustInt64(), + } + has, err := sess.Get(collaboration) if err != nil { return err + } else if has { + continue + } + + collaboration.Created = created + if _, err = sess.InsertOne(collaboration); err != nil { + return err } } - return nil + + return sess.Commit() } func accessRefactor(x *xorm.Engine) error { diff --git a/models/models.go b/models/models.go index 1a67041b4a..141e3ac497 100644 --- a/models/models.go +++ b/models/models.go @@ -24,7 +24,10 @@ import ( type Engine interface { Delete(interface{}) (int64, error) Exec(string, ...interface{}) (sql.Result, error) + Get(interface{}) (bool, error) Insert(...interface{}) (int64, error) + Id(interface{}) *xorm.Session + Where(string, ...interface{}) *xorm.Session } var ( @@ -37,24 +40,29 @@ var ( } EnableSQLite3 bool - UseSQLite3 bool ) func init() { tables = append(tables, - new(User), new(PublicKey), new(Follow), new(Oauth2), new(AccessToken), - new(Repository), new(Watch), new(Star), new(Action), new(Access), + new(User), new(PublicKey), new(Oauth2), new(AccessToken), + new(Repository), new(Collaboration), new(Access), + new(Watch), new(Star), new(Follow), new(Action), new(Issue), new(Comment), new(Attachment), new(IssueUser), new(Label), new(Milestone), new(Mirror), new(Release), new(LoginSource), new(Webhook), new(UpdateTask), new(HookTask), new(Team), new(OrgUser), new(TeamUser), - new(Notice), new(EmailAddress), new(Collaboration)) + new(Notice), new(EmailAddress)) } func LoadModelsConfig() { sec := setting.Cfg.Section("database") DbCfg.Type = sec.Key("DB_TYPE").String() - if DbCfg.Type == "sqlite3" { - UseSQLite3 = true + switch DbCfg.Type { + case "sqlite3": + setting.UseSQLite3 = true + case "mysql": + setting.UseMySQL = true + case "postgres": + setting.UsePostgreSQL = true } DbCfg.Host = sec.Key("HOST").String() DbCfg.Name = sec.Key("NAME").String() @@ -138,7 +146,7 @@ func NewEngine() (err error) { } if err = migrations.Migrate(x); err != nil { - return err + return fmt.Errorf("migrate: %v", err) } if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil { diff --git a/models/org.go b/models/org.go index f6d472a6d9..d667fb26dc 100644 --- a/models/org.go +++ b/models/org.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/Unknwon/com" - "github.com/go-xorm/xorm" "github.com/gogits/gogs/modules/base" ) @@ -389,7 +388,7 @@ func RemoveOrgUser(orgId, uid int64) error { return err } for _, t := range ts { - if err = removeTeamMemberWithSess(org.Id, t.Id, u.Id, sess); err != nil { + if err = removeTeamMember(sess, org.Id, t.Id, u.Id); err != nil { return err } } @@ -617,10 +616,9 @@ func GetTeam(orgId int64, name string) (*Team, error) { return t, nil } -// GetTeamById returns team by given ID. -func GetTeamById(teamId int64) (*Team, error) { +func getTeamById(e Engine, teamId int64) (*Team, error) { t := new(Team) - has, err := x.Id(teamId).Get(t) + has, err := e.Id(teamId).Get(t) if err != nil { return nil, err } else if !has { @@ -629,6 +627,11 @@ func GetTeamById(teamId int64) (*Team, error) { return t, nil } +// GetTeamById returns team by given ID. +func GetTeamById(teamId int64) (*Team, error) { + return getTeamById(x, teamId) +} + // UpdateTeam updates information of team. func UpdateTeam(t *Team, authChanged bool) (err error) { if !IsLegalName(t.Name) { @@ -729,10 +732,14 @@ type TeamUser struct { TeamId int64 } +func isTeamMember(e Engine, orgId, teamId, uid int64) bool { + has, _ := e.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser)) + return has +} + // IsTeamMember returns true if given user is a member of team. func IsTeamMember(orgId, teamId, uid int64) bool { - has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser)) - return has + return isTeamMember(x, orgId, teamId, uid) } // GetTeamMembers returns all members in given team of organization. @@ -742,17 +749,16 @@ func GetTeamMembers(orgId, teamId int64) ([]*User, error) { return us, err } -// GetUserTeams returns all teams that user belongs to in given organization. -func GetUserTeams(orgId, uid int64) ([]*Team, error) { +func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) { tus := make([]*TeamUser, 0, 5) - if err := x.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil { + if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil { return nil, err } ts := make([]*Team, len(tus)) for i, tu := range tus { t := new(Team) - has, err := x.Id(tu.TeamId).Get(t) + has, err := e.Id(tu.TeamId).Get(t) if err != nil { return nil, err } else if !has { @@ -763,6 +769,11 @@ func GetUserTeams(orgId, uid int64) ([]*Team, error) { return ts, nil } +// GetUserTeams returns all teams that user belongs to in given organization. +func GetUserTeams(orgId, uid int64) ([]*Team, error) { + return getUserTeams(x, orgId, uid) +} + // AddTeamMember adds new member to given team of given organization. func AddTeamMember(orgId, teamId, uid int64) error { if IsTeamMember(orgId, teamId, uid) { @@ -831,13 +842,13 @@ func AddTeamMember(orgId, teamId, uid int64) error { return sess.Commit() } -func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) error { - if !IsTeamMember(orgId, teamId, uid) { +func removeTeamMember(e Engine, orgId, teamId, uid int64) error { + if !isTeamMember(e, orgId, teamId, uid) { return nil } // Get team and its repositories. - t, err := GetTeamById(teamId) + t, err := getTeamById(e, teamId) if err != nil { return err } @@ -865,35 +876,30 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro TeamId: teamId, } - if _, err := sess.Delete(tu); err != nil { - sess.Rollback() + if _, err := e.Delete(tu); err != nil { return err - } else if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { - sess.Rollback() + } else if _, err = e.Id(t.Id).AllCols().Update(t); err != nil { return err } // Delete access to team repositories. for _, repo := range t.Repos { if err = repo.RecalcAccessSess(); err != nil { - sess.Rollback() return err } } // This must exist. ou := new(OrgUser) - _, err = sess.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou) + _, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou) if err != nil { - sess.Rollback() return err } ou.NumTeams-- if t.IsOwnerTeam() { ou.IsOwner = false } - if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil { - sess.Rollback() + if _, err = e.Id(ou.Id).AllCols().Update(ou); err != nil { return err } return nil @@ -906,7 +912,8 @@ func RemoveTeamMember(orgId, teamId, uid int64) error { if err := sess.Begin(); err != nil { return err } - if err := removeTeamMemberWithSess(orgId, teamId, uid, sess); err != nil { + if err := removeTeamMember(sess, orgId, teamId, uid); err != nil { + sess.Rollback() return err } return sess.Commit() diff --git a/models/publickey.go b/models/publickey.go index 67ab4242f2..383b85b634 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -29,7 +29,7 @@ import ( const ( // "### autogenerated by gitgos, DO NOT EDIT\n" - _TPL_PUBLICK_KEY = `command="%s serv key-%d",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n" + _TPL_PUBLICK_KEY = `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n" ) var ( @@ -98,7 +98,7 @@ func (k *PublicKey) OmitEmail() string { // GetAuthorizedString generates and returns formatted public key string for authorized_keys file. func (key *PublicKey) GetAuthorizedString() string { - return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.Id, key.Content) + return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.Id, setting.CustomConf, key.Content) } var ( diff --git a/models/repo.go b/models/repo.go index 5943dd31ad..5a669d9dd8 100644 --- a/models/repo.go +++ b/models/repo.go @@ -30,7 +30,7 @@ import ( ) const ( - TPL_UPDATE_HOOK = "#!/usr/bin/env %s\n%s update $1 $2 $3\n" + _TPL_UPDATE_HOOK = "#!/usr/bin/env %s\n%s update $1 $2 $3 --config='%s'\n" ) var ( @@ -239,8 +239,8 @@ func (repo *Repository) CloneLink() (cl CloneLink, err error) { if err = repo.GetOwner(); err != nil { return cl, err } - if setting.SshPort != 22 { - cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, repo.Owner.LowerName, repo.LowerName) + if setting.SSHPort != 22 { + cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SSHPort, repo.Owner.LowerName, repo.LowerName) } else { cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, repo.Owner.LowerName, repo.LowerName) } @@ -349,13 +349,16 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str os.RemoveAll(repoPath) } - // this command could for both migrate and mirror + // FIXME: this command could for both migrate and mirror _, stderr, err := process.ExecTimeout(10*time.Minute, fmt.Sprintf("MigrateRepository: %s", repoPath), "git", "clone", "--mirror", "--bare", url, repoPath) if err != nil { - return repo, errors.New("git clone: " + stderr) + return repo, fmt.Errorf("git clone --mirror --bare: %v", stderr) + } else if err = createUpdateHook(repoPath); err != nil { + return repo, fmt.Errorf("create update hook: %v", err) } + return repo, UpdateRepository(repo) } @@ -394,15 +397,9 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { return nil } -func createHookUpdate(hookPath, content string) error { - pu, err := os.OpenFile(hookPath, os.O_CREATE|os.O_WRONLY, 0777) - if err != nil { - return err - } - defer pu.Close() - - _, err = pu.WriteString(content) - return err +func createUpdateHook(repoPath string) error { + return ioutil.WriteFile(path.Join(repoPath, "hooks/update"), + []byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+appPath+"\"", setting.CustomConf)), 0777) } // InitRepository initializes README and .gitignore if needed. @@ -414,9 +411,7 @@ func initRepository(f string, u *User, repo *Repository, initReadme bool, repoLa return err } - // hook/post-update - if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"), - fmt.Sprintf(TPL_UPDATE_HOOK, setting.ScriptType, "\""+appPath+"\"")); err != nil { + if err := createUpdateHook(repoPath); err != nil { return err } @@ -938,58 +933,6 @@ func GetRepositoryCount(user *User) (int64, error) { return x.Count(&Repository{OwnerId: user.Id}) } -// GetCollaborators returns the collaborators for a repository -func (r *Repository) GetCollaborators() ([]*User, error) { - collaborations := make([]*Collaboration, 0) - if err := x.Find(&collaborations, &Collaboration{RepoID: r.Id}); err != nil { - return nil, err - } - - users := make([]*User, len(collaborations)) - for i, c := range collaborations { - user, err := GetUserById(c.UserID) - if err != nil { - return nil, err - } - users[i] = user - } - return users, nil -} - -// 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 - } - if has { - return nil - } - - if _, err = x.InsertOne(collaboration); err != nil { - return err - } - - if err = r.GetOwner(); err != nil { - return err - } - - return r.RecalcAccessSess() -} - -// Delete collaborator and accompanying access -func (r *Repository) DeleteCollaborator(u *User) error { - collaboration := &Collaboration{RepoID: r.Id, UserID: u.Id} - - if has, err := x.Delete(collaboration); err != nil || has == 0 { - return err - } - - return r.RecalcAccessSess() -} - type SearchOption struct { Keyword string Uid int64 @@ -1030,6 +973,18 @@ func DeleteRepositoryArchives() error { }) } +// RewriteRepositoryUpdateHook rewrites all repositories' update hook. +func RewriteRepositoryUpdateHook() error { + return x.Where("id > 0").Iterate(new(Repository), + func(idx int, bean interface{}) error { + repo := bean.(*Repository) + if err := repo.GetOwner(); err != nil { + return err + } + return createUpdateHook(RepoPath(repo.Owner.Name, repo.Name)) + }) +} + var ( // Prevent duplicate tasks. isMirrorUpdating = false @@ -1125,6 +1080,73 @@ func GitGcRepos() error { }) } +// _________ .__ .__ ___. __ .__ +// \_ ___ \ ____ | | | | _____ \_ |__ ________________ _/ |_|__| ____ ____ +// / \ \/ / _ \| | | | \__ \ | __ \ / _ \_ __ \__ \\ __\ |/ _ \ / \ +// \ \___( <_> ) |_| |__/ __ \| \_\ ( <_> ) | \// __ \| | | ( <_> ) | \ +// \______ /\____/|____/____(____ /___ /\____/|__| (____ /__| |__|\____/|___| / +// \/ \/ \/ \/ \/ + +// A Collaboration is a relation between an individual and a repository +type Collaboration struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + Created time.Time `xorm:"CREATED"` +} + +// 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 + } + if has { + return nil + } + + if _, err = x.InsertOne(collaboration); err != nil { + return err + } + + if err = r.GetOwner(); err != nil { + return err + } + + return r.RecalcAccessSess() +} + +// GetCollaborators returns the collaborators for a repository +func (r *Repository) GetCollaborators() ([]*User, error) { + collaborations := make([]*Collaboration, 0) + if err := x.Find(&collaborations, &Collaboration{RepoID: r.Id}); err != nil { + return nil, err + } + + users := make([]*User, len(collaborations)) + for i, c := range collaborations { + user, err := GetUserById(c.UserID) + if err != nil { + return nil, err + } + users[i] = user + } + return users, nil +} + +// Delete collaborator and accompanying access +func (r *Repository) DeleteCollaborator(u *User) error { + collaboration := &Collaboration{RepoID: r.Id, UserID: u.Id} + + if has, err := x.Delete(collaboration); err != nil || has == 0 { + return err + } + + return r.RecalcAccessSess() +} + // __ __ __ .__ // / \ / \_____ _/ |_ ____ | |__ // \ \/\/ /\__ \\ __\/ ___\| | \ @@ -1145,7 +1167,7 @@ func IsWatching(uid, repoId int64) bool { return has } -func watchRepoWithEngine(e Engine, uid, repoId int64, watch bool) (err error) { +func watchRepo(e Engine, uid, repoId int64, watch bool) (err error) { if watch { if IsWatching(uid, repoId) { return nil @@ -1168,7 +1190,7 @@ func watchRepoWithEngine(e Engine, uid, repoId int64, watch bool) (err error) { // Watch or unwatch repository. func WatchRepo(uid, repoId int64, watch bool) (err error) { - return watchRepoWithEngine(x, uid, repoId, watch) + return watchRepo(x, uid, repoId, watch) } // GetWatchers returns all watchers of given repository. @@ -1326,14 +1348,14 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor log.Error(4, "GetMembers: %v", err) } else { for _, u := range t.Members { - if err = watchRepoWithEngine(sess, u.Id, repo.Id, true); err != nil { + if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { log.Error(4, "WatchRepo2: %v", err) } } } } } else { - if err = watchRepoWithEngine(sess, u.Id, repo.Id, true); err != nil { + if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { log.Error(4, "WatchRepo3: %v", err) } } @@ -1375,11 +1397,3 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor return repo, nil } - -// A Collaboration is a relation between an individual and a repository -type Collaboration struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - Created time.Time `xorm:"CREATED"` -} diff --git a/models/user.go b/models/user.go index b33e529aa6..7e3dc260e5 100644 --- a/models/user.go +++ b/models/user.go @@ -512,8 +512,7 @@ func UserPath(userName string) string { func GetUserByKeyId(keyId int64) (*User, error) { user := new(User) - rawSql := "SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?" - has, err := x.Sql(rawSql, keyId).Get(user) + has, err := x.Sql("SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?", keyId).Get(user) if err != nil { return nil, err } else if !has { diff --git a/models/webhook.go b/models/webhook.go index 8e112ac572..96af0b6967 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -5,6 +5,7 @@ package models import ( + "crypto/tls" "encoding/json" "errors" "io/ioutil" @@ -307,13 +308,14 @@ func DeliverHooks() { defer func() { isShooting = false }() tasks := make([]*HookTask, 0, 10) - timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second + timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second x.Where("is_delivered=?", false).Iterate(new(HookTask), func(idx int, bean interface{}) error { t := bean.(*HookTask) req := httplib.Post(t.Url).SetTimeout(timeout, timeout). Header("X-Gogs-Delivery", t.Uuid). - Header("X-Gogs-Event", string(t.EventType)) + Header("X-Gogs-Event", string(t.EventType)). + SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}) switch t.ContentType { case JSON: @@ -329,7 +331,7 @@ func DeliverHooks() { case GOGS: { if _, err := req.Response(); err != nil { - log.Error(4, "Delivery: %v", err) + log.Error(5, "Delivery: %v", err) } else { t.IsSucceed = true } @@ -337,15 +339,15 @@ func DeliverHooks() { case SLACK: { if res, err := req.Response(); err != nil { - log.Error(4, "Delivery: %v", err) + log.Error(5, "Delivery: %v", err) } else { defer res.Body.Close() contents, err := ioutil.ReadAll(res.Body) if err != nil { - log.Error(4, "%s", err) + log.Error(5, "%s", err) } else { if string(contents) != "ok" { - log.Error(4, "slack failed with: %s", string(contents)) + log.Error(5, "slack failed with: %s", string(contents)) } else { t.IsSucceed = true } |