summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2018-12-13 23:55:43 +0800
committertechknowlogick <hello@techknowlogick.com>2018-12-13 10:55:43 -0500
commitb3b7598ec6846d53d7deb2c84781b06e22c93044 (patch)
tree53c85943b23867b20e2b31742fbe06fcda088ccd /models
parent49ea6e0deb7ecef327b0c2f41920f75c6aaf80d3 (diff)
downloadgitea-b3b7598ec6846d53d7deb2c84781b06e22c93044.tar.gz
gitea-b3b7598ec6846d53d7deb2c84781b06e22c93044.zip
Improve performance of dashboard (#4977)
Diffstat (limited to 'models')
-rw-r--r--models/action.go66
-rw-r--r--models/issue.go83
-rw-r--r--models/issue_assignees.go6
-rw-r--r--models/issue_assignees_test.go2
-rw-r--r--models/issue_comment.go94
-rw-r--r--models/issue_comment_list.go58
-rw-r--r--models/issue_dependency_test.go5
-rw-r--r--models/issue_mail.go2
-rw-r--r--models/issue_stopwatch.go8
-rw-r--r--models/issue_tracked_time.go3
-rw-r--r--models/mail.go1
-rw-r--r--models/pull.go23
-rw-r--r--models/update.go2
13 files changed, 288 insertions, 65 deletions
diff --git a/models/action.go b/models/action.go
index 9050be22a6..cde0fb080e 100644
--- a/models/action.go
+++ b/models/action.go
@@ -194,6 +194,10 @@ func (a *Action) GetRepoLink() string {
// GetCommentLink returns link to action comment.
func (a *Action) GetCommentLink() string {
+ return a.getCommentLink(x)
+}
+
+func (a *Action) getCommentLink(e Engine) string {
if a == nil {
return "#"
}
@@ -213,11 +217,15 @@ func (a *Action) GetCommentLink() string {
return "#"
}
- issue, err := GetIssueByID(issueID)
+ issue, err := getIssueByID(e, issueID)
if err != nil {
return "#"
}
+ if err = issue.loadRepo(e); err != nil {
+ return "#"
+ }
+
return issue.HTMLURL()
}
@@ -330,13 +338,15 @@ type PushCommits struct {
Commits []*PushCommit
CompareURL string
- avatars map[string]string
+ avatars map[string]string
+ emailUsers map[string]*User
}
// NewPushCommits creates a new PushCommits object.
func NewPushCommits() *PushCommits {
return &PushCommits{
- avatars: make(map[string]string),
+ avatars: make(map[string]string),
+ emailUsers: make(map[string]*User),
}
}
@@ -344,16 +354,34 @@ func NewPushCommits() *PushCommits {
// api.PayloadCommit format.
func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit {
commits := make([]*api.PayloadCommit, len(pc.Commits))
+
+ if pc.emailUsers == nil {
+ pc.emailUsers = make(map[string]*User)
+ }
+ var err error
for i, commit := range pc.Commits {
authorUsername := ""
- author, err := GetUserByEmail(commit.AuthorEmail)
- if err == nil {
+ author, ok := pc.emailUsers[commit.AuthorEmail]
+ if !ok {
+ author, err = GetUserByEmail(commit.AuthorEmail)
+ if err == nil {
+ authorUsername = author.Name
+ pc.emailUsers[commit.AuthorEmail] = author
+ }
+ } else {
authorUsername = author.Name
}
+
committerUsername := ""
- committer, err := GetUserByEmail(commit.CommitterEmail)
- if err == nil {
- // TODO: check errors other than email not found.
+ committer, ok := pc.emailUsers[commit.CommitterEmail]
+ if !ok {
+ committer, err = GetUserByEmail(commit.CommitterEmail)
+ if err == nil {
+ // TODO: check errors other than email not found.
+ committerUsername = committer.Name
+ pc.emailUsers[commit.CommitterEmail] = committer
+ }
+ } else {
committerUsername = committer.Name
}
commits[i] = &api.PayloadCommit{
@@ -379,18 +407,28 @@ func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit
// AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link.
func (pc *PushCommits) AvatarLink(email string) string {
- _, ok := pc.avatars[email]
+ avatar, ok := pc.avatars[email]
+ if ok {
+ return avatar
+ }
+
+ u, ok := pc.emailUsers[email]
if !ok {
- u, err := GetUserByEmail(email)
+ var err error
+ u, err = GetUserByEmail(email)
if err != nil {
pc.avatars[email] = base.AvatarLink(email)
if !IsErrUserNotExist(err) {
log.Error(4, "GetUserByEmail: %v", err)
+ return ""
}
} else {
- pc.avatars[email] = u.RelAvatarLink()
+ pc.emailUsers[email] = u
}
}
+ if u != nil {
+ pc.avatars[email] = u.RelAvatarLink()
+ }
return pc.avatars[email]
}
@@ -479,7 +517,8 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
continue
}
- if err = issue.ChangeStatus(doer, repo, true); err != nil {
+ issue.Repo = repo
+ if err = issue.ChangeStatus(doer, true); err != nil {
// Don't return an error when dependencies are open as this would let the push fail
if IsErrDependenciesLeft(err) {
return nil
@@ -504,7 +543,8 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
continue
}
- if err = issue.ChangeStatus(doer, repo, false); err != nil {
+ issue.Repo = repo
+ if err = issue.ChangeStatus(doer, false); err != nil {
return err
}
}
diff --git a/models/issue.go b/models/issue.go
index 88e96e5706..cee9b0ca5c 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -86,6 +86,11 @@ func (issue *Issue) IsOverdue() bool {
return util.TimeStampNow() >= issue.DeadlineUnix
}
+// LoadRepo loads issue's repository
+func (issue *Issue) LoadRepo() error {
+ return issue.loadRepo(x)
+}
+
func (issue *Issue) loadRepo(e Engine) (err error) {
if issue.Repo == nil {
issue.Repo, err = getRepositoryByID(e, issue.RepoID)
@@ -129,6 +134,11 @@ func (issue *Issue) loadLabels(e Engine) (err error) {
return nil
}
+// LoadPoster loads poster
+func (issue *Issue) LoadPoster() error {
+ return issue.loadPoster(x)
+}
+
func (issue *Issue) loadPoster(e Engine) (err error) {
if issue.Poster == nil {
issue.Poster, err = getUserByID(e, issue.PosterID)
@@ -154,10 +164,16 @@ func (issue *Issue) loadPullRequest(e Engine) (err error) {
}
return fmt.Errorf("getPullRequestByIssueID [%d]: %v", issue.ID, err)
}
+ issue.PullRequest.Issue = issue
}
return nil
}
+// LoadPullRequest loads pull request info
+func (issue *Issue) LoadPullRequest() error {
+ return issue.loadPullRequest(x)
+}
+
func (issue *Issue) loadComments(e Engine) (err error) {
if issue.Comments != nil {
return nil
@@ -310,11 +326,18 @@ func (issue *Issue) State() api.StateType {
// Required - Poster, Labels,
// Optional - Milestone, Assignee, PullRequest
func (issue *Issue) APIFormat() *api.Issue {
+ return issue.apiFormat(x)
+}
+
+func (issue *Issue) apiFormat(e Engine) *api.Issue {
+ issue.loadLabels(e)
apiLabels := make([]*api.Label, len(issue.Labels))
for i := range issue.Labels {
apiLabels[i] = issue.Labels[i].APIFormat()
}
+ issue.loadPoster(e)
+ issue.loadRepo(e)
apiIssue := &api.Issue{
ID: issue.ID,
URL: issue.APIURL(),
@@ -336,6 +359,8 @@ func (issue *Issue) APIFormat() *api.Issue {
if issue.Milestone != nil {
apiIssue.Milestone = issue.Milestone.APIFormat()
}
+ issue.loadAssignees(e)
+
if len(issue.Assignees) > 0 {
for _, assignee := range issue.Assignees {
apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat())
@@ -343,6 +368,7 @@ func (issue *Issue) APIFormat() *api.Issue {
apiIssue.Assignee = issue.Assignees[0].APIFormat() // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
}
if issue.IsPull {
+ issue.loadPullRequest(e)
apiIssue.PullRequest = &api.PullRequestMeta{
HasMerged: issue.PullRequest.HasMerged,
}
@@ -656,7 +682,7 @@ func UpdateIssueCols(issue *Issue, cols ...string) error {
return updateIssueCols(x, issue, cols...)
}
-func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, isClosed bool) (err error) {
+func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err error) {
// Nothing should be performed if current status is same as target status
if issue.IsClosed == isClosed {
return nil
@@ -707,7 +733,7 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository,
}
// New action comment
- if _, err = createStatusComment(e, doer, repo, issue); err != nil {
+ if _, err = createStatusComment(e, doer, issue); err != nil {
return err
}
@@ -715,14 +741,21 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository,
}
// ChangeStatus changes issue status to open or closed.
-func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (err error) {
+func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
- if err = issue.changeStatus(sess, doer, repo, isClosed); err != nil {
+ if err = issue.loadRepo(sess); err != nil {
+ return err
+ }
+ if err = issue.loadPoster(sess); err != nil {
+ return err
+ }
+
+ if err = issue.changeStatus(sess, doer, isClosed); err != nil {
return err
}
@@ -733,12 +766,14 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
mode, _ := AccessLevel(issue.Poster, issue.Repo)
if issue.IsPull {
+ if err = issue.loadPullRequest(sess); err != nil {
+ return err
+ }
// Merge pull request calls issue.changeStatus so we need to handle separately.
- issue.PullRequest.Issue = issue
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
- Repository: repo.APIFormat(mode),
+ Repository: issue.Repo.APIFormat(mode),
Sender: doer.APIFormat(),
}
if isClosed {
@@ -746,12 +781,12 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
} else {
apiPullRequest.Action = api.HookIssueReOpened
}
- err = PrepareWebhooks(repo, HookEventPullRequest, apiPullRequest)
+ err = PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest)
} else {
apiIssue := &api.IssuePayload{
Index: issue.Index,
Issue: issue.APIFormat(),
- Repository: repo.APIFormat(mode),
+ Repository: issue.Repo.APIFormat(mode),
Sender: doer.APIFormat(),
}
if isClosed {
@@ -759,12 +794,12 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
} else {
apiIssue.Action = api.HookIssueReOpened
}
- err = PrepareWebhooks(repo, HookEventIssues, apiIssue)
+ err = PrepareWebhooks(issue.Repo, HookEventIssues, apiIssue)
}
if err != nil {
log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
} else {
- go HookQueue.Add(repo.ID)
+ go HookQueue.Add(issue.Repo.ID)
}
return nil
@@ -785,6 +820,10 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
return fmt.Errorf("updateIssueCols: %v", err)
}
+ if err = issue.loadRepo(sess); err != nil {
+ return fmt.Errorf("loadRepo: %v", err)
+ }
+
if _, err = createChangeTitleComment(sess, doer, issue.Repo, issue, oldTitle, title); err != nil {
return fmt.Errorf("createChangeTitleComment: %v", err)
}
@@ -795,6 +834,9 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
mode, _ := AccessLevel(issue.Poster, issue.Repo)
if issue.IsPull {
+ if err = issue.loadPullRequest(sess); err != nil {
+ return fmt.Errorf("loadPullRequest: %v", err)
+ }
issue.PullRequest.Issue = issue
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueEdited,
@@ -1099,8 +1141,8 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
return nil
}
-// GetRawIssueByIndex returns raw issue without loading attributes by index in a repository.
-func GetRawIssueByIndex(repoID, index int64) (*Issue, error) {
+// GetIssueByIndex returns raw issue without loading attributes by index in a repository.
+func GetIssueByIndex(repoID, index int64) (*Issue, error) {
issue := &Issue{
RepoID: repoID,
Index: index,
@@ -1114,9 +1156,9 @@ func GetRawIssueByIndex(repoID, index int64) (*Issue, error) {
return issue, nil
}
-// GetIssueByIndex returns issue by index in a repository.
-func GetIssueByIndex(repoID, index int64) (*Issue, error) {
- issue, err := GetRawIssueByIndex(repoID, index)
+// GetIssueWithAttrsByIndex returns issue by index in a repository.
+func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
+ issue, err := GetIssueByIndex(repoID, index)
if err != nil {
return nil, err
}
@@ -1131,7 +1173,16 @@ func getIssueByID(e Engine, id int64) (*Issue, error) {
} else if !has {
return nil, ErrIssueNotExist{id, 0, 0}
}
- return issue, issue.loadAttributes(e)
+ return issue, nil
+}
+
+// GetIssueWithAttrsByID returns an issue with attributes by given ID.
+func GetIssueWithAttrsByID(id int64) (*Issue, error) {
+ issue, err := getIssueByID(x, id)
+ if err != nil {
+ return nil, err
+ }
+ return issue, issue.loadAttributes(x)
}
// GetIssueByID returns an issue by given ID.
diff --git a/models/issue_assignees.go b/models/issue_assignees.go
index f330ade1c8..753396e39b 100644
--- a/models/issue_assignees.go
+++ b/models/issue_assignees.go
@@ -174,7 +174,7 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(),
- Repository: issue.Repo.APIFormat(mode),
+ Repository: issue.Repo.innerAPIFormat(sess, mode, false),
Sender: doer.APIFormat(),
}
if removed {
@@ -191,8 +191,8 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
apiIssue := &api.IssuePayload{
Index: issue.Index,
- Issue: issue.APIFormat(),
- Repository: issue.Repo.APIFormat(mode),
+ Issue: issue.apiFormat(sess),
+ Repository: issue.Repo.innerAPIFormat(sess, mode, false),
Sender: doer.APIFormat(),
}
if removed {
diff --git a/models/issue_assignees_test.go b/models/issue_assignees_test.go
index 3247812198..029c211a4b 100644
--- a/models/issue_assignees_test.go
+++ b/models/issue_assignees_test.go
@@ -14,7 +14,7 @@ func TestUpdateAssignee(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
// Fake issue with assignees
- issue, err := GetIssueByID(1)
+ issue, err := GetIssueWithAttrsByID(1)
assert.NoError(t, err)
// Assign multiple users
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 96b162ca19..577de1d84d 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -150,25 +150,6 @@ func (c *Comment) LoadIssue() (err error) {
return
}
-// AfterLoad is invoked from XORM after setting the values of all fields of this object.
-func (c *Comment) AfterLoad(session *xorm.Session) {
- var err error
- c.Attachments, err = getAttachmentsByCommentID(session, c.ID)
- if err != nil {
- log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
- }
-
- c.Poster, err = getUserByID(session, c.PosterID)
- if err != nil {
- if IsErrUserNotExist(err) {
- c.PosterID = -1
- c.Poster = NewGhostUser()
- } else {
- log.Error(3, "getUserByID[%d]: %v", c.ID, err)
- }
- }
-}
-
// AfterDelete is invoked from XORM after the object is deleted.
func (c *Comment) AfterDelete() {
if c.ID <= 0 {
@@ -189,6 +170,11 @@ func (c *Comment) HTMLURL() string {
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return ""
}
+ err = c.Issue.loadRepo(x)
+ if err != nil { // Silently dropping errors :unamused:
+ log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+ return ""
+ }
if c.Type == CommentTypeCode {
if c.ReviewID == 0 {
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
@@ -217,6 +203,12 @@ func (c *Comment) IssueURL() string {
if c.Issue.IsPull {
return ""
}
+
+ err = c.Issue.loadRepo(x)
+ if err != nil { // Silently dropping errors :unamused:
+ log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+ return ""
+ }
return c.Issue.HTMLURL()
}
@@ -228,6 +220,12 @@ func (c *Comment) PRURL() string {
return ""
}
+ err = c.Issue.loadRepo(x)
+ if err != nil { // Silently dropping errors :unamused:
+ log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+ return ""
+ }
+
if !c.Issue.IsPull {
return ""
}
@@ -303,6 +301,39 @@ func (c *Comment) LoadMilestone() error {
return nil
}
+// LoadPoster loads comment poster
+func (c *Comment) LoadPoster() error {
+ if c.PosterID <= 0 || c.Poster != nil {
+ return nil
+ }
+
+ var err error
+ c.Poster, err = getUserByID(x, c.PosterID)
+ if err != nil {
+ if IsErrUserNotExist(err) {
+ c.PosterID = -1
+ c.Poster = NewGhostUser()
+ } else {
+ log.Error(3, "getUserByID[%d]: %v", c.ID, err)
+ }
+ }
+ return nil
+}
+
+// LoadAttachments loads attachments
+func (c *Comment) LoadAttachments() error {
+ if len(c.Attachments) > 0 {
+ return nil
+ }
+
+ var err error
+ c.Attachments, err = getAttachmentsByCommentID(x, c.ID)
+ if err != nil {
+ log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
+ }
+ return nil
+}
+
// LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees
func (c *Comment) LoadAssigneeUser() error {
var err error
@@ -375,8 +406,10 @@ func (c *Comment) LoadReactions() error {
}
func (c *Comment) loadReview(e Engine) (err error) {
- if c.Review, err = getReviewByID(e, c.ReviewID); err != nil {
- return err
+ if c.Review == nil {
+ if c.Review, err = getReviewByID(e, c.ReviewID); err != nil {
+ return err
+ }
}
return nil
}
@@ -454,6 +487,11 @@ func (c *Comment) CodeCommentURL() string {
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return ""
}
+ err = c.Issue.loadRepo(x)
+ if err != nil { // Silently dropping errors :unamused:
+ log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
+ return ""
+ }
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
}
@@ -601,7 +639,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
return nil
}
-func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
+func createStatusComment(e *xorm.Session, doer *User, issue *Issue) (*Comment, error) {
cmtType := CommentTypeClose
if !issue.IsClosed {
cmtType = CommentTypeReopen
@@ -609,7 +647,7 @@ func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *I
return createComment(e, &CreateCommentOptions{
Type: cmtType,
Doer: doer,
- Repo: repo,
+ Repo: issue.Repo,
Issue: issue,
})
}
@@ -983,6 +1021,9 @@ func UpdateComment(doer *User, c *Comment, oldContent string) error {
UpdateIssueIndexer(c.IssueID)
}
+ if err := c.LoadPoster(); err != nil {
+ return err
+ }
if err := c.LoadIssue(); err != nil {
return err
}
@@ -1040,6 +1081,9 @@ func DeleteComment(doer *User, comment *Comment) error {
UpdateIssueIndexer(comment.IssueID)
}
+ if err := comment.LoadPoster(); err != nil {
+ return err
+ }
if err := comment.LoadIssue(); err != nil {
return err
}
@@ -1095,6 +1139,10 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review
return nil, err
}
+ if err := CommentList(comments).loadPosters(e); err != nil {
+ return nil, err
+ }
+
if err := issue.loadRepo(e); err != nil {
return nil, err
}
diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go
new file mode 100644
index 0000000000..35c1253f6b
--- /dev/null
+++ b/models/issue_comment_list.go
@@ -0,0 +1,58 @@
+// Copyright 2018 The Gitea 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
+
+// CommentList defines a list of comments
+type CommentList []*Comment
+
+func (comments CommentList) getPosterIDs() []int64 {
+ commentIDs := make(map[int64]struct{}, len(comments))
+ for _, comment := range comments {
+ if _, ok := commentIDs[comment.PosterID]; !ok {
+ commentIDs[comment.PosterID] = struct{}{}
+ }
+ }
+ return keysInt64(commentIDs)
+}
+
+// LoadPosters loads posters from database
+func (comments CommentList) LoadPosters() error {
+ return comments.loadPosters(x)
+}
+
+func (comments CommentList) loadPosters(e Engine) error {
+ if len(comments) == 0 {
+ return nil
+ }
+
+ posterIDs := comments.getPosterIDs()
+ posterMaps := make(map[int64]*User, len(posterIDs))
+ var left = len(posterIDs)
+ for left > 0 {
+ var limit = defaultMaxInSize
+ if left < limit {
+ limit = left
+ }
+ err := e.
+ In("id", posterIDs[:limit]).
+ Find(&posterMaps)
+ if err != nil {
+ return err
+ }
+ left = left - limit
+ posterIDs = posterIDs[limit:]
+ }
+
+ for _, comment := range comments {
+ if comment.PosterID <= 0 {
+ continue
+ }
+ var ok bool
+ if comment.Poster, ok = posterMaps[comment.PosterID]; !ok {
+ comment.Poster = NewGhostUser()
+ }
+ }
+ return nil
+}
diff --git a/models/issue_dependency_test.go b/models/issue_dependency_test.go
index 571bce3184..deb5dbcad7 100644
--- a/models/issue_dependency_test.go
+++ b/models/issue_dependency_test.go
@@ -19,8 +19,11 @@ func TestCreateIssueDependency(t *testing.T) {
issue1, err := GetIssueByID(1)
assert.NoError(t, err)
+ issue1.LoadAttributes()
+
issue2, err := GetIssueByID(2)
assert.NoError(t, err)
+ issue2.LoadAttributes()
// Create a dependency and check if it was successful
err = CreateIssueDependency(user1, issue1, issue2)
@@ -44,7 +47,7 @@ func TestCreateIssueDependency(t *testing.T) {
assert.False(t, left)
// Close #2 and check again
- err = issue2.ChangeStatus(user1, issue2.Repo, true)
+ err = issue2.ChangeStatus(user1, true)
assert.NoError(t, err)
left, err = IssueNoDependenciesLeft(issue1)
diff --git a/models/issue_mail.go b/models/issue_mail.go
index b78da6d79a..7f780e667e 100644
--- a/models/issue_mail.go
+++ b/models/issue_mail.go
@@ -39,7 +39,7 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
// In case the issue poster is not watching the repository and is active,
// even if we have duplicated in watchers, can be safely filtered out.
- poster, err := GetUserByID(issue.PosterID)
+ poster, err := getUserByID(e, issue.PosterID)
if err != nil {
return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
}
diff --git a/models/issue_stopwatch.go b/models/issue_stopwatch.go
index 178b76c5dd..d754e7e19e 100644
--- a/models/issue_stopwatch.go
+++ b/models/issue_stopwatch.go
@@ -49,6 +49,10 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
if err != nil {
return err
}
+ if err := issue.loadRepo(x); err != nil {
+ return err
+ }
+
if exists {
// Create tracked time out of the time difference between start date and actual date
timediff := time.Now().Unix() - int64(sw.CreatedUnix)
@@ -112,6 +116,10 @@ func CancelStopwatch(user *User, issue *Issue) error {
return err
}
+ if err := issue.loadRepo(x); err != nil {
+ return err
+ }
+
if _, err := CreateComment(&CreateCommentOptions{
Doer: user,
Issue: issue,
diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go
index 6592f06d73..bb3e767127 100644
--- a/models/issue_tracked_time.go
+++ b/models/issue_tracked_time.go
@@ -90,6 +90,9 @@ func AddTime(user *User, issue *Issue, time int64) (*TrackedTime, error) {
if _, err := x.Insert(tt); err != nil {
return nil, err
}
+ if err := issue.loadRepo(x); err != nil {
+ return nil, err
+ }
if _, err := CreateComment(&CreateCommentOptions{
Issue: issue,
Repo: issue.Repo,
diff --git a/models/mail.go b/models/mail.go
index 6b69e7b2ad..7e6d4e0265 100644
--- a/models/mail.go
+++ b/models/mail.go
@@ -151,6 +151,7 @@ func composeTplData(subject, body, link string) map[string]interface{} {
func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message {
subject := issue.mailSubject()
+ issue.LoadRepo()
body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas()))
data := make(map[string]interface{}, 10)
diff --git a/models/pull.go b/models/pull.go
index 0041f83dc8..0d8886186e 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -148,6 +148,10 @@ func (pr *PullRequest) GetGitRefName() string {
// Required - Issue
// Optional - Merger
func (pr *PullRequest) APIFormat() *api.PullRequest {
+ return pr.apiFormat(x)
+}
+
+func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
var (
baseBranch *Branch
headBranch *Branch
@@ -155,16 +159,20 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
headCommit *git.Commit
err error
)
- apiIssue := pr.Issue.APIFormat()
+ if err = pr.Issue.loadRepo(e); err != nil {
+ log.Error(log.ERROR, "loadRepo[%d]: %v", pr.ID, err)
+ return nil
+ }
+ apiIssue := pr.Issue.apiFormat(e)
if pr.BaseRepo == nil {
- pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
+ pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID)
if err != nil {
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
return nil
}
}
if pr.HeadRepo == nil {
- pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
+ pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
if err != nil {
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
return nil
@@ -187,15 +195,18 @@ func (pr *PullRequest) APIFormat() *api.PullRequest {
Ref: pr.BaseBranch,
Sha: baseCommit.ID.String(),
RepoID: pr.BaseRepoID,
- Repository: pr.BaseRepo.APIFormat(AccessModeNone),
+ Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
}
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
Sha: headCommit.ID.String(),
RepoID: pr.HeadRepoID,
- Repository: pr.HeadRepo.APIFormat(AccessModeNone),
+ Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
}
+
+ pr.Issue.loadRepo(e)
+
apiPullRequest := &api.PullRequest{
ID: pr.ID,
Index: pr.Index,
@@ -542,7 +553,7 @@ func (pr *PullRequest) setMerged() (err error) {
return err
}
- if err = pr.Issue.changeStatus(sess, pr.Merger, pr.Issue.Repo, true); err != nil {
+ if err = pr.Issue.changeStatus(sess, pr.Merger, true); err != nil {
return fmt.Errorf("Issue.changeStatus: %v", err)
}
if _, err = sess.ID(pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil {
diff --git a/models/update.go b/models/update.go
index 0f71cd1e70..9cd4d0d977 100644
--- a/models/update.go
+++ b/models/update.go
@@ -51,7 +51,7 @@ func ListToPushCommits(l *list.List) *PushCommits {
}
commits = append(commits, CommitToPushCommit(commit))
}
- return &PushCommits{l.Len(), commits, "", nil}
+ return &PushCommits{l.Len(), commits, "", make(map[string]string), make(map[string]*User)}
}
// PushUpdateOptions defines the push update options