diff options
Diffstat (limited to 'routers')
-rw-r--r-- | routers/admin/admin.go | 2 | ||||
-rw-r--r-- | routers/admin/notice.go | 2 | ||||
-rw-r--r-- | routers/admin/users.go | 1 | ||||
-rw-r--r-- | routers/api/v1/repo.go | 77 | ||||
-rw-r--r-- | routers/api/v1/user.go | 2 | ||||
-rw-r--r-- | routers/install.go | 9 | ||||
-rw-r--r-- | routers/repo/commit.go | 85 | ||||
-rw-r--r-- | routers/repo/forks.go | 37 | ||||
-rw-r--r-- | routers/repo/http.go | 7 | ||||
-rw-r--r-- | routers/repo/issue.go | 202 | ||||
-rw-r--r-- | routers/repo/pull.go | 106 | ||||
-rw-r--r-- | routers/repo/release.go | 82 | ||||
-rw-r--r-- | routers/repo/repo.go | 62 | ||||
-rw-r--r-- | routers/repo/setting.go | 14 | ||||
-rw-r--r-- | routers/repo/stars.go | 44 | ||||
-rw-r--r-- | routers/repo/view.go | 77 | ||||
-rw-r--r-- | routers/repo/watchers.go | 44 | ||||
-rw-r--r-- | routers/user/auth.go | 2 | ||||
-rw-r--r-- | routers/user/home.go | 50 |
19 files changed, 446 insertions, 459 deletions
diff --git a/routers/admin/admin.go b/routers/admin/admin.go index 54d1a145..54e4559f 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -11,7 +11,7 @@ import ( "time" "github.com/Unknwon/com" - "github.com/Unknwon/macaron" + "gopkg.in/macaron.v1" "github.com/gogits/gogs/models" "github.com/gogits/gogs/models/cron" diff --git a/routers/admin/notice.go b/routers/admin/notice.go index 512c3f59..b076994d 100644 --- a/routers/admin/notice.go +++ b/routers/admin/notice.go @@ -49,5 +49,5 @@ func DeleteNotice(ctx *middleware.Context) { } log.Trace("System notice deleted by admin(%s): %d", ctx.User.Name, id) ctx.Flash.Success(ctx.Tr("admin.notices.delete_success")) - ctx.Redirect("/admin/notices") + ctx.Redirect(setting.AppSubUrl + "/admin/notices") } diff --git a/routers/admin/users.go b/routers/admin/users.go index ac0f5381..d5358553 100644 --- a/routers/admin/users.go +++ b/routers/admin/users.go @@ -213,6 +213,7 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) { u.IsActive = form.Active u.IsAdmin = form.Admin u.AllowGitHook = form.AllowGitHook + u.AllowImportLocal = form.AllowImportLocal if err := models.UpdateUser(u); err != nil { if models.IsErrEmailAlreadyUsed(err) { diff --git a/routers/api/v1/repo.go b/routers/api/v1/repo.go index 9cdb16f8..b4da4c6f 100644 --- a/routers/api/v1/repo.go +++ b/routers/api/v1/repo.go @@ -5,9 +5,7 @@ package v1 import ( - "net/url" "path" - "strings" "github.com/Unknwon/com" @@ -108,9 +106,9 @@ func ListMyRepos(ctx *middleware.Context) { } numOwnRepos := len(ownRepos) - accessibleRepos, err := ctx.User.GetAccessibleRepositories() + accessibleRepos, err := ctx.User.GetRepositoryAccesses() if err != nil { - ctx.APIError(500, "GetAccessibleRepositories", err) + ctx.APIError(500, "GetRepositoryAccesses", err) return } @@ -218,26 +216,33 @@ func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { } } - // Remote address can be HTTP/HTTPS/Git URL or local path. - remoteAddr := form.CloneAddr - if strings.HasPrefix(form.CloneAddr, "http://") || - strings.HasPrefix(form.CloneAddr, "https://") || - strings.HasPrefix(form.CloneAddr, "git://") { - u, err := url.Parse(form.CloneAddr) - if err != nil { - ctx.APIError(422, "", err) - return - } - if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 { - u.User = url.UserPassword(form.AuthUsername, form.AuthPassword) + remoteAddr, err := form.ParseRemoteAddr(ctx.User) + if err != nil { + if models.IsErrInvalidCloneAddr(err) { + addrErr := err.(models.ErrInvalidCloneAddr) + switch { + case addrErr.IsURLError: + ctx.APIError(422, "", err) + case addrErr.IsPermissionDenied: + ctx.APIError(422, "", "You are not allowed to import local repositories.") + case addrErr.IsInvalidPath: + ctx.APIError(422, "", "Invalid local path, it does not exist or not a directory.") + default: + ctx.APIError(500, "ParseRemoteAddr", "Unknown error type (ErrInvalidCloneAddr): "+err.Error()) + } + } else { + ctx.APIError(500, "ParseRemoteAddr", err) } - remoteAddr = u.String() - } else if !com.IsDir(remoteAddr) { - ctx.APIError(422, "", "Invalid local path, it does not exist or not a directory.") return } - repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) + repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{ + Name: form.RepoName, + Description: form.Description, + IsPrivate: form.Private || setting.Repository.ForcePrivate, + IsMirror: form.Mirror, + RemoteAddr: remoteAddr, + }) if err != nil { if repo != nil { if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil { @@ -252,37 +257,55 @@ func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) { ctx.JSON(201, ToApiRepository(ctxUser, repo, api.Permission{true, true, true})) } -func DeleteRepo(ctx *middleware.Context) { - user, err := models.GetUserByName(ctx.Params(":username")) +func parseOwnerAndRepo(ctx *middleware.Context) (*models.User, *models.Repository) { + owner, err := models.GetUserByName(ctx.Params(":username")) if err != nil { if models.IsErrUserNotExist(err) { ctx.APIError(422, "", err) } else { ctx.APIError(500, "GetUserByName", err) } - return + return nil, nil } - repo, err := models.GetRepositoryByName(user.Id, ctx.Params(":reponame")) + repo, err := models.GetRepositoryByName(owner.Id, ctx.Params(":reponame")) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Error(404) } else { ctx.APIError(500, "GetRepositoryByName", err) } + return nil, nil + } + + return owner, repo +} + +func GetRepo(ctx *middleware.Context) { + owner, repo := parseOwnerAndRepo(ctx) + if ctx.Written() { + return + } + + ctx.JSON(200, ToApiRepository(owner, repo, api.Permission{true, true, true})) +} + +func DeleteRepo(ctx *middleware.Context) { + owner, repo := parseOwnerAndRepo(ctx) + if ctx.Written() { return } - if user.IsOrganization() && !user.IsOwnedBy(ctx.User.Id) { + if owner.IsOrganization() && !owner.IsOwnedBy(ctx.User.Id) { ctx.APIError(403, "", "Given user is not owner of organization.") return } - if err := models.DeleteRepository(user.Id, repo.ID); err != nil { + if err := models.DeleteRepository(owner.Id, repo.ID); err != nil { ctx.APIError(500, "DeleteRepository", err) return } - log.Trace("Repository deleted: %s/%s", user.Name, repo.Name) + log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name) ctx.Status(204) } diff --git a/routers/api/v1/user.go b/routers/api/v1/user.go index f27cd3ae..ec4f720c 100644 --- a/routers/api/v1/user.go +++ b/routers/api/v1/user.go @@ -55,7 +55,7 @@ func SearchUsers(ctx *middleware.Context) { } } - ctx.Render.JSON(200, map[string]interface{}{ + ctx.JSON(200, map[string]interface{}{ "ok": true, "data": results, }) diff --git a/routers/install.go b/routers/install.go index b2523080..5240b88e 100644 --- a/routers/install.go +++ b/routers/install.go @@ -13,9 +13,9 @@ import ( "strings" "github.com/Unknwon/com" - "github.com/Unknwon/macaron" "github.com/go-xorm/xorm" "gopkg.in/ini.v1" + "gopkg.in/macaron.v1" "github.com/gogits/gogs/models" "github.com/gogits/gogs/models/cron" @@ -25,6 +25,7 @@ import ( "github.com/gogits/gogs/modules/mailer" "github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/modules/setting" + "github.com/gogits/gogs/modules/ssh" "github.com/gogits/gogs/modules/user" ) @@ -66,6 +67,7 @@ func GlobalInit() { models.HasEngine = true cron.NewContext() models.InitDeliverHooks() + models.InitTestPullRequests() log.NewGitLogger(path.Join(setting.LogRootPath, "http.log")) } if models.EnableSQLite3 { @@ -75,6 +77,11 @@ func GlobalInit() { log.Info("TiDB Supported") } checkRunMode() + + if setting.StartSSHServer { + ssh.Listen(setting.SSHPort) + log.Info("SSH server started on :%v", setting.SSHPort) + } } func InstallInit(ctx *middleware.Context) { diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 13483cc8..101cb5c5 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -8,7 +8,6 @@ import ( "container/list" "path" - "github.com/Unknwon/com" "github.com/Unknwon/paginater" "github.com/gogits/gogs/models" @@ -38,7 +37,6 @@ func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List { newCommits := list.New() for e := oldCommits.Front(); e != nil; e = e.Next() { c := e.Value.(*git.Commit) - c.CommitMessage = c.CommitMessage newCommits.PushBack(c) } return newCommits @@ -47,18 +45,6 @@ func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List { func Commits(ctx *middleware.Context) { ctx.Data["PageIsCommits"] = true - userName := ctx.Repo.Owner.Name - repoName := ctx.Repo.Repository.Name - - brs, err := ctx.Repo.GitRepo.GetBranches() - if err != nil { - ctx.Handle(500, "GetBranches", err) - return - } else if len(brs) == 0 { - ctx.Handle(404, "GetBranches", nil) - return - } - commitsCount, err := ctx.Repo.Commit.CommitsCount() if err != nil { ctx.Handle(500, "GetCommitsCount", err) @@ -79,11 +65,12 @@ func Commits(ctx *middleware.Context) { } commits = RenderIssueLinks(commits, ctx.Repo.RepoLink) commits = models.ValidateCommitsWithEmails(commits) - ctx.Data["Commits"] = commits - ctx.Data["Username"] = userName - ctx.Data["Reponame"] = repoName + + ctx.Data["Username"] = ctx.Repo.Owner.Name + ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["CommitCount"] = commitsCount + ctx.Data["Branch"] = ctx.Repo.BranchName ctx.HTML(200, COMMITS) } @@ -96,18 +83,6 @@ func SearchCommits(ctx *middleware.Context) { return } - userName := ctx.Params(":username") - repoName := ctx.Params(":reponame") - - brs, err := ctx.Repo.GitRepo.GetBranches() - if err != nil { - ctx.Handle(500, "GetBranches", err) - return - } else if len(brs) == 0 { - ctx.Handle(404, "GetBranches", nil) - return - } - commits, err := ctx.Repo.Commit.SearchCommits(keyword) if err != nil { ctx.Handle(500, "SearchCommits", err) @@ -115,12 +90,13 @@ func SearchCommits(ctx *middleware.Context) { } commits = RenderIssueLinks(commits, ctx.Repo.RepoLink) commits = models.ValidateCommitsWithEmails(commits) + ctx.Data["Commits"] = commits ctx.Data["Keyword"] = keyword - ctx.Data["Username"] = userName - ctx.Data["Reponame"] = repoName + ctx.Data["Username"] = ctx.Repo.Owner.Name + ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["CommitCount"] = commits.Len() - ctx.Data["Commits"] = commits + ctx.Data["Branch"] = ctx.Repo.BranchName ctx.HTML(200, COMMITS) } @@ -133,58 +109,36 @@ func FileHistory(ctx *middleware.Context) { return } - userName := ctx.Repo.Owner.Name - repoName := ctx.Repo.Repository.Name branchName := ctx.Repo.BranchName - - brs, err := ctx.Repo.GitRepo.GetBranches() - if err != nil { - ctx.Handle(500, "GetBranches", err) - return - } else if len(brs) == 0 { - ctx.Handle(404, "GetBranches", nil) - return - } - commitsCount, err := ctx.Repo.GitRepo.FileCommitsCount(branchName, fileName) if err != nil { - ctx.Handle(500, "repo.FileHistory(GetCommitsCount)", err) + ctx.Handle(500, "FileCommitsCount", err) return } else if commitsCount == 0 { - ctx.Handle(404, "repo.FileHistory", nil) + ctx.Handle(404, "FileCommitsCount", nil) return } - // Calculate and validate page number. - page := com.StrTo(ctx.Query("p")).MustInt() - if page < 1 { + page := ctx.QueryInt("page") + if page <= 1 { page = 1 } - lastPage := page - 1 - if lastPage < 0 { - lastPage = 0 - } - nextPage := page + 1 - if nextPage*50 > commitsCount { - nextPage = 0 - } + ctx.Data["Page"] = paginater.New(commitsCount, git.CommitsRangeSize, page, 5) - commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange( - branchName, fileName, page) + commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(branchName, fileName, page) if err != nil { - ctx.Handle(500, "repo.FileHistory(CommitsByRange)", err) + ctx.Handle(500, "CommitsByFileAndRange", err) return } commits = RenderIssueLinks(commits, ctx.Repo.RepoLink) commits = models.ValidateCommitsWithEmails(commits) - ctx.Data["Commits"] = commits - ctx.Data["Username"] = userName - ctx.Data["Reponame"] = repoName + + ctx.Data["Username"] = ctx.Repo.Owner.Name + ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["FileName"] = fileName ctx.Data["CommitCount"] = commitsCount - ctx.Data["LastPageNum"] = lastPage - ctx.Data["NextPageNum"] = nextPage + ctx.Data["Branch"] = branchName ctx.HTML(200, COMMITS) } @@ -196,7 +150,6 @@ func Diff(ctx *middleware.Context) { commitID := ctx.Repo.CommitID commit := ctx.Repo.Commit - commit.CommitMessage = commit.CommitMessage diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName), commitID, setting.Git.MaxGitDiffLines) if err != nil { diff --git a/routers/repo/forks.go b/routers/repo/forks.go deleted file mode 100644 index 099f0cc4..00000000 --- a/routers/repo/forks.go +++ /dev/null @@ -1,37 +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 repo - -import ( - "fmt" - "github.com/gogits/gogs/modules/base" - "github.com/gogits/gogs/modules/middleware" -) - -const ( - FORKS base.TplName = "repo/forks" -) - -func Forks(ctx *middleware.Context) { - ctx.Data["Title"] = ctx.Tr("repos.forks") - - forks, err := ctx.Repo.Repository.GetForks() - - if err != nil { - ctx.Handle(500, "GetForks", err) - return - } - - for _, fork := range forks { - if err = fork.GetOwner(); err != nil { - ctx.Handle(500, "GetOwner", fmt.Errorf("%d: %v", fork.ID, err)) - return - } - } - - ctx.Data["Forks"] = forks - - ctx.HTML(200, FORKS) -} diff --git a/routers/repo/http.go b/routers/repo/http.go index 52c9fbd3..214cc9ba 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -34,7 +34,7 @@ func authRequired(ctx *middleware.Context) { ctx.HTML(401, base.TplName("status/401")) } -func Http(ctx *middleware.Context) { +func HTTP(ctx *middleware.Context) { username := ctx.Params(":username") reponame := ctx.Params(":reponame") if strings.HasSuffix(reponame, ".git") { @@ -158,7 +158,7 @@ func Http(ctx *middleware.Context) { } if !isPull && repo.IsMirror { - ctx.HandleText(401, "can't push to mirror") + ctx.HandleText(401, "mirror repository is read-only") return } } @@ -195,7 +195,8 @@ func Http(ctx *middleware.Context) { // FIXME: handle error. if err = models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id); err == nil { - models.HookQueue.AddRepoID(repo.ID) + go models.HookQueue.Add(repo.ID) + go models.AddTestPullRequestTask(repo.ID, strings.TrimPrefix(refName, "refs/heads/")) } } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 6912a2fa..cf6687fe 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -59,6 +59,7 @@ func Issues(ctx *middleware.Context) { if isPullList { ctx.Data["Title"] = ctx.Tr("repo.pulls") ctx.Data["PageIsPullList"] = true + ctx.Data["HasForkedRepo"] = ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID) } else { ctx.Data["Title"] = ctx.Tr("repo.issues") ctx.Data["PageIsIssueList"] = true @@ -124,7 +125,8 @@ func Issues(ctx *middleware.Context) { } else { total = int(issueStats.ClosedCount) } - ctx.Data["Page"] = paginater.New(total, setting.IssuePagingNum, page, 5) + pager := paginater.New(total, setting.IssuePagingNum, page, 5) + ctx.Data["Page"] = pager // Get issues. issues, err := models.Issues(&models.IssuesOptions{ @@ -133,7 +135,7 @@ func Issues(ctx *middleware.Context) { RepoID: repo.ID, PosterID: posterID, MilestoneID: milestoneID, - Page: page, + Page: pager.Current(), IsClosed: isShowClosed, IsMention: filterMode == models.FM_MENTION, IsPull: isPullList, @@ -324,6 +326,47 @@ func ValidateRepoMetas(ctx *middleware.Context, form auth.CreateIssueForm) ([]in return labelIDs, milestoneID, assigneeID } +func checkMentions(ctx *middleware.Context, issue *models.Issue) { + // Update mentions. + mentions := base.MentionPattern.FindAllString(issue.Content, -1) + if len(mentions) > 0 { + for i := range mentions { + mentions[i] = strings.TrimSpace(mentions[i])[1:] + } + + if err := models.UpdateMentions(mentions, issue.ID); err != nil { + ctx.Handle(500, "UpdateMentions", err) + return + } + } + + repo := ctx.Repo.Repository + + // Mail watchers and mentions. + if setting.Service.EnableNotifyMail { + tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, repo, issue) + if err != nil { + ctx.Handle(500, "SendIssueNotifyMail", err) + return + } + + tos = append(tos, ctx.User.LowerName) + newTos := make([]string, 0, len(mentions)) + for _, m := range mentions { + if com.IsSliceContainsStr(tos, m) { + continue + } + + newTos = append(newTos, m) + } + if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, + repo, issue, models.GetUserEmailsByNames(newTos)); err != nil { + ctx.Handle(500, "SendIssueMentionMail", err) + return + } + } +} + func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["PageIsIssueList"] = true @@ -351,7 +394,7 @@ func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { issue := &models.Issue{ RepoID: ctx.Repo.Repository.ID, Index: repo.NextIssueIndex(), - Name: form.Title, + Name: strings.TrimSpace(form.Title), PosterID: ctx.User.Id, Poster: ctx.User, MilestoneID: milestoneID, @@ -363,41 +406,9 @@ func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { return } - // Update mentions. - mentions := base.MentionPattern.FindAllString(issue.Content, -1) - if len(mentions) > 0 { - for i := range mentions { - mentions[i] = strings.TrimSpace(mentions[i])[1:] - } - - if err := models.UpdateMentions(mentions, issue.ID); err != nil { - ctx.Handle(500, "UpdateMentions", err) - return - } - } - - // Mail watchers and mentions. - if setting.Service.EnableNotifyMail { - tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, repo, issue) - if err != nil { - ctx.Handle(500, "SendIssueNotifyMail", err) - return - } - - tos = append(tos, ctx.User.LowerName) - newTos := make([]string, 0, len(mentions)) - for _, m := range mentions { - if com.IsSliceContainsStr(tos, m) { - continue - } - - newTos = append(newTos, m) - } - if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, - repo, issue, models.GetUserEmailsByNames(newTos)); err != nil { - ctx.Handle(500, "SendIssueMentionMail", err) - return - } + checkMentions(ctx, issue) + if ctx.Written() { + return } log.Trace("Issue created: %d/%d", repo.ID, issue.ID) @@ -476,8 +487,14 @@ func ViewIssue(ctx *middleware.Context) { } if issue.IsPull { + if err = issue.GetPullRequest(); err != nil { + ctx.Handle(500, "GetPullRequest", err) + return + } + ctx.Data["PageIsPullList"] = true ctx.Data["PageIsPullConversation"] = true + ctx.Data["HasForkedRepo"] = ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID) } else { ctx.Data["PageIsIssueList"] = true } @@ -605,7 +622,7 @@ func UpdateIssueTitle(ctx *middleware.Context) { return } - issue.Name = ctx.Query("title") + issue.Name = ctx.QueryTrim("title") if len(issue.Name) == 0 { ctx.Error(204) return @@ -747,6 +764,12 @@ func NewComment(ctx *middleware.Context, form auth.CreateCommentForm) { } return } + if issue.IsPull { + if err = issue.GetPullRequest(); err != nil { + ctx.Handle(500, "GetPullRequest", err) + return + } + } var attachments []string if setting.AttachmentEnabled { @@ -759,72 +782,83 @@ func NewComment(ctx *middleware.Context, form auth.CreateCommentForm) { return } + var comment *models.Comment defer func() { - // Check if issue owner/poster changes the status of issue. - if (ctx.Repo.IsOwner() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id))) && + // Check if issue admin/poster changes the status of issue. + if (ctx.Repo.IsAdmin() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id))) && (form.Status == "reopen" || form.Status == "close") && !(issue.IsPull && issue.HasMerged) { - issue.Repo = ctx.Repo.Repository - if err = issue.ChangeStatus(ctx.User, form.Status == "close"); err != nil { - log.Error(4, "ChangeStatus: %v", err) + + // Duplication and conflict check should apply to reopen pull request. + var pr *models.PullRequest + + if form.Status == "reopen" && issue.IsPull { + pull := issue.PullRequest + pr, err = models.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch) + if err != nil { + if !models.IsErrPullRequestNotExist(err) { + ctx.Handle(500, "GetUnmergedPullRequest", err) + return + } + } + + // Regenerate patch and test conflict. + if pr == nil { + if err = issue.UpdatePatch(); err != nil { + ctx.Handle(500, "UpdatePatch", err) + return + } + + issue.AddToTaskQueue() + } + } + + if pr != nil { + ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index)) } else { - log.Trace("Issue[%d] status changed: %v", issue.ID, !issue.IsClosed) + issue.Repo = ctx.Repo.Repository + if err = issue.ChangeStatus(ctx.User, form.Status == "close"); err != nil { + log.Error(4, "ChangeStatus: %v", err) + } else { + log.Trace("Issue[%d] status changed to closed: %v", issue.ID, issue.IsClosed) + } } } + + // Redirect to comment hashtag if there is any actual content. + typeName := "issues" + if issue.IsPull { + typeName = "pulls" + } + if comment != nil { + ctx.Redirect(fmt.Sprintf("%s/%s/%d#%s", ctx.Repo.RepoLink, typeName, issue.Index, comment.HashTag())) + } else { + ctx.Redirect(fmt.Sprintf("%s/%s/%d", ctx.Repo.RepoLink, typeName, issue.Index)) + } }() // Fix #321: Allow empty comments, as long as we have attachments. if len(form.Content) == 0 && len(attachments) == 0 { - ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index)) return } - comment, err := models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments) + comment, err = models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments) if err != nil { ctx.Handle(500, "CreateIssueComment", err) return } - // Update mentions. - mentions := base.MentionPattern.FindAllString(comment.Content, -1) - if len(mentions) > 0 { - for i := range mentions { - mentions[i] = mentions[i][1:] - } - - if err := models.UpdateMentions(mentions, issue.ID); err != nil { - ctx.Handle(500, "UpdateMentions", err) - return - } + checkMentions(ctx, &models.Issue{ + ID: issue.ID, + Index: issue.Index, + Name: issue.Name, + Content: form.Content, + }) + if ctx.Written() { + return } - // Mail watchers and mentions. - if setting.Service.EnableNotifyMail { - issue.Content = form.Content - tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) - if err != nil { - ctx.Handle(500, "SendIssueNotifyMail", err) - return - } - - tos = append(tos, ctx.User.LowerName) - newTos := make([]string, 0, len(mentions)) - for _, m := range mentions { - if com.IsSliceContainsStr(tos, m) { - continue - } - - newTos = append(newTos, m) - } - if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, - ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { - ctx.Handle(500, "SendIssueMentionMail", err) - return - } - } log.Trace("Comment created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID) - - ctx.Redirect(fmt.Sprintf("%s/issues/%d#%s", ctx.Repo.RepoLink, issue.Index, comment.HashTag())) } func UpdateCommentContent(ctx *middleware.Context) { diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 40c83351..b6959241 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -6,6 +6,7 @@ package repo import ( "container/list" + "errors" "path" "strings" @@ -128,7 +129,7 @@ func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) { } func checkPullInfo(ctx *middleware.Context) *models.Issue { - pull, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { ctx.Handle(404, "GetIssueByIndex", err) @@ -137,28 +138,34 @@ func checkPullInfo(ctx *middleware.Context) *models.Issue { } return nil } - ctx.Data["Title"] = pull.Name - ctx.Data["Issue"] = pull + ctx.Data["Title"] = issue.Name + ctx.Data["Issue"] = issue - if !pull.IsPull { + if !issue.IsPull { ctx.Handle(404, "ViewPullCommits", nil) return nil } - if err = pull.GetPoster(); err != nil { + if err = issue.GetPoster(); err != nil { ctx.Handle(500, "GetPoster", err) return nil + } else if err = issue.GetPullRequest(); err != nil { + ctx.Handle(500, "GetPullRequest", err) + return nil + } else if err = issue.GetHeadRepo(); err != nil { + ctx.Handle(500, "GetHeadRepo", err) + return nil } if ctx.IsSigned { // Update issue-user. - if err = pull.ReadBy(ctx.User.Id); err != nil { + if err = issue.ReadBy(ctx.User.Id); err != nil { ctx.Handle(500, "ReadBy", err) return nil } } - return pull + return issue } func PrepareMergedViewPullInfo(ctx *middleware.Context, pull *models.Issue) { @@ -166,7 +173,12 @@ func PrepareMergedViewPullInfo(ctx *middleware.Context, pull *models.Issue) { var err error - ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBarcnh + if err = pull.GetMerger(); err != nil { + ctx.Handle(500, "GetMerger", err) + return + } + + ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch ctx.Data["NumCommits"], err = ctx.Repo.GitRepo.CommitsCountBetween(pull.MergeBase, pull.MergedCommitID) @@ -184,13 +196,19 @@ func PrepareMergedViewPullInfo(ctx *middleware.Context, pull *models.Issue) { func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullRequestInfo { repo := ctx.Repo.Repository - ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBarcnh + ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch var ( headGitRepo *git.Repository err error ) + + if err = pull.GetHeadRepo(); err != nil { + ctx.Handle(500, "GetHeadRepo", err) + return nil + } + if pull.HeadRepo != nil { headRepoPath, err := pull.HeadRepo.RepoPath() if err != nil { @@ -205,7 +223,7 @@ func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullR } } - if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBarcnh) { + if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) { ctx.Data["IsPullReuqestBroken"] = true ctx.Data["HeadTarget"] = "deleted" ctx.Data["NumCommits"] = 0 @@ -214,7 +232,7 @@ func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullR } prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name), - pull.BaseBranch, pull.HeadBarcnh) + pull.BaseBranch, pull.HeadBranch) if err != nil { ctx.Handle(500, "GetPullRequestInfo", err) return nil @@ -316,7 +334,7 @@ func ViewPullFiles(ctx *middleware.Context) { return } - headCommitID, err := headGitRepo.GetCommitIdOfBranch(pull.HeadBarcnh) + headCommitID, err := headGitRepo.GetCommitIdOfBranch(pull.HeadBranch) if err != nil { ctx.Handle(500, "GetCommitIdOfBranch", err) return @@ -355,39 +373,39 @@ func ViewPullFiles(ctx *middleware.Context) { } func MergePullRequest(ctx *middleware.Context) { - pull := checkPullInfo(ctx) + issue := checkPullInfo(ctx) if ctx.Written() { return } - if pull.IsClosed { + if issue.IsClosed { ctx.Handle(404, "MergePullRequest", nil) return } - pr, err := models.GetPullRequestByPullID(pull.ID) + pr, err := models.GetPullRequestByIssueID(issue.ID) if err != nil { if models.IsErrPullRequestNotExist(err) { - ctx.Handle(404, "GetPullRequestByPullID", nil) + ctx.Handle(404, "GetPullRequestByIssueID", nil) } else { - ctx.Handle(500, "GetPullRequestByPullID", err) + ctx.Handle(500, "GetPullRequestByIssueID", err) } return } - if !pr.CanAutoMerge || pr.HasMerged { + if !pr.CanAutoMerge() || pr.HasMerged { ctx.Handle(404, "MergePullRequest", nil) return } - pr.Pull = pull - pr.Pull.Repo = ctx.Repo.Repository + pr.Issue = issue + pr.Issue.Repo = ctx.Repo.Repository if err = pr.Merge(ctx.User, ctx.Repo.GitRepo); err != nil { - ctx.Handle(500, "GetPullRequestByPullID", err) + ctx.Handle(500, "Merge", err) return } log.Trace("Pull request merged: %d", pr.ID) - ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.PullIndex)) + ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index)) } func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) { @@ -536,18 +554,18 @@ func CompareAndPullRequest(ctx *middleware.Context) { return } - // pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch) - // if err != nil { - // if !models.IsErrPullRequestNotExist(err) { - // ctx.Handle(500, "GetUnmergedPullRequest", err) - // return - // } - // } else { - // ctx.Data["HasPullRequest"] = true - // ctx.Data["PullRequest"] = pr - // ctx.HTML(200, COMPARE_PULL) - // return - // } + pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch) + if err != nil { + if !models.IsErrPullRequestNotExist(err) { + ctx.Handle(500, "GetUnmergedPullRequest", err) + return + } + } else { + ctx.Data["HasPullRequest"] = true + ctx.Data["PullRequest"] = pr + ctx.HTML(200, COMPARE_PULL) + return + } nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch) if ctx.Written() { @@ -616,7 +634,7 @@ func CompareAndPullRequestPost(ctx *middleware.Context, form auth.CreateIssueFor HeadRepoID: headRepo.ID, BaseRepoID: repo.ID, HeadUserName: headUser.Name, - HeadBarcnh: headBranch, + HeadBranch: headBranch, BaseBranch: baseBranch, MergeBase: prInfo.MergeBase, Type: models.PULL_REQUEST_GOGS, @@ -628,3 +646,21 @@ func CompareAndPullRequestPost(ctx *middleware.Context, form auth.CreateIssueFor log.Trace("Pull request created: %d/%d", repo.ID, pull.ID) ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pull.Index)) } + +func TriggerTask(ctx *middleware.Context) { + _, repo := parseOwnerAndRepo(ctx) + if ctx.Written() { + return + } + branch := ctx.Query("branch") + if len(branch) == 0 { + ctx.Handle(422, "TriggerTask", errors.New("branch is empty")) + return + } + + log.Trace("TriggerTask[%d].(new request): %s", repo.ID, branch) + + go models.HookQueue.Add(repo.ID) + go models.AddTestPullRequestTask(repo.ID, branch) + ctx.Status(202) +} diff --git a/routers/repo/release.go b/routers/repo/release.go index 30d5f60b..f06a8319 100644 --- a/routers/repo/release.go +++ b/routers/repo/release.go @@ -13,15 +13,13 @@ import ( ) const ( - RELEASES base.TplName = "repo/release/list" - RELEASE_NEW base.TplName = "repo/release/new" - RELEASE_EDIT base.TplName = "repo/release/edit" + RELEASES base.TplName = "repo/release/list" + RELEASE_NEW base.TplName = "repo/release/new" ) func Releases(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("repo.release.releases") - ctx.Data["IsRepoToolbarReleases"] = true - ctx.Data["IsRepoReleaseNew"] = false + ctx.Data["PageIsReleaseList"] = true rawTags, err := ctx.Repo.GitRepo.GetTags() if err != nil { @@ -45,7 +43,7 @@ func Releases(ctx *middleware.Context) { continue } if rel.TagName == rawTag { - rel.Publisher, err = models.GetUserByID(rel.PublisherId) + rel.Publisher, err = models.GetUserByID(rel.PublisherID) if err != nil { ctx.Handle(500, "GetUserById", err) return @@ -88,10 +86,10 @@ func Releases(ctx *middleware.Context) { tags[i] = &models.Release{ Title: rawTag, TagName: rawTag, - Sha1: commit.Id.String(), + Sha1: commit.ID.String(), } - tags[i].NumCommits, err = ctx.Repo.GitRepo.CommitsCount(commit.Id.String()) + tags[i].NumCommits, err = ctx.Repo.GitRepo.CommitsCount(commit.ID.String()) if err != nil { ctx.Handle(500, "CommitsCount", err) return @@ -105,7 +103,7 @@ func Releases(ctx *middleware.Context) { continue } - rel.Publisher, err = models.GetUserByID(rel.PublisherId) + rel.Publisher, err = models.GetUserByID(rel.PublisherID) if err != nil { ctx.Handle(500, "GetUserById", err) return @@ -140,27 +138,15 @@ func Releases(ctx *middleware.Context) { } func NewRelease(ctx *middleware.Context) { - if !ctx.Repo.IsOwner() { - ctx.Handle(403, "release.ReleasesNew", nil) - return - } - ctx.Data["Title"] = ctx.Tr("repo.release.new_release") + ctx.Data["PageIsReleaseList"] = true ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch - ctx.Data["IsRepoToolbarReleases"] = true - ctx.Data["IsRepoReleaseNew"] = true ctx.HTML(200, RELEASE_NEW) } func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) { - if !ctx.Repo.IsOwner() { - ctx.Handle(403, "release.ReleasesNew", nil) - return - } - ctx.Data["Title"] = ctx.Tr("repo.release.new_release") - ctx.Data["IsRepoToolbarReleases"] = true - ctx.Data["IsRepoReleaseNew"] = true + ctx.Data["PageIsReleaseList"] = true if ctx.HasError() { ctx.HTML(200, RELEASE_NEW) @@ -185,12 +171,12 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) { } rel := &models.Release{ - RepoId: ctx.Repo.Repository.ID, - PublisherId: ctx.User.Id, + RepoID: ctx.Repo.Repository.ID, + PublisherID: ctx.User.Id, Title: form.Title, TagName: form.TagName, Target: form.Target, - Sha1: commit.Id.String(), + Sha1: commit.ID.String(), NumCommits: commitsCount, Note: form.Content, IsDraft: len(form.Draft) > 0, @@ -198,67 +184,69 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) { } if err = models.CreateRelease(ctx.Repo.GitRepo, rel); err != nil { - if err == models.ErrReleaseAlreadyExist { + if models.IsErrReleaseAlreadyExist(err) { + ctx.Data["Err_TagName"] = true ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), RELEASE_NEW, &form) } else { ctx.Handle(500, "CreateRelease", err) } return } - log.Trace("%s Release created: %s/%s:%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.Name, form.TagName) + log.Trace("Release created: %s/%s:%s", ctx.User.LowerName, ctx.Repo.Repository.Name, form.TagName) ctx.Redirect(ctx.Repo.RepoLink + "/releases") } func EditRelease(ctx *middleware.Context) { - if !ctx.Repo.IsOwner() { - ctx.Handle(403, "release.ReleasesEdit", nil) - return - } + ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") + ctx.Data["PageIsReleaseList"] = true + ctx.Data["PageIsEditRelease"] = true tagName := ctx.Params(":tagname") rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName) if err != nil { - if err == models.ErrReleaseNotExist { + if models.IsErrReleaseNotExist(err) { ctx.Handle(404, "GetRelease", err) } else { ctx.Handle(500, "GetRelease", err) } return } - ctx.Data["Release"] = rel + ctx.Data["tag_name"] = rel.TagName + ctx.Data["tag_target"] = rel.Target + ctx.Data["title"] = rel.Title + ctx.Data["content"] = rel.Note + ctx.Data["prerelease"] = rel.IsPrerelease - ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") - ctx.Data["IsRepoToolbarReleases"] = true - ctx.HTML(200, RELEASE_EDIT) + ctx.HTML(200, RELEASE_NEW) } func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) { - if !ctx.Repo.IsOwner() { - ctx.Handle(403, "release.EditReleasePost", nil) - return - } + ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") + ctx.Data["PageIsReleaseList"] = true + ctx.Data["PageIsEditRelease"] = true tagName := ctx.Params(":tagname") rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName) if err != nil { - if err == models.ErrReleaseNotExist { + if models.IsErrReleaseNotExist(err) { ctx.Handle(404, "GetRelease", err) } else { ctx.Handle(500, "GetRelease", err) } return } - ctx.Data["Release"] = rel + ctx.Data["tag_name"] = rel.TagName + ctx.Data["tag_target"] = rel.Target + ctx.Data["title"] = rel.Title + ctx.Data["content"] = rel.Note + ctx.Data["prerelease"] = rel.IsPrerelease if ctx.HasError() { - ctx.HTML(200, RELEASE_EDIT) + ctx.HTML(200, RELEASE_NEW) return } - ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") - ctx.Data["IsRepoToolbarReleases"] = true - rel.Title = form.Title rel.Note = form.Content rel.IsDraft = len(form.Draft) > 0 diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 8a0c5f97..ab7b4b99 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -6,7 +6,6 @@ package repo import ( "fmt" - "net/url" "os" "path" "strings" @@ -46,7 +45,7 @@ func checkContextUser(ctx *middleware.Context, uid int64) *models.User { } if err != nil { - ctx.Handle(500, "checkContextUser", fmt.Errorf("GetUserById(%d): %v", uid, err)) + ctx.Handle(500, "GetUserByID", fmt.Errorf("[%d]: %v", uid, err)) return nil } @@ -67,6 +66,7 @@ func Create(ctx *middleware.Context) { ctx.Data["Readmes"] = models.Readmes ctx.Data["readme"] = "Default" ctx.Data["private"] = ctx.User.LastRepoVisibility + ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) if ctx.Written() { @@ -117,11 +117,11 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { Gitignores: form.Gitignores, License: form.License, Readme: form.Readme, - IsPrivate: form.Private, + IsPrivate: form.Private || setting.Repository.ForcePrivate, AutoInit: form.AutoInit, }) if err == nil { - log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name) + log.Trace("Repository created[%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name) return } @@ -138,6 +138,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { func Migrate(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("new_migrate") ctx.Data["private"] = ctx.User.LastRepoVisibility + ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) if ctx.Written() { @@ -162,32 +163,36 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { return } - // Remote address can be HTTP/HTTPS/Git URL or local path. - // Note: remember to change api/v1/repo.go: MigrateRepo - // FIXME: merge these two functions with better error handling - remoteAddr := form.CloneAddr - if strings.HasPrefix(form.CloneAddr, "http://") || - strings.HasPrefix(form.CloneAddr, "https://") || - strings.HasPrefix(form.CloneAddr, "git://") { - u, err := url.Parse(form.CloneAddr) - if err != nil { + remoteAddr, err := form.ParseRemoteAddr(ctx.User) + if err != nil { + if models.IsErrInvalidCloneAddr(err) { ctx.Data["Err_CloneAddr"] = true - ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form) - return + addrErr := err.(models.ErrInvalidCloneAddr) + switch { + case addrErr.IsURLError: + ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form) + case addrErr.IsPermissionDenied: + ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), MIGRATE, &form) + case addrErr.IsInvalidPath: + ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form) + default: + ctx.Handle(500, "Unknown error", err) + } + } else { + ctx.Handle(500, "ParseRemoteAddr", err) } - if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 { - u.User = url.UserPassword(form.AuthUsername, form.AuthPassword) - } - remoteAddr = u.String() - } else if !com.IsDir(remoteAddr) { - ctx.Data["Err_CloneAddr"] = true - ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form) return } - repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) + repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{ + Name: form.RepoName, + Description: form.Description, + IsPrivate: form.Private || setting.Repository.ForcePrivate, + IsMirror: form.Mirror, + RemoteAddr: remoteAddr, + }) if err == nil { - log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) + log.Trace("Repository migrated[%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName) ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) return } @@ -245,11 +250,6 @@ func Action(ctx *middleware.Context) { redirectTo = ctx.Repo.RepoLink } ctx.Redirect(redirectTo) - - return - ctx.JSON(200, map[string]interface{}{ - "ok": true, - }) } func Download(ctx *middleware.Context) { @@ -312,7 +312,7 @@ func Download(ctx *middleware.Context) { return } - archivePath = path.Join(archivePath, base.ShortSha(commit.Id.String())+ext) + archivePath = path.Join(archivePath, base.ShortSha(commit.ID.String())+ext) if !com.IsFile(archivePath) { if err := commit.CreateArchive(archivePath, archiveType); err != nil { ctx.Handle(500, "Download -> CreateArchive "+archivePath, err) @@ -320,5 +320,5 @@ func Download(ctx *middleware.Context) { } } - ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+base.ShortSha(commit.Id.String())+ext) + ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+base.ShortSha(commit.ID.String())+ext) } diff --git a/routers/repo/setting.go b/routers/repo/setting.go index a9930e78..089c939e 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -564,28 +564,28 @@ func DeleteWebhook(ctx *middleware.Context) { }) } -func TriggerHook(ctx *middleware.Context) { - u, err := models.GetUserByName(ctx.Params(":username")) +func parseOwnerAndRepo(ctx *middleware.Context) (*models.User, *models.Repository) { + owner, err := models.GetUserByName(ctx.Params(":username")) if err != nil { if models.IsErrUserNotExist(err) { ctx.Handle(404, "GetUserByName", err) } else { ctx.Handle(500, "GetUserByName", err) } - return + return nil, nil } - repo, err := models.GetRepositoryByName(u.Id, ctx.Params(":reponame")) + repo, err := models.GetRepositoryByName(owner.Id, ctx.Params(":reponame")) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Handle(404, "GetRepositoryByName", err) } else { ctx.Handle(500, "GetRepositoryByName", err) } - return + return nil, nil } - models.HookQueue.AddRepoID(repo.ID) - ctx.Status(200) + + return owner, repo } func GitHooks(ctx *middleware.Context) { diff --git a/routers/repo/stars.go b/routers/repo/stars.go deleted file mode 100644 index 93854886..00000000 --- a/routers/repo/stars.go +++ /dev/null @@ -1,44 +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 repo - -import ( - "github.com/Unknwon/paginater" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/modules/base" - "github.com/gogits/gogs/modules/middleware" -) - -const ( - STARS base.TplName = "repo/stars" -) - -func Stars(ctx *middleware.Context) { - ctx.Data["Title"] = ctx.Tr("repos.stars") - - page := ctx.QueryInt("page") - if page <= 0 { - page = 1 - } - - ctx.Data["Page"] = paginater.New(ctx.Repo.Repository.NumStars, models.ItemsPerPage, page, 5) - - stars, err := ctx.Repo.Repository.GetStars(ctx.QueryInt("page")) - - if err != nil { - ctx.Handle(500, "GetStars", err) - return - } - - if (ctx.QueryInt("page")-1)*models.ItemsPerPage > ctx.Repo.Repository.NumStars { - ctx.Handle(404, "ctx.Repo.Repository.NumStars", nil) - return - } - - ctx.Data["Stars"] = stars - - ctx.HTML(200, STARS) -} diff --git a/routers/repo/view.go b/routers/repo/view.go index 2a36db6b..eeb5d5c0 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -11,19 +11,25 @@ import ( "path/filepath" "strings" + "github.com/Unknwon/paginater" + "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware" + "github.com/gogits/gogs/modules/template" ) const ( - HOME base.TplName = "repo/home" + HOME base.TplName = "repo/home" + WATCHERS base.TplName = "repo/watchers" + FORKS base.TplName = "repo/forks" ) func Home(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Repo.Repository.Name + ctx.Data["RequireHighlightJS"] = true branchName := ctx.Repo.BranchName userName := ctx.Repo.Owner.Name @@ -31,14 +37,19 @@ func Home(ctx *middleware.Context) { repoLink := ctx.Repo.RepoLink branchLink := ctx.Repo.RepoLink + "/src/" + branchName + treeLink := branchLink rawLink := ctx.Repo.RepoLink + "/raw/" + branchName // Get tree path treename := ctx.Repo.TreeName - if len(treename) > 0 && treename[len(treename)-1] == '/' { - ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1]) - return + if len(treename) > 0 { + if treename[len(treename)-1] == '/' { + ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1]) + return + } + + treeLink += "/" + treename } ctx.Data["IsRepoToolbarSource"] = true @@ -98,9 +109,9 @@ func Home(ctx *middleware.Context) { readmeExist := base.IsMarkdownFile(blob.Name()) || base.IsReadmeFile(blob.Name()) ctx.Data["ReadmeExist"] = readmeExist if readmeExist { - ctx.Data["FileContent"] = string(base.RenderMarkdown(buf, branchLink)) + ctx.Data["FileContent"] = string(base.RenderMarkdown(buf, path.Dir(treeLink))) } else { - if err, content := base.ToUtf8WithErr(buf); err != nil { + if err, content := template.ToUtf8WithErr(buf); err != nil { if err != nil { log.Error(4, "Convert content encoding: %s", err) } @@ -151,7 +162,7 @@ func Home(ctx *middleware.Context) { ctx.Handle(500, "GetCommitOfRelPath", err) return } - files = append(files, []interface{}{te, git.NewSubModuleFile(c, smUrl, te.Id.String())}) + files = append(files, []interface{}{te, git.NewSubModuleFile(c, smUrl, te.ID.String())}) } } ctx.Data["Files"] = files @@ -191,7 +202,7 @@ func Home(ctx *middleware.Context) { buf = append(buf, d...) switch { case base.IsMarkdownFile(readmeFile.Name()): - buf = base.RenderMarkdown(buf, branchLink) + buf = base.RenderMarkdown(buf, treeLink) default: buf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1) } @@ -238,3 +249,53 @@ func Home(ctx *middleware.Context) { ctx.Data["BranchLink"] = branchLink ctx.HTML(200, HOME) } + +func renderItems(ctx *middleware.Context, total int, getter func(page int) ([]*models.User, error)) { + page := ctx.QueryInt("page") + if page <= 0 { + page = 1 + } + pager := paginater.New(total, models.ItemsPerPage, page, 5) + ctx.Data["Page"] = pager + + items, err := getter(pager.Current()) + if err != nil { + ctx.Handle(500, "getter", err) + return + } + ctx.Data["Watchers"] = items + + ctx.HTML(200, WATCHERS) +} + +func Watchers(ctx *middleware.Context) { + ctx.Data["Title"] = ctx.Tr("repo.watchers") + ctx.Data["PageIsWatchers"] = true + renderItems(ctx, ctx.Repo.Repository.NumWatches, ctx.Repo.Repository.GetWatchers) +} + +func Stars(ctx *middleware.Context) { + ctx.Data["Title"] = ctx.Tr("repo.stargazers") + ctx.Data["PageIsStargazers"] = true + renderItems(ctx, ctx.Repo.Repository.NumStars, ctx.Repo.Repository.GetStargazers) +} + +func Forks(ctx *middleware.Context) { + ctx.Data["Title"] = ctx.Tr("repos.forks") + + forks, err := ctx.Repo.Repository.GetForks() + if err != nil { + ctx.Handle(500, "GetForks", err) + return + } + + for _, fork := range forks { + if err = fork.GetOwner(); err != nil { + ctx.Handle(500, "GetOwner", err) + return + } + } + ctx.Data["Forks"] = forks + + ctx.HTML(200, FORKS) +} diff --git a/routers/repo/watchers.go b/routers/repo/watchers.go deleted file mode 100644 index 8626fa23..00000000 --- a/routers/repo/watchers.go +++ /dev/null @@ -1,44 +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 repo - -import ( - "github.com/Unknwon/paginater" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/modules/base" - "github.com/gogits/gogs/modules/middleware" -) - -const ( - WATCHERS base.TplName = "repo/watchers" -) - -func Watchers(ctx *middleware.Context) { - ctx.Data["Title"] = ctx.Tr("repos.watches") - - page := ctx.QueryInt("page") - if page <= 0 { - page = 1 - } - - ctx.Data["Page"] = paginater.New(ctx.Repo.Repository.NumWatches, models.ItemsPerPage, page, 5) - - watchers, err := ctx.Repo.Repository.GetWatchers(ctx.QueryInt("page")) - - if err != nil { - ctx.Handle(500, "GetWatchers", err) - return - } - - if (ctx.QueryInt("page")-1)*models.ItemsPerPage > ctx.Repo.Repository.NumWatches { - ctx.Handle(404, "ctx.Repo.Repository.NumWatches", nil) - return - } - - ctx.Data["Watchers"] = watchers - - ctx.HTML(200, WATCHERS) -} diff --git a/routers/user/auth.go b/routers/user/auth.go index 8037f76f..54cbf447 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -7,7 +7,7 @@ package user import ( "net/url" - "github.com/macaron-contrib/captcha" + "github.com/go-macaron/captcha" "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/auth" diff --git a/routers/user/home.go b/routers/user/home.go index 8008889d..98033fc1 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -62,23 +62,21 @@ func Dashboard(ctx *middleware.Context) { return } - // Check context type. if !ctxUser.IsOrganization() { - // Normal user. - ctxUser = ctx.User - collaborates, err := ctx.User.GetAccessibleRepositories() + collaborateRepos, err := ctx.User.GetAccessibleRepositories() if err != nil { ctx.Handle(500, "GetAccessibleRepositories", err) return } - repositories := make([]*models.Repository, 0, len(collaborates)) - for repo := range collaborates { - repositories = append(repositories, repo) + for i := range collaborateRepos { + if err = collaborateRepos[i].GetOwner(); err != nil { + ctx.Handle(500, "GetOwner: "+collaborateRepos[i].Name, err) + return + } } - - ctx.Data["CollaborateCount"] = len(repositories) - ctx.Data["CollaborativeRepos"] = repositories + ctx.Data["CollaborateCount"] = len(collaborateRepos) + ctx.Data["CollaborativeRepos"] = collaborateRepos } repos, err := models.GetRepositories(ctxUser.Id, true) @@ -89,7 +87,7 @@ func Dashboard(ctx *middleware.Context) { ctx.Data["Repos"] = repos // Get mirror repositories. - mirrors := make([]*models.Repository, 0, len(repos)/2) + mirrors := make([]*models.Repository, 0, 5) for _, repo := range repos { if repo.IsMirror { if err = repo.GetMirror(); err != nil { @@ -111,6 +109,7 @@ func Dashboard(ctx *middleware.Context) { // Check access of private repositories. feeds := make([]*models.Action, 0, len(actions)) + unameAvatars := make(map[string]string) for _, act := range actions { if act.IsPrivate { // This prevents having to retrieve the repository for each action @@ -122,16 +121,22 @@ func Dashboard(ctx *middleware.Context) { } } - // FIXME: cache results? - u, err := models.GetUserByName(act.ActUserName) - if err != nil { - if models.IsErrUserNotExist(err) { - continue + + // Cache results to reduce queries. + _, ok := unameAvatars[act.ActUserName] + if !ok { + u, err := models.GetUserByName(act.ActUserName) + if err != nil { + if models.IsErrUserNotExist(err) { + continue + } + ctx.Handle(500, "GetUserByName", err) + return } - ctx.Handle(500, "GetUserByName", err) - return + unameAvatars[act.ActUserName] = u.AvatarLink() } - act.ActAvatar = u.AvatarLink() + + act.ActAvatar = unameAvatars[act.ActUserName] feeds = append(feeds, act) } ctx.Data["Feeds"] = feeds @@ -156,6 +161,7 @@ func Issues(ctx *middleware.Context) { // Organization does not have view type and filter mode. var ( viewType string + sortType = ctx.Query("sort") filterMode = models.FM_ALL assigneeID int64 posterID int64 @@ -248,6 +254,7 @@ func Issues(ctx *middleware.Context) { Page: page, IsClosed: isShowClosed, IsPull: isPullList, + SortType: sortType, }) if err != nil { ctx.Handle(500, "Issues: %v", err) @@ -276,6 +283,7 @@ func Issues(ctx *middleware.Context) { ctx.Data["IssueStats"] = issueStats ctx.Data["ViewType"] = viewType + ctx.Data["SortType"] = sortType ctx.Data["RepoID"] = repoID ctx.Data["IsShowClosed"] = isShowClosed if isShowClosed { @@ -299,7 +307,7 @@ func ShowSSHKeys(ctx *middleware.Context, uid int64) { buf.WriteString(keys[i].OmitEmail()) buf.WriteString("\n") } - ctx.RenderData(200, buf.Bytes()) + ctx.PlainText(200, buf.Bytes()) } func Profile(ctx *middleware.Context) { @@ -345,7 +353,7 @@ func Profile(ctx *middleware.Context) { ctx.Data["TabName"] = tab switch tab { case "activity": - actions, err := models.GetFeeds(u.Id, 0, false) + actions, err := models.GetFeeds(u.Id, 0, true) if err != nil { ctx.Handle(500, "GetFeeds", err) return |