aboutsummaryrefslogtreecommitdiff
path: root/routers
diff options
context:
space:
mode:
Diffstat (limited to 'routers')
-rw-r--r--routers/admin/admin.go2
-rw-r--r--routers/admin/notice.go2
-rw-r--r--routers/admin/users.go1
-rw-r--r--routers/api/v1/repo.go77
-rw-r--r--routers/api/v1/user.go2
-rw-r--r--routers/install.go9
-rw-r--r--routers/repo/commit.go85
-rw-r--r--routers/repo/forks.go37
-rw-r--r--routers/repo/http.go7
-rw-r--r--routers/repo/issue.go202
-rw-r--r--routers/repo/pull.go106
-rw-r--r--routers/repo/release.go82
-rw-r--r--routers/repo/repo.go62
-rw-r--r--routers/repo/setting.go14
-rw-r--r--routers/repo/stars.go44
-rw-r--r--routers/repo/view.go77
-rw-r--r--routers/repo/watchers.go44
-rw-r--r--routers/user/auth.go2
-rw-r--r--routers/user/home.go50
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