diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/action.go | 44 | ||||
-rw-r--r-- | models/cron/cron.go | 59 | ||||
-rw-r--r-- | models/git_diff.go | 6 | ||||
-rw-r--r-- | models/issue.go | 259 | ||||
-rw-r--r-- | models/issue_label.go | 234 | ||||
-rw-r--r-- | models/login.go | 12 | ||||
-rw-r--r-- | models/migrations/migrations.go | 2 | ||||
-rw-r--r-- | models/org.go | 20 | ||||
-rw-r--r-- | models/pull.go | 34 | ||||
-rw-r--r-- | models/repo.go | 16 | ||||
-rw-r--r-- | models/token.go | 5 | ||||
-rw-r--r-- | models/update.go | 90 | ||||
-rw-r--r-- | models/user.go | 5 | ||||
-rw-r--r-- | models/webhook.go | 4 |
14 files changed, 407 insertions, 383 deletions
diff --git a/models/action.go b/models/action.go index 3bcf999d..678d6c60 100644 --- a/models/action.go +++ b/models/action.go @@ -28,17 +28,19 @@ import ( type ActionType int const ( - CREATE_REPO ActionType = iota + 1 // 1 - RENAME_REPO // 2 - STAR_REPO // 3 - FOLLOW_REPO // 4 - COMMIT_REPO // 5 - CREATE_ISSUE // 6 - CREATE_PULL_REQUEST // 7 - TRANSFER_REPO // 8 - PUSH_TAG // 9 - COMMENT_ISSUE // 10 - MERGE_PULL_REQUEST // 11 + ACTION_CREATE_REPO ActionType = iota + 1 // 1 + ACTION_RENAME_REPO // 2 + ACTION_STAR_REPO // 3 + ACTION_WATCH_REPO // 4 + ACTION_COMMIT_REPO // 5 + ACTION_CREATE_ISSUE // 6 + ACTION_CREATE_PULL_REQUEST // 7 + ACTION_TRANSFER_REPO // 8 + ACTION_PUSH_TAG // 9 + ACTION_COMMENT_ISSUE // 10 + ACTION_MERGE_PULL_REQUEST // 11 + ACTION_CLOSE_ISSUE // 12 + ACTION_REOPEN_ISSUE // 13 ) var ( @@ -178,7 +180,7 @@ func newRepoAction(e Engine, u *User, repo *Repository) (err error) { ActUserID: u.Id, ActUserName: u.Name, ActEmail: u.Email, - OpType: CREATE_REPO, + OpType: ACTION_CREATE_REPO, RepoID: repo.ID, RepoUserName: repo.Owner.Name, RepoName: repo.Name, @@ -201,7 +203,7 @@ func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Reposit ActUserID: actUser.Id, ActUserName: actUser.Name, ActEmail: actUser.Email, - OpType: RENAME_REPO, + OpType: ACTION_RENAME_REPO, RepoID: repo.ID, RepoUserName: repo.Owner.Name, RepoName: repo.Name, @@ -366,7 +368,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string continue } - if err = issue.ChangeStatus(u, true); err != nil { + if err = issue.ChangeStatus(u, repo, true); err != nil { return err } } @@ -406,7 +408,7 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string continue } - if err = issue.ChangeStatus(u, false); err != nil { + if err = issue.ChangeStatus(u, repo, false); err != nil { return err } } @@ -443,10 +445,10 @@ func CommitRepoAction( } isNewBranch := false - opType := COMMIT_REPO + opType := ACTION_COMMIT_REPO // Check it's tag push or branch. if strings.HasPrefix(refFullName, "refs/tags/") { - opType = PUSH_TAG + opType = ACTION_PUSH_TAG commit = &PushCommits{} } else { // if not the first commit, set the compareUrl @@ -502,7 +504,7 @@ func CommitRepoAction( } switch opType { - case COMMIT_REPO: // Push + case ACTION_COMMIT_REPO: // Push p := &api.PushPayload{ Ref: refFullName, Before: oldCommitID, @@ -530,7 +532,7 @@ func CommitRepoAction( }) } - case PUSH_TAG: // Create + case ACTION_PUSH_TAG: // Create return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{ Ref: refName, RefType: "tag", @@ -547,7 +549,7 @@ func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repos ActUserID: actUser.Id, ActUserName: actUser.Name, ActEmail: actUser.Email, - OpType: TRANSFER_REPO, + OpType: ACTION_TRANSFER_REPO, RepoID: repo.ID, RepoUserName: newOwner.Name, RepoName: repo.Name, @@ -578,7 +580,7 @@ func mergePullRequestAction(e Engine, actUser *User, repo *Repository, pull *Iss ActUserID: actUser.Id, ActUserName: actUser.Name, ActEmail: actUser.Email, - OpType: MERGE_PULL_REQUEST, + OpType: ACTION_MERGE_PULL_REQUEST, Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name), RepoID: repo.ID, RepoUserName: repo.Owner.Name, diff --git a/models/cron/cron.go b/models/cron/cron.go deleted file mode 100644 index 8e494e55..00000000 --- a/models/cron/cron.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2014 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 cron - -import ( - "time" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/modules/cron" - "github.com/gogits/gogs/modules/log" - "github.com/gogits/gogs/modules/setting" -) - -var c = cron.New() - -func NewContext() { - var ( - entry *cron.Entry - err error - ) - if setting.Cron.UpdateMirror.Enabled { - entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate) - if err != nil { - log.Fatal(4, "Cron[Update mirrors]: %v", err) - } - if setting.Cron.UpdateMirror.RunAtStart { - entry.Prev = time.Now() - go models.MirrorUpdate() - } - } - if setting.Cron.RepoHealthCheck.Enabled { - entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck) - if err != nil { - log.Fatal(4, "Cron[Repository health check]: %v", err) - } - if setting.Cron.RepoHealthCheck.RunAtStart { - entry.Prev = time.Now() - go models.GitFsck() - } - } - if setting.Cron.CheckRepoStats.Enabled { - entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats) - if err != nil { - log.Fatal(4, "Cron[Check repository statistics]: %v", err) - } - if setting.Cron.CheckRepoStats.RunAtStart { - entry.Prev = time.Now() - go models.CheckRepoStats() - } - } - c.Start() -} - -// ListTasks returns all running cron tasks. -func ListTasks() []*cron.Entry { - return c.Entries() -} diff --git a/models/git_diff.go b/models/git_diff.go index 9796ef59..ab70139f 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -161,7 +161,6 @@ type DiffFile struct { IsBin bool IsRenamed bool Sections []*DiffSection - HighlightClass string } func (diffFile *DiffFile) GetType() int { @@ -169,10 +168,7 @@ func (diffFile *DiffFile) GetType() int { } func (diffFile *DiffFile) GetHighlightClass() string { - if diffFile.HighlightClass == "" { - diffFile.HighlightClass = highlight.FileNameToHighlightClass(diffFile.Name) - } - return diffFile.HighlightClass + return highlight.FileNameToHighlightClass(diffFile.Name) } type Diff struct { diff --git a/models/issue.go b/models/issue.go index 32645463..94998d78 100644 --- a/models/issue.go +++ b/models/issue.go @@ -17,11 +17,11 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" + gouuid "github.com/satori/go.uuid" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/setting" - gouuid "github.com/gogits/gogs/modules/uuid" ) var ( @@ -218,7 +218,7 @@ func (i *Issue) ReadBy(uid int64) error { return UpdateIssueUserByRead(uid, i.ID) } -func (i *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err error) { +func (i *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, isClosed bool) (err error) { if i.IsClosed == isClosed { return nil } @@ -251,7 +251,7 @@ func (i *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err er } // New action comment. - if _, err = createStatusComment(e, doer, i.Repo, i); err != nil { + if _, err = createStatusComment(e, doer, repo, i); err != nil { return err } @@ -259,14 +259,14 @@ func (i *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err er } // ChangeStatus changes issue status to open/closed. -func (i *Issue) ChangeStatus(doer *User, isClosed bool) (err error) { +func (i *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (err error) { sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } - if err = i.changeStatus(sess, doer, isClosed); err != nil { + if err = i.changeStatus(sess, doer, repo, isClosed); err != nil { return err } @@ -364,7 +364,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) ActUserID: issue.Poster.Id, ActUserName: issue.Poster.Name, ActEmail: issue.Poster.Email, - OpType: CREATE_ISSUE, + OpType: ACTION_CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), RepoID: repo.ID, RepoUserName: repo.Owner.Name, @@ -934,213 +934,6 @@ func UpdateIssueUsersByMentions(uids []int64, iid int64) error { return nil } -// .____ ___. .__ -// | | _____ \_ |__ ____ | | -// | | \__ \ | __ \_/ __ \| | -// | |___ / __ \| \_\ \ ___/| |__ -// |_______ (____ /___ /\___ >____/ -// \/ \/ \/ \/ - -// Label represents a label of repository for issues. -type Label struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX"` - Name string - Color string `xorm:"VARCHAR(7)"` - NumIssues int - NumClosedIssues int - NumOpenIssues int `xorm:"-"` - IsChecked bool `xorm:"-"` -} - -// CalOpenIssues calculates the open issues of label. -func (m *Label) CalOpenIssues() { - m.NumOpenIssues = m.NumIssues - m.NumClosedIssues -} - -// NewLabel creates new label of repository. -func NewLabel(l *Label) error { - _, err := x.Insert(l) - return err -} - -func getLabelByID(e Engine, id int64) (*Label, error) { - if id <= 0 { - return nil, ErrLabelNotExist{id} - } - - l := &Label{ID: id} - has, err := x.Get(l) - if err != nil { - return nil, err - } else if !has { - return nil, ErrLabelNotExist{l.ID} - } - return l, nil -} - -// GetLabelByID returns a label by given ID. -func GetLabelByID(id int64) (*Label, error) { - return getLabelByID(x, id) -} - -// GetLabelsByRepoID returns all labels that belong to given repository by ID. -func GetLabelsByRepoID(repoID int64) ([]*Label, error) { - labels := make([]*Label, 0, 10) - return labels, x.Where("repo_id=?", repoID).Find(&labels) -} - -func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) { - issueLabels, err := getIssueLabels(e, issueID) - if err != nil { - return nil, fmt.Errorf("getIssueLabels: %v", err) - } - - var label *Label - labels := make([]*Label, 0, len(issueLabels)) - for idx := range issueLabels { - label, err = getLabelByID(e, issueLabels[idx].LabelID) - if err != nil && !IsErrLabelNotExist(err) { - return nil, fmt.Errorf("getLabelByID: %v", err) - } - labels = append(labels, label) - } - return labels, nil -} - -// GetLabelsByIssueID returns all labels that belong to given issue by ID. -func GetLabelsByIssueID(issueID int64) ([]*Label, error) { - return getLabelsByIssueID(x, issueID) -} - -func updateLabel(e Engine, l *Label) error { - _, err := e.Id(l.ID).AllCols().Update(l) - return err -} - -// UpdateLabel updates label information. -func UpdateLabel(l *Label) error { - return updateLabel(x, l) -} - -// DeleteLabel delete a label of given repository. -func DeleteLabel(repoID, labelID int64) error { - l, err := GetLabelByID(labelID) - if err != nil { - if IsErrLabelNotExist(err) { - return nil - } - return err - } - - sess := x.NewSession() - defer sessionRelease(sess) - if err = sess.Begin(); err != nil { - return err - } - - if _, err = x.Where("label_id=?", labelID).Delete(new(IssueLabel)); err != nil { - return err - } else if _, err = sess.Delete(l); err != nil { - return err - } - return sess.Commit() -} - -// .___ .____ ___. .__ -// | | ______ ________ __ ____ | | _____ \_ |__ ____ | | -// | |/ ___// ___/ | \_/ __ \| | \__ \ | __ \_/ __ \| | -// | |\___ \ \___ \| | /\ ___/| |___ / __ \| \_\ \ ___/| |__ -// |___/____ >____ >____/ \___ >_______ (____ /___ /\___ >____/ -// \/ \/ \/ \/ \/ \/ \/ - -// IssueLabel represetns an issue-lable relation. -type IssueLabel struct { - ID int64 `xorm:"pk autoincr"` - IssueID int64 `xorm:"UNIQUE(s)"` - LabelID int64 `xorm:"UNIQUE(s)"` -} - -func hasIssueLabel(e Engine, issueID, labelID int64) bool { - has, _ := e.Where("issue_id=? AND label_id=?", issueID, labelID).Get(new(IssueLabel)) - return has -} - -// HasIssueLabel returns true if issue has been labeled. -func HasIssueLabel(issueID, labelID int64) bool { - return hasIssueLabel(x, issueID, labelID) -} - -func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) { - if _, err = e.Insert(&IssueLabel{ - IssueID: issue.ID, - LabelID: label.ID, - }); err != nil { - return err - } - - label.NumIssues++ - if issue.IsClosed { - label.NumClosedIssues++ - } - return updateLabel(e, label) -} - -// NewIssueLabel creates a new issue-label relation. -func NewIssueLabel(issue *Issue, label *Label) (err error) { - sess := x.NewSession() - defer sessionRelease(sess) - if err = sess.Begin(); err != nil { - return err - } - - if err = newIssueLabel(sess, issue, label); err != nil { - return err - } - - return sess.Commit() -} - -func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) { - issueLabels := make([]*IssueLabel, 0, 10) - return issueLabels, e.Where("issue_id=?", issueID).Asc("label_id").Find(&issueLabels) -} - -// GetIssueLabels returns all issue-label relations of given issue by ID. -func GetIssueLabels(issueID int64) ([]*IssueLabel, error) { - return getIssueLabels(x, issueID) -} - -func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) { - if _, err = e.Delete(&IssueLabel{ - IssueID: issue.ID, - LabelID: label.ID, - }); err != nil { - return err - } - - label.NumIssues-- - if issue.IsClosed { - label.NumClosedIssues-- - } - return updateLabel(e, label) -} - -// DeleteIssueLabel deletes issue-label relation. -func DeleteIssueLabel(issue *Issue, label *Label) (err error) { - sess := x.NewSession() - defer sessionRelease(sess) - if err = sess.Begin(); err != nil { - return err - } - - if err = deleteIssueLabel(sess, issue, label); err != nil { - return err - } - - return sess.Commit() -} - // _____ .__.__ __ // / \ |__| | ____ _______/ |_ ____ ____ ____ // / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \ @@ -1564,9 +1357,24 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com return nil, err } + // Compose comment action, could be plain comment, close or reopen issue. + // This object will be used to notify watchers in the end of function. + act := &Action{ + ActUserID: u.Id, + ActUserName: u.Name, + ActEmail: u.Email, + Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), + RepoID: repo.ID, + RepoUserName: repo.Owner.Name, + RepoName: repo.Name, + IsPrivate: repo.IsPrivate, + } + // Check comment type. switch cmtType { case COMMENT_TYPE_COMMENT: + act.OpType = ACTION_COMMENT_ISSUE + if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", issue.ID); err != nil { return nil, err } @@ -1593,23 +1401,9 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com } } - // Notify watchers. - act := &Action{ - ActUserID: u.Id, - ActUserName: u.Name, - ActEmail: u.Email, - OpType: COMMENT_ISSUE, - Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, - } - if err = notifyWatchers(e, act); err != nil { - return nil, err - } - case COMMENT_TYPE_REOPEN: + act.OpType = ACTION_REOPEN_ISSUE + if issue.IsPull { _, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", repo.ID) } else { @@ -1619,6 +1413,8 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com return nil, err } case COMMENT_TYPE_CLOSE: + act.OpType = ACTION_CLOSE_ISSUE + if issue.IsPull { _, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", repo.ID) } else { @@ -1629,6 +1425,11 @@ func createComment(e *xorm.Session, u *User, repo *Repository, issue *Issue, com } } + // Notify watchers for whatever action comes in. + if err = notifyWatchers(e, act); err != nil { + return nil, fmt.Errorf("notifyWatchers: %v", err) + } + return comment, nil } diff --git a/models/issue_label.go b/models/issue_label.go new file mode 100644 index 00000000..4f814821 --- /dev/null +++ b/models/issue_label.go @@ -0,0 +1,234 @@ +// Copyright 2016 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 models + +import ( + "fmt" + "html/template" + "strconv" + "strings" + + "github.com/go-xorm/xorm" +) + +// Label represents a label of repository for issues. +type Label struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` + Name string + Color string `xorm:"VARCHAR(7)"` + NumIssues int + NumClosedIssues int + NumOpenIssues int `xorm:"-"` + IsChecked bool `xorm:"-"` +} + +// CalOpenIssues calculates the open issues of label. +func (m *Label) CalOpenIssues() { + m.NumOpenIssues = m.NumIssues - m.NumClosedIssues +} + +// ForegroundColor calculates the text color for labels based +// on their background color. +func (l *Label) ForegroundColor() template.CSS { + if strings.HasPrefix(l.Color, "#") { + if color, err := strconv.ParseUint(l.Color[1:], 16, 64); err == nil { + r := float32(0xFF & (color >> 16)) + g := float32(0xFF & (color >> 8)) + b := float32(0xFF & color) + luminance := (0.2126*r + 0.7152*g + 0.0722*b) / 255 + + if luminance < 0.5 { + return template.CSS("#fff") + } + } + } + + // default to black + return template.CSS("#000") +} + +// NewLabel creates new label of repository. +func NewLabel(l *Label) error { + _, err := x.Insert(l) + return err +} + +func getLabelByID(e Engine, id int64) (*Label, error) { + if id <= 0 { + return nil, ErrLabelNotExist{id} + } + + l := &Label{ID: id} + has, err := x.Get(l) + if err != nil { + return nil, err + } else if !has { + return nil, ErrLabelNotExist{l.ID} + } + return l, nil +} + +// GetLabelByID returns a label by given ID. +func GetLabelByID(id int64) (*Label, error) { + return getLabelByID(x, id) +} + +// GetLabelsByRepoID returns all labels that belong to given repository by ID. +func GetLabelsByRepoID(repoID int64) ([]*Label, error) { + labels := make([]*Label, 0, 10) + return labels, x.Where("repo_id=?", repoID).Find(&labels) +} + +func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) { + issueLabels, err := getIssueLabels(e, issueID) + if err != nil { + return nil, fmt.Errorf("getIssueLabels: %v", err) + } + + var label *Label + labels := make([]*Label, 0, len(issueLabels)) + for idx := range issueLabels { + label, err = getLabelByID(e, issueLabels[idx].LabelID) + if err != nil && !IsErrLabelNotExist(err) { + return nil, fmt.Errorf("getLabelByID: %v", err) + } + labels = append(labels, label) + } + return labels, nil +} + +// GetLabelsByIssueID returns all labels that belong to given issue by ID. +func GetLabelsByIssueID(issueID int64) ([]*Label, error) { + return getLabelsByIssueID(x, issueID) +} + +func updateLabel(e Engine, l *Label) error { + _, err := e.Id(l.ID).AllCols().Update(l) + return err +} + +// UpdateLabel updates label information. +func UpdateLabel(l *Label) error { + return updateLabel(x, l) +} + +// DeleteLabel delete a label of given repository. +func DeleteLabel(repoID, labelID int64) error { + l, err := GetLabelByID(labelID) + if err != nil { + if IsErrLabelNotExist(err) { + return nil + } + return err + } + + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return err + } + + if _, err = x.Where("label_id=?", labelID).Delete(new(IssueLabel)); err != nil { + return err + } else if _, err = sess.Delete(l); err != nil { + return err + } + return sess.Commit() +} + +// .___ .____ ___. .__ +// | | ______ ________ __ ____ | | _____ \_ |__ ____ | | +// | |/ ___// ___/ | \_/ __ \| | \__ \ | __ \_/ __ \| | +// | |\___ \ \___ \| | /\ ___/| |___ / __ \| \_\ \ ___/| |__ +// |___/____ >____ >____/ \___ >_______ (____ /___ /\___ >____/ +// \/ \/ \/ \/ \/ \/ \/ + +// IssueLabel represetns an issue-lable relation. +type IssueLabel struct { + ID int64 `xorm:"pk autoincr"` + IssueID int64 `xorm:"UNIQUE(s)"` + LabelID int64 `xorm:"UNIQUE(s)"` +} + +func hasIssueLabel(e Engine, issueID, labelID int64) bool { + has, _ := e.Where("issue_id=? AND label_id=?", issueID, labelID).Get(new(IssueLabel)) + return has +} + +// HasIssueLabel returns true if issue has been labeled. +func HasIssueLabel(issueID, labelID int64) bool { + return hasIssueLabel(x, issueID, labelID) +} + +func newIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) { + if _, err = e.Insert(&IssueLabel{ + IssueID: issue.ID, + LabelID: label.ID, + }); err != nil { + return err + } + + label.NumIssues++ + if issue.IsClosed { + label.NumClosedIssues++ + } + return updateLabel(e, label) +} + +// NewIssueLabel creates a new issue-label relation. +func NewIssueLabel(issue *Issue, label *Label) (err error) { + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return err + } + + if err = newIssueLabel(sess, issue, label); err != nil { + return err + } + + return sess.Commit() +} + +func getIssueLabels(e Engine, issueID int64) ([]*IssueLabel, error) { + issueLabels := make([]*IssueLabel, 0, 10) + return issueLabels, e.Where("issue_id=?", issueID).Asc("label_id").Find(&issueLabels) +} + +// GetIssueLabels returns all issue-label relations of given issue by ID. +func GetIssueLabels(issueID int64) ([]*IssueLabel, error) { + return getIssueLabels(x, issueID) +} + +func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label) (err error) { + if _, err = e.Delete(&IssueLabel{ + IssueID: issue.ID, + LabelID: label.ID, + }); err != nil { + return err + } + + label.NumIssues-- + if issue.IsClosed { + label.NumClosedIssues-- + } + return updateLabel(e, label) +} + +// DeleteIssueLabel deletes issue-label relation. +func DeleteIssueLabel(issue *Issue, label *Label) (err error) { + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return err + } + + if err = deleteIssueLabel(sess, issue, label); err != nil { + return err + } + + return sess.Commit() +} diff --git a/models/login.go b/models/login.go index df890509..cbad646d 100644 --- a/models/login.go +++ b/models/login.go @@ -28,11 +28,11 @@ type LoginType int // Note: new type must be added at the end of list to maintain compatibility. const ( LOGIN_NOTYPE LoginType = iota - LOGIN_PLAIN - LOGIN_LDAP - LOGIN_SMTP - LOGIN_PAM - LOGIN_DLDAP + LOGIN_PLAIN // 1 + LOGIN_LDAP // 2 + LOGIN_SMTP // 3 + LOGIN_PAM // 4 + LOGIN_DLDAP // 5 ) var ( @@ -42,7 +42,7 @@ var ( var LoginNames = map[LoginType]string{ LOGIN_LDAP: "LDAP (via BindDN)", - LOGIN_DLDAP: "LDAP (simple auth)", + LOGIN_DLDAP: "LDAP (simple auth)", // Via direct bind LOGIN_SMTP: "SMTP", LOGIN_PAM: "PAM", } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 78729bde..c8e399e1 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -16,12 +16,12 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" + gouuid "github.com/satori/go.uuid" "gopkg.in/ini.v1" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/setting" - gouuid "github.com/gogits/gogs/modules/uuid" ) const _MIN_DB_VER = 4 diff --git a/models/org.go b/models/org.go index de66af66..9d86df10 100644 --- a/models/org.go +++ b/models/org.go @@ -254,27 +254,25 @@ func IsPublicMembership(orgId, uid int64) bool { return has } -func getOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) { +func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) { orgs := make([]*User, 0, 10) - return orgs, sess.Where("`org_user`.uid=?", userID). + if !showAll { + sess.And("`org_user`.is_public=?", true) + } + return orgs, sess.And("`org_user`.uid=?", userID). Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs) } // GetOrgsByUserID returns a list of organizations that the given user ID // has joined. -func GetOrgsByUserID(userID int64) ([]*User, error) { - sess := x.NewSession() - return getOrgsByUserID(sess, userID) +func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) { + return getOrgsByUserID(x.NewSession(), userID, showAll) } // GetOrgsByUserIDDesc returns a list of organizations that the given user ID // has joined, ordered descending by the given condition. -func GetOrgsByUserIDDesc(userID int64, desc string, all bool) ([]*User, error) { - sess := x.NewSession() - if !all { - sess.And("`org_user`.is_public=?", true) - } - return getOrgsByUserID(sess.Desc(desc), userID) +func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, error) { + return getOrgsByUserID(x.NewSession().Desc(desc), userID, showAll) } func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) { diff --git a/models/pull.go b/models/pull.go index 330319f9..276dc1bc 100644 --- a/models/pull.go +++ b/models/pull.go @@ -138,7 +138,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error return err } - if err = pr.Issue.changeStatus(sess, doer, true); err != nil { + if err = pr.Issue.changeStatus(sess, doer, pr.Issue.Repo, true); err != nil { return fmt.Errorf("Issue.changeStatus: %v", err) } @@ -330,7 +330,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str ActUserID: pull.Poster.Id, ActUserName: pull.Poster.Name, ActEmail: pull.Poster.Email, - OpType: CREATE_PULL_REQUEST, + OpType: ACTION_CREATE_PULL_REQUEST, Content: fmt.Sprintf("%d|%s", pull.Index, pull.Name), RepoID: repo.ID, RepoUserName: repo.Owner.Name, @@ -482,6 +482,33 @@ func (pr *PullRequest) UpdatePatch() (err error) { return nil } +// PushToBaseRepo pushes commits from branches of head repository to +// corresponding branches of base repository. +// FIXME: could fail after user force push head repo, should we always force push here? +// FIXME: Only push branches that are actually updates? +func (pr *PullRequest) PushToBaseRepo() (err error) { + log.Trace("PushToBaseRepo[%[1]d]: pushing commits to base repo 'refs/pull/%[1]d/head'", pr.ID) + + headRepoPath := pr.HeadRepo.RepoPath() + headGitRepo, err := git.OpenRepository(headRepoPath) + if err != nil { + return fmt.Errorf("OpenRepository: %v", err) + } + + tmpRemoteName := fmt.Sprintf("tmp-pull-%d", pr.ID) + if err = headGitRepo.AddRemote(tmpRemoteName, pr.BaseRepo.RepoPath(), false); err != nil { + return fmt.Errorf("headGitRepo.AddRemote: %v", err) + } + // Make sure to remove the remote even if the push fails + defer headGitRepo.RemoveRemote(tmpRemoteName) + + if err = git.Push(headRepoPath, tmpRemoteName, fmt.Sprintf("%s:refs/pull/%d/head", pr.HeadBranch, pr.Index)); err != nil { + return fmt.Errorf("Push: %v", err) + } + + return nil +} + // AddToTaskQueue adds itself to pull request test task queue. func (pr *PullRequest) AddToTaskQueue() { go PullRequestQueue.AddFunc(pr.ID, func() { @@ -498,6 +525,9 @@ func addHeadRepoTasks(prs []*PullRequest) { if err := pr.UpdatePatch(); err != nil { log.Error(4, "UpdatePatch: %v", err) continue + } else if err := pr.PushToBaseRepo(); err != nil { + log.Error(4, "PushToBaseRepo: %v", err) + continue } pr.AddToTaskQueue() diff --git a/models/repo.go b/models/repo.go index 57014beb..089a5998 100644 --- a/models/repo.go +++ b/models/repo.go @@ -30,9 +30,9 @@ import ( "github.com/gogits/git-module" api "github.com/gogits/go-gogs-client" - "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/bindata" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/setting" ) @@ -332,7 +332,17 @@ func (repo *Repository) IsOwnedBy(userID int64) bool { // CanBeForked returns true if repository meets the requirements of being forked. func (repo *Repository) CanBeForked() bool { - return !repo.IsBare && !repo.IsMirror + return !repo.IsBare +} + +// CanEnablePulls returns true if repository meets the requirements of accepting pulls. +func (repo *Repository) CanEnablePulls() bool { + return !repo.IsMirror +} + +// AllowPulls returns true if repository meets the requirements of accepting pulls and has them enabled. +func (repo *Repository) AllowsPulls() bool { + return repo.CanEnablePulls() && repo.EnablePulls } func (repo *Repository) NextIssueIndex() int64 { @@ -348,7 +358,7 @@ func (repo *Repository) DescriptionHtml() template.HTML { sanitize := func(s string) string { return fmt.Sprintf(`<a href="%[1]s" target="_blank">%[1]s</a>`, s) } - return template.HTML(DescPattern.ReplaceAllStringFunc(base.Sanitizer.Sanitize(repo.Description), sanitize)) + return template.HTML(DescPattern.ReplaceAllStringFunc(markdown.Sanitizer.Sanitize(repo.Description), sanitize)) } func (repo *Repository) LocalCopyPath() string { diff --git a/models/token.go b/models/token.go index 136753c3..adf50a43 100644 --- a/models/token.go +++ b/models/token.go @@ -7,8 +7,9 @@ package models import ( "time" + gouuid "github.com/satori/go.uuid" + "github.com/gogits/gogs/modules/base" - "github.com/gogits/gogs/modules/uuid" ) // AccessToken represents a personal access token. @@ -25,7 +26,7 @@ type AccessToken struct { // NewAccessToken creates new access token. func NewAccessToken(t *AccessToken) error { - t.Sha1 = base.EncodeSha1(uuid.NewV4().String()) + t.Sha1 = base.EncodeSha1(gouuid.NewV4().String()) _, err := x.Insert(t) return err } diff --git a/models/update.go b/models/update.go index 5c6ea7f6..66775ea9 100644 --- a/models/update.go +++ b/models/update.go @@ -10,7 +10,7 @@ import ( "os/exec" "strings" - "github.com/gogits/git-module" + git "github.com/gogits/git-module" "github.com/gogits/gogs/modules/log" ) @@ -65,94 +65,104 @@ func ListToPushCommits(l *list.List) *PushCommits { return &PushCommits{l.Len(), commits, "", nil} } -func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName string, userID int64) error { - isNew := strings.HasPrefix(oldCommitID, "0000000") - if isNew && - strings.HasPrefix(newCommitID, "0000000") { - return fmt.Errorf("old rev and new rev both 000000") +type PushUpdateOptions struct { + RefName string + OldCommitID string + NewCommitID string + PusherID int64 + PusherName string + RepoUserName string + RepoName string +} + +// PushUpdate must be called for any push actions in order to +// generates necessary push action history feeds. +func PushUpdate(opts PushUpdateOptions) (err error) { + isNewRef := strings.HasPrefix(opts.OldCommitID, "0000000") + isDelRef := strings.HasPrefix(opts.NewCommitID, "0000000") + if isNewRef && isDelRef { + return fmt.Errorf("Old and new revisions both start with 000000") } - f := RepoPath(repoUserName, repoName) + repoPath := RepoPath(opts.RepoUserName, opts.RepoName) gitUpdate := exec.Command("git", "update-server-info") - gitUpdate.Dir = f - gitUpdate.Run() + gitUpdate.Dir = repoPath + if err = gitUpdate.Run(); err != nil { + return fmt.Errorf("Fail to call 'git update-server-info': %v", err) + } - isDel := strings.HasPrefix(newCommitID, "0000000") - if isDel { - log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userID) + if isDelRef { + log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d", + opts.RefName, opts.RepoUserName, opts.RepoName, opts.PusherName) return nil } - gitRepo, err := git.OpenRepository(f) + gitRepo, err := git.OpenRepository(repoPath) if err != nil { - return fmt.Errorf("runUpdate.Open repoId: %v", err) + return fmt.Errorf("OpenRepository: %v", err) } - user, err := GetUserByName(repoUserName) + repoUser, err := GetUserByName(opts.RepoUserName) if err != nil { - return fmt.Errorf("runUpdate.GetUserByName: %v", err) + return fmt.Errorf("GetUserByName: %v", err) } - repo, err := GetRepositoryByName(user.Id, repoName) + repo, err := GetRepositoryByName(repoUser.Id, opts.RepoName) if err != nil { - return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err) + return fmt.Errorf("GetRepositoryByName: %v", err) } // Push tags. - if strings.HasPrefix(refName, "refs/tags/") { - tagName := git.RefEndName(refName) - tag, err := gitRepo.GetTag(tagName) + if strings.HasPrefix(opts.RefName, "refs/tags/") { + tag, err := gitRepo.GetTag(git.RefEndName(opts.RefName)) if err != nil { - log.GitLogger.Fatal(4, "runUpdate.GetTag: %v", err) + return fmt.Errorf("gitRepo.GetTag: %v", err) } + // When tagger isn't available, fall back to get committer email. var actEmail string if tag.Tagger != nil { actEmail = tag.Tagger.Email } else { cmt, err := tag.Commit() if err != nil { - log.GitLogger.Fatal(4, "runUpdate.GetTag Commit: %v", err) + return fmt.Errorf("tag.Commit: %v", err) } actEmail = cmt.Committer.Email } commit := &PushCommits{} - - if err = CommitRepoAction(userID, user.Id, userName, actEmail, - repo.ID, repoUserName, repoName, refName, commit, oldCommitID, newCommitID); err != nil { - log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) + if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, actEmail, + repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, commit, opts.OldCommitID, opts.NewCommitID); err != nil { + return fmt.Errorf("CommitRepoAction (tag): %v", err) } return err } - newCommit, err := gitRepo.GetCommit(newCommitID) + newCommit, err := gitRepo.GetCommit(opts.NewCommitID) if err != nil { - return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err) + return fmt.Errorf("gitRepo.GetCommit: %v", err) } // Push new branch. var l *list.List - if isNew { + if isNewRef { l, err = newCommit.CommitsBeforeLimit(10) if err != nil { - return fmt.Errorf("CommitsBefore: %v", err) + return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err) } } else { - l, err = newCommit.CommitsBeforeUntil(oldCommitID) + l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID) if err != nil { - return fmt.Errorf("CommitsBeforeUntil: %v", err) + return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err) } } - if err != nil { - return fmt.Errorf("runUpdate.Commit repoId: %v", err) - } - - if err = CommitRepoAction(userID, user.Id, userName, user.Email, - repo.ID, repoUserName, repoName, refName, ListToPushCommits(l), oldCommitID, newCommitID); err != nil { - return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) + if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, repoUser.Email, + repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, ListToPushCommits(l), + opts.OldCommitID, opts.NewCommitID); err != nil { + return fmt.Errorf("CommitRepoAction (branch): %v", err) } return nil } diff --git a/models/user.go b/models/user.go index 7a881759..3264c063 100644 --- a/models/user.go +++ b/models/user.go @@ -29,6 +29,7 @@ import ( "github.com/gogits/gogs/modules/avatar" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/markdown" "github.com/gogits/gogs/modules/setting" ) @@ -111,7 +112,7 @@ func (u *User) BeforeUpdate() { func (u *User) AfterSet(colName string, _ xorm.Cell) { switch colName { case "full_name": - u.FullName = base.Sanitizer.Sanitize(u.FullName) + u.FullName = markdown.Sanitizer.Sanitize(u.FullName) case "created": u.Created = regulateTimeZone(u.Created) } @@ -641,7 +642,7 @@ func updateUser(e Engine, u *User) error { u.Description = u.Description[:255] } - u.FullName = base.Sanitizer.Sanitize(u.FullName) + u.FullName = markdown.Sanitizer.Sanitize(u.FullName) _, err := e.Id(u.Id).AllCols().Update(u) return err } diff --git a/models/webhook.go b/models/webhook.go index bdfb62d8..c20a72e9 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -15,13 +15,13 @@ import ( "github.com/Unknwon/com" "github.com/go-xorm/xorm" + gouuid "github.com/satori/go.uuid" api "github.com/gogits/go-gogs-client" "github.com/gogits/gogs/modules/httplib" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/setting" - "github.com/gogits/gogs/modules/uuid" ) type HookContentType int @@ -361,7 +361,7 @@ func CreateHookTask(t *HookTask) error { if err != nil { return err } - t.UUID = uuid.NewV4().String() + t.UUID = gouuid.NewV4().String() t.PayloadContent = string(data) _, err = x.Insert(t) return err |