aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/web.go174
-rw-r--r--conf/locale/locale_en-US.ini2
-rw-r--r--conf/locale/locale_zh-CN.ini2
-rw-r--r--gogs.go2
-rw-r--r--models/release.go2
-rw-r--r--modules/base/template.go1
-rw-r--r--modules/git/commit.go8
-rw-r--r--modules/git/repo_commit.go57
-rw-r--r--modules/git/repo_tag.go8
-rw-r--r--modules/git/tree_blob.go13
-rw-r--r--modules/git/utils.go21
-rw-r--r--public/css/github.min.css (renamed from public/ng/css/github.min.css)0
-rw-r--r--public/img/avatar_default.jpgbin6951 -> 6238 bytes
-rw-r--r--public/img/favicon.bak.pngbin15949 -> 12737 bytes
-rw-r--r--public/img/gogs-lg.pngbin97926 -> 97903 bytes
-rw-r--r--public/ng/css/font-awesome.min.css4
-rw-r--r--public/ng/css/gogs.css6
-rw-r--r--routers/org/members.go6
-rw-r--r--routers/org/org.go36
-rw-r--r--routers/org/teams.go26
-rw-r--r--routers/repo/commit.go439
-rw-r--r--routers/repo/download.go73
-rw-r--r--routers/repo/issue.go2226
-rw-r--r--routers/repo/release.go434
-rw-r--r--routers/repo/repo.go184
-rw-r--r--routers/repo/setting.go718
-rw-r--r--routers/user/home.go23
-rw-r--r--routers/user/setting.go8
-rw-r--r--templates/.VERSION2
-rw-r--r--templates/admin/config.tmpl6
-rw-r--r--templates/ng/base/head.tmpl4
-rw-r--r--templates/repo/commits.tmpl2
-rw-r--r--templates/repo/diff.tmpl2
-rw-r--r--templates/repo/issue/list.tmpl2
-rw-r--r--templates/repo/issue/view.tmpl8
-rw-r--r--templates/status/401.tmpl6
-rw-r--r--templates/status/404.tmpl1
-rw-r--r--templates/user/dashboard/dashboard.tmpl49
-rw-r--r--templates/user/dashboard/repo_list.tmpl12
-rw-r--r--templates/user/issues.tmpl2
-rw-r--r--templates/user/profile.tmpl6
-rw-r--r--templates/user/settings/nav.tmpl1
-rw-r--r--templates/user/settings/orgs.tmpl18
43 files changed, 2347 insertions, 2247 deletions
diff --git a/cmd/web.go b/cmd/web.go
index 9329b61426..744614f6b7 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -30,7 +30,7 @@ import (
"github.com/gogits/gogs/routers/admin"
"github.com/gogits/gogs/routers/api/v1"
"github.com/gogits/gogs/routers/dev"
- // "github.com/gogits/gogs/routers/org"
+ "github.com/gogits/gogs/routers/org"
"github.com/gogits/gogs/routers/repo"
"github.com/gogits/gogs/routers/user"
)
@@ -101,8 +101,8 @@ func runWeb(*cli.Context) {
// Routers.
m.Get("/", ignSignIn, routers.Home)
- // m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
- // m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
+ m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
+ m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
m.Group("", func(r *macaron.Router) {
r.Get("/issues", user.Issues)
r.Get("/pulls", user.Pulls)
@@ -151,6 +151,7 @@ func runWeb(*cli.Context) {
r.Get("/ssh", user.SettingsSSHKeys)
r.Post("/ssh", bindIgnErr(auth.AddSSHKeyForm{}), user.SettingsSSHKeysPost)
r.Get("/social", user.SettingsSocial)
+ r.Get("/orgs", user.SettingsOrgs)
r.Route("/delete", "GET,POST", user.SettingsDelete)
})
}, reqSignIn)
@@ -173,8 +174,8 @@ func runWeb(*cli.Context) {
m.Group("/repo", func(r *macaron.Router) {
r.Get("/create", repo.Create)
r.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost)
- // r.Get("/migrate", repo.Migrate)
- // r.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
+ r.Get("/migrate", repo.Migrate)
+ r.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
}, reqSignIn)
adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})
@@ -210,91 +211,92 @@ func runWeb(*cli.Context) {
dev.RegisterDebugRoutes(m)
}
- // reqTrueOwner := middleware.RequireTrueOwner()
-
- // m.Group("/org", func(r *macaron.Router) {
- // r.Get("/create", org.New)
- // r.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.NewPost)
- // r.Get("/:org", org.Home)
- // r.Get("/:org/dashboard", org.Dashboard)
- // r.Get("/:org/members", org.Members)
-
- // r.Get("/:org/teams", org.Teams)
- // r.Get("/:org/teams/new", org.NewTeam)
- // r.Post("/:org/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost)
- // r.Get("/:org/teams/:team/edit", org.EditTeam)
-
- // r.Get("/:org/team/:team", org.SingleTeam)
-
- // r.Get("/:org/settings", org.Settings)
- // r.Post("/:org/settings", bindIgnErr(auth.OrgSettingForm{}), org.SettingsPost)
- // r.Post("/:org/settings/delete", org.DeletePost)
- // }, reqSignIn)
-
- // m.Group("/:username/:reponame", func(r *macaron.Router) {
- // r.Get("/settings", repo.Setting)
- // r.Post("/settings", bindIgnErr(auth.RepoSettingForm{}), repo.SettingPost)
-
- // m.Group("/settings", func(r *macaron.Router) {
- // r.Get("/collaboration", repo.Collaboration)
- // r.Post("/collaboration", repo.CollaborationPost)
- // r.Get("/hooks", repo.WebHooks)
- // r.Get("/hooks/add", repo.WebHooksAdd)
- // r.Post("/hooks/add", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksAddPost)
- // r.Get("/hooks/:id", repo.WebHooksEdit)
- // r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
- // })
- // }, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner)
-
- // m.Group("/:username/:reponame", func(r *macaron.Router) {
- // r.Get("/action/:action", repo.Action)
-
- // m.Group("/issues", func(r *macaron.Router) {
- // r.Get("/new", repo.CreateIssue)
- // r.Post("/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost)
- // r.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
- // r.Post("/:index/label", repo.UpdateIssueLabel)
- // r.Post("/:index/milestone", repo.UpdateIssueMilestone)
- // r.Post("/:index/assignee", repo.UpdateAssignee)
- // r.Get("/:index/attachment/:id", repo.IssueGetAttachment)
- // r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
- // r.Post("/labels/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
- // r.Post("/labels/delete", repo.DeleteLabel)
- // r.Get("/milestones", repo.Milestones)
- // r.Get("/milestones/new", repo.NewMilestone)
- // r.Post("/milestones/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
- // r.Get("/milestones/:index/edit", repo.UpdateMilestone)
- // r.Post("/milestones/:index/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.UpdateMilestonePost)
- // r.Get("/milestones/:index/:action", repo.UpdateMilestone)
- // })
-
- // r.Post("/comment/:action", repo.Comment)
- // r.Get("/releases/new", repo.NewRelease)
- // r.Get("/releases/edit/:tagname", repo.EditRelease)
- // }, reqSignIn, middleware.RepoAssignment(true))
-
- // m.Group("/:username/:reponame", func(r *macaron.Router) {
- // r.Post("/releases/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
- // r.Post("/releases/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
- // }, reqSignIn, middleware.RepoAssignment(true, true))
-
- // m.Group("/:username/:reponame", func(r *macaron.Router) {
- // r.Get("/issues", repo.Issues)
- // r.Get("/issues/:index", repo.ViewIssue)
- // r.Get("/pulls", repo.Pulls)
- // r.Get("/branches", repo.Branches)
- // }, ignSignIn, middleware.RepoAssignment(true))
+ reqTrueOwner := middleware.RequireTrueOwner()
+
+ // Organization routers.
+ m.Group("/org", func(r *macaron.Router) {
+ r.Get("/create", org.New)
+ r.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.NewPost)
+ r.Get("/:org", org.Home)
+ r.Get("/:org/dashboard", org.Dashboard)
+ r.Get("/:org/members", org.Members)
+
+ r.Get("/:org/teams", org.Teams)
+ r.Get("/:org/teams/new", org.NewTeam)
+ r.Post("/:org/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost)
+ r.Get("/:org/teams/:team/edit", org.EditTeam)
+
+ r.Get("/:org/team/:team", org.SingleTeam)
+
+ r.Get("/:org/settings", org.Settings)
+ r.Post("/:org/settings", bindIgnErr(auth.OrgSettingForm{}), org.SettingsPost)
+ r.Post("/:org/settings/delete", org.DeletePost)
+ }, reqSignIn)
+
+ m.Group("/:username/:reponame", func(r *macaron.Router) {
+ r.Get("/settings", repo.Setting)
+ r.Post("/settings", bindIgnErr(auth.RepoSettingForm{}), repo.SettingPost)
+
+ m.Group("/settings", func(r *macaron.Router) {
+ r.Get("/collaboration", repo.Collaboration)
+ r.Post("/collaboration", repo.CollaborationPost)
+ r.Get("/hooks", repo.WebHooks)
+ r.Get("/hooks/add", repo.WebHooksAdd)
+ r.Post("/hooks/add", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksAddPost)
+ r.Get("/hooks/:id", repo.WebHooksEdit)
+ r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
+ })
+ }, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner)
+
+ m.Group("/:username/:reponame", func(r *macaron.Router) {
+ // r.Get("/action/:action", repo.Action)
+
+ m.Group("/issues", func(r *macaron.Router) {
+ r.Get("/new", repo.CreateIssue)
+ r.Post("/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost)
+ r.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
+ r.Post("/:index/label", repo.UpdateIssueLabel)
+ r.Post("/:index/milestone", repo.UpdateIssueMilestone)
+ r.Post("/:index/assignee", repo.UpdateAssignee)
+ r.Get("/:index/attachment/:id", repo.IssueGetAttachment)
+ r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
+ r.Post("/labels/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
+ r.Post("/labels/delete", repo.DeleteLabel)
+ r.Get("/milestones", repo.Milestones)
+ r.Get("/milestones/new", repo.NewMilestone)
+ r.Post("/milestones/new", bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
+ r.Get("/milestones/:index/edit", repo.UpdateMilestone)
+ r.Post("/milestones/:index/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.UpdateMilestonePost)
+ r.Get("/milestones/:index/:action", repo.UpdateMilestone)
+ })
+
+ r.Post("/comment/:action", repo.Comment)
+ r.Get("/releases/new", repo.NewRelease)
+ r.Get("/releases/edit/:tagname", repo.EditRelease)
+ }, reqSignIn, middleware.RepoAssignment(true))
+
+ m.Group("/:username/:reponame", func(r *macaron.Router) {
+ r.Post("/releases/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
+ r.Post("/releases/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
+ }, reqSignIn, middleware.RepoAssignment(true, true))
+
+ m.Group("/:username/:reponame", func(r *macaron.Router) {
+ r.Get("/issues", repo.Issues)
+ r.Get("/issues/:index", repo.ViewIssue)
+ r.Get("/pulls", repo.Pulls)
+ r.Get("/branches", repo.Branches)
+ }, ignSignIn, middleware.RepoAssignment(true))
m.Group("/:username/:reponame", func(r *macaron.Router) {
r.Get("/src/:branchname", repo.Home)
r.Get("/src/:branchname/*", repo.Home)
- r.Get("/raw/:branchname/**", repo.SingleDownload)
- // r.Get("/commits/:branchname", repo.Commits)
- // r.Get("/commits/:branchname/search", repo.SearchCommits)
- // r.Get("/commits/:branchname/**", repo.FileHistory)
- // r.Get("/commit/:branchname", repo.Diff)
- // r.Get("/commit/:branchname/**", repo.Diff)
- // r.Get("/releases", repo.Releases)
+ r.Get("/raw/:branchname/*", repo.SingleDownload)
+ r.Get("/commits/:branchname", repo.Commits)
+ r.Get("/commits/:branchname/search", repo.SearchCommits)
+ r.Get("/commits/:branchname/*", repo.FileHistory)
+ r.Get("/commit/:branchname", repo.Diff)
+ r.Get("/commit/:branchname/*", repo.Diff)
+ r.Get("/releases", repo.Releases)
r.Get("/archive/*.*", repo.Download)
}, ignSignIn, middleware.RepoAssignment(true, true))
diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini
index b8832167ae..c673ca9f49 100644
--- a/conf/locale/locale_en-US.ini
+++ b/conf/locale/locale_en-US.ini
@@ -89,6 +89,7 @@ profile = Profile
password = Password
ssh_keys = SSH Keys
social = Social Accounts
+orgs = Organizations
delete = Delete Accoount
public_profile = Public Profile
@@ -118,6 +119,7 @@ add_on = Added on
last_used = Last used on
no_activity = No recent activity
+manage_orgs = Manage Organizations
manage_social = Manage Associated Social Accounts
delete_account = Delete Your Account
diff --git a/conf/locale/locale_zh-CN.ini b/conf/locale/locale_zh-CN.ini
index 30e683071e..ff542a374c 100644
--- a/conf/locale/locale_zh-CN.ini
+++ b/conf/locale/locale_zh-CN.ini
@@ -89,6 +89,7 @@ profile = 个人信息
password = 修改密码
ssh_keys = 管理 SSH 密钥
social = 社交帐号绑定
+orgs = 管理组织
delete = 删除帐户
public_profile = 公开信息
@@ -118,6 +119,7 @@ add_on = 增加于
last_used = 上次使用在
no_activity = 没有最近活动
+manage_orgs = 管理我的组织
manage_social = 管理关联社交帐户
delete_account = 删除当前帐户
diff --git a/gogs.go b/gogs.go
index e432d6bede..53f96e90f9 100644
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting"
)
-const APP_VER = "0.4.7.0725 Alpha"
+const APP_VER = "0.4.7.0726 Alpha"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/models/release.go b/models/release.go
index 3e1a78118c..012b6cc5c4 100644
--- a/models/release.go
+++ b/models/release.go
@@ -10,7 +10,7 @@ import (
"strings"
"time"
- "github.com/gogits/git"
+ "github.com/gogits/gogs/modules/git"
)
var (
diff --git a/modules/base/template.go b/modules/base/template.go
index 7589fdaafb..b9968bae65 100644
--- a/modules/base/template.go
+++ b/modules/base/template.go
@@ -106,7 +106,6 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
"CreateCaptcha": func() string { return "" },
}
-// TODO: Legacy
type Actioner interface {
GetOpType() int
GetActUserName() string
diff --git a/modules/git/commit.go b/modules/git/commit.go
index f61f2927b9..52348fefed 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -73,6 +73,14 @@ func (c *Commit) CommitsCount() (int, error) {
return c.repo.commitsCount(c.Id)
}
+func (c *Commit) SearchCommits(keyword string) (*list.List, error) {
+ return c.repo.searchCommits(c.Id, keyword)
+}
+
+func (c *Commit) CommitsByRange(page int) (*list.List, error) {
+ return c.repo.commitsByRange(c.Id, page)
+}
+
func (c *Commit) GetCommitOfRelPath(relPath string) (*Commit, error) {
return c.repo.getCommitOfRelPath(c.Id, relPath)
}
diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go
index b1ea5a29a5..0e39963e68 100644
--- a/modules/git/repo_commit.go
+++ b/modules/git/repo_commit.go
@@ -32,7 +32,18 @@ func (repo *Repository) GetCommitOfBranch(branchName string) (*Commit, error) {
if err != nil {
return nil, err
}
+ return repo.GetCommit(commitId)
+}
+
+func (repo *Repository) GetCommitIdOfTag(tagName string) (string, error) {
+ return repo.getCommitIdOfRef("refs/tags/" + tagName)
+}
+func (repo *Repository) GetCommitOfTag(tagName string) (*Commit, error) {
+ commitId, err := repo.GetCommitIdOfTag(tagName)
+ if err != nil {
+ return nil, err
+ }
return repo.GetCommit(commitId)
}
@@ -212,6 +223,32 @@ func (repo *Repository) commitsBefore(lock *sync.Mutex, l *list.List, parent *li
return nil
}
+func (repo *Repository) CommitsCount(commitId string) (int, error) {
+ id, err := NewIdFromString(commitId)
+ if err != nil {
+ return 0, err
+ }
+ return repo.commitsCount(id)
+}
+
+func (repo *Repository) FileCommitsCount(branch, file string) (int, error) {
+ stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count",
+ branch, "--", file)
+ if err != nil {
+ return 0, errors.New(stderr)
+ }
+ return com.StrTo(strings.TrimSpace(stdout)).Int()
+}
+
+func (repo *Repository) CommitsByFileAndRange(branch, file string, page int) (*list.List, error) {
+ stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", branch,
+ "--skip="+com.ToStr((page-1)*50), "--max-count=50", prettyLogFormat, "--", file)
+ if err != nil {
+ return nil, errors.New(string(stderr))
+ }
+ return parsePrettyFormatLog(repo, stdout)
+}
+
func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) {
l := list.New()
lock := new(sync.Mutex)
@@ -219,6 +256,26 @@ func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) {
return l, err
}
+func (repo *Repository) searchCommits(id sha1, keyword string) (*list.List, error) {
+ stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", id.String(), "-100",
+ "-i", "--grep="+keyword, prettyLogFormat)
+ if err != nil {
+ return nil, err
+ } else if len(stderr) > 0 {
+ return nil, errors.New(string(stderr))
+ }
+ return parsePrettyFormatLog(repo, stdout)
+}
+
+func (repo *Repository) commitsByRange(id sha1, page int) (*list.List, error) {
+ stdout, stderr, err := com.ExecCmdDirBytes(repo.Path, "git", "log", id.String(),
+ "--skip="+com.ToStr((page-1)*50), "--max-count=50", prettyLogFormat)
+ if err != nil {
+ return nil, errors.New(string(stderr))
+ }
+ return parsePrettyFormatLog(repo, stdout)
+}
+
func (repo *Repository) getCommitOfRelPath(id sha1, relPath string) (*Commit, error) {
stdout, _, err := com.ExecCmdDir(repo.Path, "git", "log", "-1", prettyLogFormat, id.String(), "--", relPath)
if err != nil {
diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go
index cefbe783ab..21818f3e6b 100644
--- a/modules/git/repo_tag.go
+++ b/modules/git/repo_tag.go
@@ -30,6 +30,14 @@ func (repo *Repository) GetTags() ([]string, error) {
return tags[:len(tags)-1], nil
}
+func (repo *Repository) CreateTag(tagName, idStr string) error {
+ _, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", tagName, idStr)
+ if err != nil {
+ return errors.New(stderr)
+ }
+ return nil
+}
+
func (repo *Repository) getTag(id sha1) (*Tag, error) {
if repo.tagCache != nil {
if t, ok := repo.tagCache[id]; ok {
diff --git a/modules/git/tree_blob.go b/modules/git/tree_blob.go
index debc722bc9..f996aba376 100644
--- a/modules/git/tree_blob.go
+++ b/modules/git/tree_blob.go
@@ -44,3 +44,16 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
}
return nil, fmt.Errorf("GetTreeEntryByPath: %v", ErrNotExist)
}
+
+func (t *Tree) GetBlobByPath(rpath string) (*Blob, error) {
+ entry, err := t.GetTreeEntryByPath(rpath)
+ if err != nil {
+ return nil, err
+ }
+
+ if !entry.IsDir() {
+ return entry.Blob(), nil
+ }
+
+ return nil, ErrNotExist
+}
diff --git a/modules/git/utils.go b/modules/git/utils.go
index 3c0c60f235..26eef23191 100644
--- a/modules/git/utils.go
+++ b/modules/git/utils.go
@@ -5,12 +5,33 @@
package git
import (
+ "bytes"
+ "container/list"
"path/filepath"
"strings"
)
const prettyLogFormat = `--pretty=format:%H`
+func parsePrettyFormatLog(repo *Repository, logByts []byte) (*list.List, error) {
+ l := list.New()
+ if len(logByts) == 0 {
+ return l, nil
+ }
+
+ parts := bytes.Split(logByts, []byte{'\n'})
+
+ for _, commitId := range parts {
+ commit, err := repo.GetCommit(string(commitId))
+ if err != nil {
+ return nil, err
+ }
+ l.PushBack(commit)
+ }
+
+ return l, nil
+}
+
func RefEndName(refStr string) string {
index := strings.LastIndex(refStr, "/")
if index != -1 {
diff --git a/public/ng/css/github.min.css b/public/css/github.min.css
index 7b3600c93b..7b3600c93b 100644
--- a/public/ng/css/github.min.css
+++ b/public/css/github.min.css
diff --git a/public/img/avatar_default.jpg b/public/img/avatar_default.jpg
index 728ec5af6c..f97aaaf041 100644
--- a/public/img/avatar_default.jpg
+++ b/public/img/avatar_default.jpg
Binary files differ
diff --git a/public/img/favicon.bak.png b/public/img/favicon.bak.png
index ba9bd03756..33d8f1cd21 100644
--- a/public/img/favicon.bak.png
+++ b/public/img/favicon.bak.png
Binary files differ
diff --git a/public/img/gogs-lg.png b/public/img/gogs-lg.png
index 384a58d20f..fde06eb2b0 100644
--- a/public/img/gogs-lg.png
+++ b/public/img/gogs-lg.png
Binary files differ
diff --git a/public/ng/css/font-awesome.min.css b/public/ng/css/font-awesome.min.css
deleted file mode 100644
index 3d920fc87c..0000000000
--- a/public/ng/css/font-awesome.min.css
+++ /dev/null
@@ -1,4 +0,0 @@
-/*!
- * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome
- * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
- */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.1.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-square:before,.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"} \ No newline at end of file
diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css
index 7afba6b628..96cf77a639 100644
--- a/public/ng/css/gogs.css
+++ b/public/ng/css/gogs.css
@@ -373,7 +373,7 @@ img.avatar-30 {
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
- margin-right: 8px;
+ margin-left: 30px;
}
.markdown a span.octicon-link {
opacity: 0;
@@ -1058,6 +1058,9 @@ The register and sign-in page style
}
#repo-bare-start pre {
margin: 0 40px;
+ padding: 6px 10px;
+ border: 1px solid #ddd;
+ background: #f8f8f8;
}
.repo-bare #repo-bare-start h2 {
margin-top: 30px;
@@ -1073,6 +1076,7 @@ The register and sign-in page style
margin-right: 200px;
}
.repo-bare #repo-clone-help {
+ clear: both;
width: 100%;
}
.repo-bare #repo-clone-url {
diff --git a/routers/org/members.go b/routers/org/members.go
index c6f49b14bd..ac278d4e6d 100644
--- a/routers/org/members.go
+++ b/routers/org/members.go
@@ -5,12 +5,10 @@
package org
import (
- "github.com/go-martini/martini"
-
"github.com/gogits/gogs/modules/middleware"
)
-func Members(ctx *middleware.Context, params martini.Params) {
- ctx.Data["Title"] = "Organization " + params["org"] + " Members"
+func Members(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Organization " + ctx.Params(":org") + " Members"
ctx.HTML(200, "org/members")
}
diff --git a/routers/org/org.go b/routers/org/org.go
index 4c8854974d..74527d6008 100644
--- a/routers/org/org.go
+++ b/routers/org/org.go
@@ -5,9 +5,7 @@
package org
import (
- "github.com/go-martini/martini"
-
- "github.com/gogits/gogs-ng/models"
+ "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
@@ -21,10 +19,10 @@ const (
SETTINGS base.TplName = "org/settings"
)
-func Home(ctx *middleware.Context, params martini.Params) {
- ctx.Data["Title"] = "Organization " + params["org"]
+func Home(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Organization " + ctx.Params(":org")
- org, err := models.GetUserByName(params["org"])
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.Home(GetUserByName)", err)
@@ -99,12 +97,12 @@ func NewPost(ctx *middleware.Context, form auth.CreateOrgForm) {
ctx.Redirect("/org/" + form.OrgName + "/dashboard")
}
-func Dashboard(ctx *middleware.Context, params martini.Params) {
+func Dashboard(ctx *middleware.Context) {
ctx.Data["Title"] = "Dashboard"
ctx.Data["PageIsUserDashboard"] = true
ctx.Data["PageIsOrgDashboard"] = true
- org, err := models.GetUserByName(params["org"])
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.Dashboard(GetUserByName)", err)
@@ -114,11 +112,11 @@ func Dashboard(ctx *middleware.Context, params martini.Params) {
return
}
- // if err := ctx.User.GetOrganizations(); err != nil {
- // ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
- // return
- // }
- // ctx.Data["Orgs"] = ctx.User.Orgs
+ if err := ctx.User.GetOrganizations(); err != nil {
+ ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+ return
+ }
+ ctx.Data["Orgs"] = ctx.User.Orgs
ctx.Data["ContextUser"] = org
ctx.Data["MyRepos"], err = models.GetRepositories(org.Id, true)
@@ -137,10 +135,10 @@ func Dashboard(ctx *middleware.Context, params martini.Params) {
ctx.HTML(200, user.DASHBOARD)
}
-func Settings(ctx *middleware.Context, params martini.Params) {
+func Settings(ctx *middleware.Context) {
ctx.Data["Title"] = "Settings"
- org, err := models.GetUserByName(params["org"])
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.Settings(GetUserByName)", err)
@@ -154,10 +152,10 @@ func Settings(ctx *middleware.Context, params martini.Params) {
ctx.HTML(200, SETTINGS)
}
-func SettingsPost(ctx *middleware.Context, params martini.Params, form auth.OrgSettingForm) {
+func SettingsPost(ctx *middleware.Context, form auth.OrgSettingForm) {
ctx.Data["Title"] = "Settings"
- org, err := models.GetUserByName(params["org"])
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.SettingsPost(GetUserByName)", err)
@@ -187,10 +185,10 @@ func SettingsPost(ctx *middleware.Context, params martini.Params, form auth.OrgS
ctx.Redirect("/org/" + org.Name + "/settings")
}
-func DeletePost(ctx *middleware.Context, params martini.Params) {
+func DeletePost(ctx *middleware.Context) {
ctx.Data["Title"] = "Settings"
- org, err := models.GetUserByName(params["org"])
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.DeletePost(GetUserByName)", err)
diff --git a/routers/org/teams.go b/routers/org/teams.go
index 0b17f46368..d494ddc04d 100644
--- a/routers/org/teams.go
+++ b/routers/org/teams.go
@@ -5,8 +5,6 @@
package org
import (
- "github.com/go-martini/martini"
-
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
@@ -19,10 +17,10 @@ const (
TEAM_NEW base.TplName = "org/team_new"
)
-func Teams(ctx *middleware.Context, params martini.Params) {
- ctx.Data["Title"] = "Organization " + params["org"] + " Teams"
+func Teams(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Organization " + ctx.Params(":org") + " Teams"
- org, err := models.GetUserByName(params["org"])
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.Teams(GetUserByName)", err)
@@ -48,8 +46,8 @@ func Teams(ctx *middleware.Context, params martini.Params) {
ctx.HTML(200, TEAMS)
}
-func NewTeam(ctx *middleware.Context, params martini.Params) {
- org, err := models.GetUserByName(params["org"])
+func NewTeam(ctx *middleware.Context) {
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.NewTeam(GetUserByName)", err)
@@ -69,8 +67,8 @@ func NewTeam(ctx *middleware.Context, params martini.Params) {
ctx.HTML(200, TEAM_NEW)
}
-func NewTeamPost(ctx *middleware.Context, params martini.Params, form auth.CreateTeamForm) {
- org, err := models.GetUserByName(params["org"])
+func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
+ org, err := models.GetUserByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Handle(404, "org.NewTeamPost(GetUserByName)", err)
@@ -125,12 +123,12 @@ func NewTeamPost(ctx *middleware.Context, params martini.Params, form auth.Creat
ctx.Redirect("/org/" + org.LowerName + "/teams/" + t.LowerName)
}
-func EditTeam(ctx *middleware.Context, params martini.Params) {
- ctx.Data["Title"] = "Organization " + params["org"] + " Edit Team"
+func EditTeam(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Organization " + ctx.Params(":org") + " Edit Team"
ctx.HTML(200, "org/edit_team")
}
-func SingleTeam(ctx *middleware.Context,params martini.Params){
- ctx.Data["Title"] = "single-team"+params["org"]
- ctx.HTML(200,"org/team")
+func SingleTeam(ctx *middleware.Context) {
+ ctx.Data["Title"] = "single-team" + ctx.Params(":org")
+ ctx.HTML(200, "org/team")
}
diff --git a/routers/repo/commit.go b/routers/repo/commit.go
index 71b483823b..6320123b40 100644
--- a/routers/repo/commit.go
+++ b/routers/repo/commit.go
@@ -4,224 +4,221 @@
package repo
-// import (
-// "path"
-
-// "github.com/Unknwon/com"
-// "github.com/go-martini/martini"
-
-// "github.com/gogits/gogs/models"
-// "github.com/gogits/gogs/modules/base"
-// "github.com/gogits/gogs/modules/middleware"
-// )
-
-// const (
-// COMMITS base.TplName = "repo/commits"
-// DIFF base.TplName = "repo/diff"
-// )
-
-// func Commits(ctx *middleware.Context, params martini.Params) {
-// ctx.Data["IsRepoToolbarCommits"] = true
-
-// userName := ctx.Repo.Owner.Name
-// repoName := ctx.Repo.Repository.Name
-
-// brs, err := ctx.Repo.GitRepo.GetBranches()
-// if err != nil {
-// ctx.Handle(500, "repo.Commits(GetBranches)", err)
-// return
-// } else if len(brs) == 0 {
-// ctx.Handle(404, "repo.Commits(GetBranches)", nil)
-// return
-// }
-
-// commitsCount, err := ctx.Repo.Commit.CommitsCount()
-// if err != nil {
-// ctx.Handle(500, "repo.Commits(GetCommitsCount)", err)
-// return
-// }
-
-// // Calculate and validate page number.
-// page, _ := com.StrTo(ctx.Query("p")).Int()
-// if page < 1 {
-// page = 1
-// }
-// lastPage := page - 1
-// if lastPage < 0 {
-// lastPage = 0
-// }
-// nextPage := page + 1
-// if nextPage*50 > commitsCount {
-// nextPage = 0
-// }
-
-// // Both `git log branchName` and `git log commitId` work.
-// // ctx.Data["Commits"], err = ctx.Repo.Commit.CommitsByRange(page)
-// // if err != nil {
-// // ctx.Handle(500, "repo.Commits(CommitsByRange)", err)
-// // return
-// // }
-
-// ctx.Data["Username"] = userName
-// ctx.Data["Reponame"] = repoName
-// ctx.Data["CommitCount"] = commitsCount
-// ctx.Data["LastPageNum"] = lastPage
-// ctx.Data["NextPageNum"] = nextPage
-// ctx.HTML(200, COMMITS)
-// }
-
-// func SearchCommits(ctx *middleware.Context, params martini.Params) {
-// ctx.Data["IsSearchPage"] = true
-// ctx.Data["IsRepoToolbarCommits"] = true
-
-// keyword := ctx.Query("q")
-// if len(keyword) == 0 {
-// ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchName)
-// return
-// }
-
-// userName := params["username"]
-// repoName := params["reponame"]
-
-// brs, err := ctx.Repo.GitRepo.GetBranches()
-// if err != nil {
-// ctx.Handle(500, "repo.SearchCommits(GetBranches)", err)
-// return
-// } else if len(brs) == 0 {
-// ctx.Handle(404, "repo.SearchCommits(GetBranches)", nil)
-// return
-// }
-
-// // commits, err := ctx.Repo.Commit.SearchCommits(keyword)
-// // if err != nil {
-// // ctx.Handle(500, "repo.SearchCommits(SearchCommits)", err)
-// // return
-// // }
-
-// ctx.Data["Keyword"] = keyword
-// ctx.Data["Username"] = userName
-// ctx.Data["Reponame"] = repoName
-// // ctx.Data["CommitCount"] = commits.Len()
-// // ctx.Data["Commits"] = commits
-// ctx.HTML(200, COMMITS)
-// }
-
-// func Diff(ctx *middleware.Context, params martini.Params) {
-// ctx.Data["IsRepoToolbarCommits"] = true
-
-// userName := ctx.Repo.Owner.Name
-// repoName := ctx.Repo.Repository.Name
-// commitId := ctx.Repo.CommitId
-
-// commit := ctx.Repo.Commit
-
-// diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
-// if err != nil {
-// ctx.Handle(404, "repo.Diff(GetDiff)", err)
-// return
-// }
-
-// isImageFile := func(name string) bool {
-// // blob, err := ctx.Repo.Commit.GetBlobByPath(name)
-// // if err != nil {
-// // return false
-// // }
-
-// // dataRc, err := blob.Data()
-// // if err != nil {
-// // return false
-// // }
-// // buf := make([]byte, 1024)
-// // n, _ := dataRc.Read(buf)
-// // if n > 0 {
-// // buf = buf[:n]
-// // }
-// // dataRc.Close()
-// // _, isImage := base.IsImageFile(buf)
-// // return isImage
-// return false
-// }
-
-// parents := make([]string, commit.ParentCount())
-// for i := 0; i < commit.ParentCount(); i++ {
-// sha, err := commit.ParentId(i)
-// parents[i] = sha.String()
-// if err != nil {
-// ctx.Handle(404, "repo.Diff", err)
-// return
-// }
-// }
-
-// ctx.Data["Username"] = userName
-// ctx.Data["Reponame"] = repoName
-// ctx.Data["IsImageFile"] = isImageFile
-// ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
-// ctx.Data["Commit"] = commit
-// ctx.Data["Diff"] = diff
-// ctx.Data["Parents"] = parents
-// ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
-// ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
-// ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId)
-// ctx.HTML(200, DIFF)
-// }
-
-// func FileHistory(ctx *middleware.Context, params martini.Params) {
-// ctx.Data["IsRepoToolbarCommits"] = true
-
-// fileName := params["_1"]
-// if len(fileName) == 0 {
-// Commits(ctx, params)
-// return
-// }
-
-// userName := ctx.Repo.Owner.Name
-// repoName := ctx.Repo.Repository.Name
-// branchName := params["branchname"]
-
-// brs, err := ctx.Repo.GitRepo.GetBranches()
-// if err != nil {
-// ctx.Handle(500, "repo.FileHistory", err)
-// return
-// } else if len(brs) == 0 {
-// ctx.Handle(404, "repo.FileHistory", nil)
-// return
-// }
-
-// // commitsCount, err := ctx.Repo.GitRepo.FileCommitsCount(branchName, fileName)
-// // if err != nil {
-// // ctx.Handle(500, "repo.FileHistory(GetCommitsCount)", err)
-// // return
-// // } else if commitsCount == 0 {
-// // ctx.Handle(404, "repo.FileHistory", nil)
-// // return
-// // }
-
-// // Calculate and validate page number.
-// // page, _ := base.StrTo(ctx.Query("p")).Int()
-// // if page < 1 {
-// // page = 1
-// // }
-// // lastPage := page - 1
-// // if lastPage < 0 {
-// // lastPage = 0
-// // }
-// // nextPage := page + 1
-// // if nextPage*50 > commitsCount {
-// // nextPage = 0
-// // }
-
-// // ctx.Data["Commits"], err = ctx.Repo.GitRepo.CommitsByFileAndRange(
-// // branchName, fileName, page)
-// // if err != nil {
-// // ctx.Handle(500, "repo.FileHistory(CommitsByRange)", err)
-// // return
-// // }
-
-// ctx.Data["Username"] = userName
-// ctx.Data["Reponame"] = repoName
-// ctx.Data["FileName"] = fileName
-// // ctx.Data["CommitCount"] = commitsCount
-// // ctx.Data["LastPageNum"] = lastPage
-// // ctx.Data["NextPageNum"] = nextPage
-// ctx.HTML(200, COMMITS)
-// }
+import (
+ "path"
+
+ "github.com/Unknwon/com"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+const (
+ COMMITS base.TplName = "repo/commits"
+ DIFF base.TplName = "repo/diff"
+)
+
+func Commits(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarCommits"] = 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)
+ return
+ }
+
+ // Calculate and validate page number.
+ page, _ := com.StrTo(ctx.Query("p")).Int()
+ if page < 1 {
+ page = 1
+ }
+ lastPage := page - 1
+ if lastPage < 0 {
+ lastPage = 0
+ }
+ nextPage := page + 1
+ if nextPage*50 > commitsCount {
+ nextPage = 0
+ }
+
+ // Both `git log branchName` and `git log commitId` work.
+ ctx.Data["Commits"], err = ctx.Repo.Commit.CommitsByRange(page)
+ if err != nil {
+ ctx.Handle(500, "CommitsByRange", err)
+ return
+ }
+
+ ctx.Data["Username"] = userName
+ ctx.Data["Reponame"] = repoName
+ ctx.Data["CommitCount"] = commitsCount
+ ctx.Data["LastPageNum"] = lastPage
+ ctx.Data["NextPageNum"] = nextPage
+ ctx.HTML(200, COMMITS)
+}
+
+func SearchCommits(ctx *middleware.Context) {
+ ctx.Data["IsSearchPage"] = true
+ ctx.Data["IsRepoToolbarCommits"] = true
+
+ keyword := ctx.Query("q")
+ if len(keyword) == 0 {
+ ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchName)
+ 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, "repo.SearchCommits(SearchCommits)", err)
+ return
+ }
+
+ ctx.Data["Keyword"] = keyword
+ ctx.Data["Username"] = userName
+ ctx.Data["Reponame"] = repoName
+ ctx.Data["CommitCount"] = commits.Len()
+ ctx.Data["Commits"] = commits
+ ctx.HTML(200, COMMITS)
+}
+
+func Diff(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarCommits"] = true
+
+ userName := ctx.Repo.Owner.Name
+ repoName := ctx.Repo.Repository.Name
+ commitId := ctx.Repo.CommitId
+
+ commit := ctx.Repo.Commit
+
+ diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
+ if err != nil {
+ ctx.Handle(404, "GetDiff", err)
+ return
+ }
+
+ isImageFile := func(name string) bool {
+ blob, err := ctx.Repo.Commit.GetBlobByPath(name)
+ if err != nil {
+ return false
+ }
+
+ dataRc, err := blob.Data()
+ if err != nil {
+ return false
+ }
+ buf := make([]byte, 1024)
+ n, _ := dataRc.Read(buf)
+ if n > 0 {
+ buf = buf[:n]
+ }
+ _, isImage := base.IsImageFile(buf)
+ return isImage
+ }
+
+ parents := make([]string, commit.ParentCount())
+ for i := 0; i < commit.ParentCount(); i++ {
+ sha, err := commit.ParentId(i)
+ parents[i] = sha.String()
+ if err != nil {
+ ctx.Handle(404, "repo.Diff", err)
+ return
+ }
+ }
+
+ ctx.Data["Username"] = userName
+ ctx.Data["Reponame"] = repoName
+ ctx.Data["IsImageFile"] = isImageFile
+ ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
+ ctx.Data["Commit"] = commit
+ ctx.Data["Diff"] = diff
+ ctx.Data["Parents"] = parents
+ ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
+ ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
+ ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId)
+ ctx.HTML(200, DIFF)
+}
+
+func FileHistory(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarCommits"] = true
+
+ fileName := ctx.Params("*")
+ if len(fileName) == 0 {
+ Commits(ctx)
+ return
+ }
+
+ userName := ctx.Repo.Owner.Name
+ repoName := ctx.Repo.Repository.Name
+ branchName := ctx.Params(":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)
+ return
+ } else if commitsCount == 0 {
+ ctx.Handle(404, "repo.FileHistory", nil)
+ return
+ }
+
+ // Calculate and validate page number.
+ page := com.StrTo(ctx.Query("p")).MustInt()
+ if page < 1 {
+ page = 1
+ }
+ lastPage := page - 1
+ if lastPage < 0 {
+ lastPage = 0
+ }
+ nextPage := page + 1
+ if nextPage*50 > commitsCount {
+ nextPage = 0
+ }
+
+ ctx.Data["Commits"], err = ctx.Repo.GitRepo.CommitsByFileAndRange(
+ branchName, fileName, page)
+ if err != nil {
+ ctx.Handle(500, "repo.FileHistory(CommitsByRange)", err)
+ return
+ }
+
+ ctx.Data["Username"] = userName
+ ctx.Data["Reponame"] = repoName
+ ctx.Data["FileName"] = fileName
+ ctx.Data["CommitCount"] = commitsCount
+ ctx.Data["LastPageNum"] = lastPage
+ ctx.Data["NextPageNum"] = nextPage
+ ctx.HTML(200, COMMITS)
+}
diff --git a/routers/repo/download.go b/routers/repo/download.go
index 42bce2b1ff..abb9b06292 100644
--- a/routers/repo/download.go
+++ b/routers/repo/download.go
@@ -5,50 +5,41 @@
package repo
import (
- // "io"
- // "os"
- // "path/filepath"
+ "io"
+ "path"
- // "github.com/Unknwon/com"
-
- // "github.com/gogits/git"
-
- // "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
)
func SingleDownload(ctx *middleware.Context) {
- // treename := params["_1"]
-
- // blob, err := ctx.Repo.Commit.GetBlobByPath(treename)
- // if err != nil {
- // ctx.Handle(500, "repo.SingleDownload(GetBlobByPath)", err)
- // return
- // }
-
- // dataRc, err := blob.Data()
- // if err != nil {
- // ctx.Handle(500, "repo.SingleDownload(Data)", err)
- // return
- // }
-
- // buf := make([]byte, 1024)
- // n, _ := dataRc.Read(buf)
- // if n > 0 {
- // buf = buf[:n]
- // }
-
- // defer func() {
- // dataRc.Close()
- // }()
-
- // contentType, isTextFile := base.IsTextFile(buf)
- // _, isImageFile := base.IsImageFile(buf)
- // ctx.Res.Header().Set("Content-Type", contentType)
- // if !isTextFile && !isImageFile {
- // ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(treename))
- // ctx.Res.Header().Set("Content-Transfer-Encoding", "binary")
- // }
- // ctx.Res.Write(buf)
- // io.Copy(ctx.Res, dataRc)
+ treename := ctx.Params("*")
+
+ blob, err := ctx.Repo.Commit.GetBlobByPath(treename)
+ if err != nil {
+ ctx.Handle(500, "GetBlobByPath", err)
+ return
+ }
+
+ dataRc, err := blob.Data()
+ if err != nil {
+ ctx.Handle(500, "repo.SingleDownload(Data)", err)
+ return
+ }
+
+ buf := make([]byte, 1024)
+ n, _ := dataRc.Read(buf)
+ if n > 0 {
+ buf = buf[:n]
+ }
+
+ contentType, isTextFile := base.IsTextFile(buf)
+ _, isImageFile := base.IsImageFile(buf)
+ ctx.Resp.Header().Set("Content-Type", contentType)
+ if !isTextFile && !isImageFile {
+ ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+path.Base(treename))
+ ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
+ }
+ ctx.Resp.Write(buf)
+ io.Copy(ctx.Resp, dataRc)
}
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 005596bdeb..ab9b2b646e 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -4,1114 +4,1118 @@
package repo
-// import (
-// "errors"
-// // "fmt"
-// // "io"
-// // "io/ioutil"
-// // "mime"
-// "net/url"
-// // "strings"
-// // "time"
-
-// "github.com/Unknwon/com"
-// "github.com/go-martini/martini"
-
-// // "github.com/gogits/gogs-ng/models"
-// "github.com/gogits/gogs/modules/auth"
-// "github.com/gogits/gogs/modules/base"
-// // "github.com/gogits/gogs/modules/log"
-// // "github.com/gogits/gogs/modules/mailer"
-// "github.com/gogits/gogs/modules/middleware"
-// // "github.com/gogits/gogs/modules/setting"
-// )
-
-// const (
-// ISSUES base.TplName = "repo/issue/list"
-// ISSUE_CREATE base.TplName = "repo/issue/create"
-// ISSUE_VIEW base.TplName = "repo/issue/view"
-
-// MILESTONE base.TplName = "repo/issue/milestone"
-// MILESTONE_NEW base.TplName = "repo/issue/milestone_new"
-// MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit"
-// )
-
-// var (
-// ErrFileTypeForbidden = errors.New("File type is not allowed")
-// ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded")
-// )
-
-// func Issues(ctx *middleware.Context) {
-// ctx.Data["Title"] = "Issues"
-// ctx.Data["IsRepoToolbarIssues"] = true
-// ctx.Data["IsRepoToolbarIssuesList"] = true
-
-// viewType := ctx.Query("type")
-// types := []string{"assigned", "created_by", "mentioned"}
-// if !com.IsSliceContainsStr(types, viewType) {
-// viewType = "all"
-// }
-
-// isShowClosed := ctx.Query("state") == "closed"
-
-// if viewType != "all" && !ctx.IsSigned {
-// ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
-// ctx.Redirect("/user/login")
-// return
-// }
-
-// // var assigneeId, posterId int64
-// // var filterMode int
-// // switch viewType {
-// // case "assigned":
-// // assigneeId = ctx.User.Id
-// // filterMode = models.FM_ASSIGN
-// // case "created_by":
-// // posterId = ctx.User.Id
-// // filterMode = models.FM_CREATE
-// // case "mentioned":
-// // filterMode = models.FM_MENTION
-// // }
-
-// // var mid int64
-// // midx, _ := com.StrTo(ctx.Query("milestone")).Int64()
-// // if midx > 0 {
-// // mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, midx)
-// // if err != nil {
-// // ctx.Handle(500, "issue.Issues(GetMilestoneByIndex): %v", err)
-// // return
-// // }
-// // mid = mile.Id
-// // }
-
-// // selectLabels := ctx.Query("labels")
-// // labels, err := models.GetLabels(ctx.Repo.Repository.Id)
-// // if err != nil {
-// // ctx.Handle(500, "issue.Issues(GetLabels): %v", err)
-// // return
-// // }
-// // for _, l := range labels {
-// // l.CalOpenIssues()
-// // }
-// // ctx.Data["Labels"] = labels
-
-// page, _ := com.StrTo(ctx.Query("page")).Int()
-
-// // Get issues.
-// // issues, err := models.GetIssues(assigneeId, ctx.Repo.Repository.Id, posterId, mid, page,
-// // isShowClosed, selectLabels, ctx.Query("sortType"))
-// // if err != nil {
-// // ctx.Handle(500, "issue.Issues(GetIssues): %v", err)
-// // return
-// // }
-
-// // Get issue-user pairs.
-// // pairs, err := models.GetIssueUserPairs(ctx.Repo.Repository.Id, posterId, isShowClosed)
-// // if err != nil {
-// // ctx.Handle(500, "issue.Issues(GetIssueUserPairs): %v", err)
-// // return
-// // }
-
-// // Get posters.
-// // for i := range issues {
-// // if err = issues[i].GetLabels(); err != nil {
-// // ctx.Handle(500, "issue.Issues(GetLabels)", fmt.Errorf("[#%d]%v", issues[i].Id, err))
-// // return
-// // }
-
-// // idx := models.PairsContains(pairs, issues[i].Id)
-
-// // if filterMode == models.FM_MENTION && (idx == -1 || !pairs[idx].IsMentioned) {
-// // continue
-// // }
-
-// // if idx > -1 {
-// // issues[i].IsRead = pairs[idx].IsRead
-// // } else {
-// // issues[i].IsRead = true
-// // }
-
-// // if err = issues[i].GetPoster(); err != nil {
-// // ctx.Handle(500, "issue.Issues(GetPoster)", fmt.Errorf("[#%d]%v", issues[i].Id, err))
-// // return
-// // }
-// // }
-
-// // var uid int64 = -1
-// // if ctx.User != nil {
-// // uid = ctx.User.Id
-// // }
-// // issueStats := models.GetIssueStats(ctx.Repo.Repository.Id, uid, isShowClosed, filterMode)
-// // ctx.Data["IssueStats"] = issueStats
-// // ctx.Data["SelectLabels"], _ = com.StrTo(selectLabels).Int64()
-// // ctx.Data["ViewType"] = viewType
-// // ctx.Data["Issues"] = issues
-// // ctx.Data["IsShowClosed"] = isShowClosed
-// // if isShowClosed {
-// // ctx.Data["State"] = "closed"
-// // ctx.Data["ShowCount"] = issueStats.ClosedCount
-// // } else {
-// // ctx.Data["ShowCount"] = issueStats.OpenCount
-// // }
-// // ctx.HTML(200, ISSUES)
-// }
-
-// func CreateIssue(ctx *middleware.Context, params martini.Params) {
-// // ctx.Data["Title"] = "Create issue"
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = false
-// // ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled
-
-// // var err error
-// // // Get all milestones.
-// // ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, false)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err)
-// // return
-// // }
-// // ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, true)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err)
-// // return
-// // }
-
-// // us, err := models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
-// // if err != nil {
-// // ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
-// // return
-// // }
-
-// // ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes
-// // ctx.Data["Collaborators"] = us
-
-// // ctx.HTML(200, ISSUE_CREATE)
-// }
-
-// func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
-// // send := func(status int, data interface{}, err error) {
-// // if err != nil {
-// // log.Error(4, "issue.CreateIssuePost(?): %s", err.Error())
-
-// // ctx.JSON(status, map[string]interface{}{
-// // "ok": false,
-// // "status": status,
-// // "error": err.Error(),
-// // })
-// // } else {
-// // ctx.JSON(status, map[string]interface{}{
-// // "ok": true,
-// // "status": status,
-// // "data": data,
-// // })
-// // }
-// // }
-
-// // var err error
-// // // Get all milestones.
-// // _, err = models.GetMilestones(ctx.Repo.Repository.Id, false)
-// // if err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-// // _, err = models.GetMilestones(ctx.Repo.Repository.Id, true)
-// // if err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // _, err = models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
-// // if err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // if ctx.HasError() {
-// // send(400, nil, errors.New(ctx.Flash.ErrorMsg))
-// // return
-// // }
-
-// // // Only collaborators can assign.
-// // if !ctx.Repo.IsOwner {
-// // form.AssigneeId = 0
-// // }
-// // issue := &models.Issue{
-// // RepoId: ctx.Repo.Repository.Id,
-// // Index: int64(ctx.Repo.Repository.NumIssues) + 1,
-// // Name: form.IssueName,
-// // PosterId: ctx.User.Id,
-// // MilestoneId: form.MilestoneId,
-// // AssigneeId: form.AssigneeId,
-// // LabelIds: form.Labels,
-// // Content: form.Content,
-// // }
-// // if err := models.NewIssue(issue); err != nil {
-// // send(500, nil, err)
-// // return
-// // } else if err := models.NewIssueUserPairs(issue.RepoId, issue.Id, ctx.Repo.Owner.Id,
-// // ctx.User.Id, form.AssigneeId, ctx.Repo.Repository.Name); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // if setting.AttachmentEnabled {
-// // uploadFiles(ctx, issue.Id, 0)
-// // }
-
-// // // Update mentions.
-// // ms := base.MentionPattern.FindAllString(issue.Content, -1)
-// // if len(ms) > 0 {
-// // for i := range ms {
-// // ms[i] = ms[i][1:]
-// // }
-
-// // if err := models.UpdateMentions(ms, issue.Id); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-// // }
-
-// // act := &models.Action{
-// // ActUserId: ctx.User.Id,
-// // ActUserName: ctx.User.Name,
-// // ActEmail: ctx.User.Email,
-// // OpType: models.OP_CREATE_ISSUE,
-// // Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
-// // RepoId: ctx.Repo.Repository.Id,
-// // RepoUserName: ctx.Repo.Owner.Name,
-// // RepoName: ctx.Repo.Repository.Name,
-// // RefName: ctx.Repo.BranchName,
-// // IsPrivate: ctx.Repo.Repository.IsPrivate,
-// // }
-// // // Notify watchers.
-// // if err := models.NotifyWatchers(act); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // // Mail watchers and mentions.
-// // if setting.Service.EnableNotifyMail {
-// // tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
-// // if err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // tos = append(tos, ctx.User.LowerName)
-// // newTos := make([]string, 0, len(ms))
-// // for _, m := range ms {
-// // 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 {
-// // send(500, nil, err)
-// // return
-// // }
-// // }
-// // log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id)
-
-// // send(200, fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index), nil)
-// }
-
-// // func checkLabels(labels, allLabels []*models.Label) {
-// // for _, l := range labels {
-// // for _, l2 := range allLabels {
-// // if l.Id == l2.Id {
-// // l2.IsChecked = true
-// // break
-// // }
-// // }
-// // }
-// // }
-
-// // func ViewIssue(ctx *middleware.Context, params martini.Params) {
-// // ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled
-
-// // idx, _ := base.StrTo(params["index"]).Int64()
-// // if idx == 0 {
-// // ctx.Handle(404, "issue.ViewIssue", nil)
-// // return
-// // }
-
-// // issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
-// // if err != nil {
-// // if err == models.ErrIssueNotExist {
-// // ctx.Handle(404, "issue.ViewIssue(GetIssueByIndex)", err)
-// // } else {
-// // ctx.Handle(500, "issue.ViewIssue(GetIssueByIndex)", err)
-// // }
-// // return
-// // }
-
-// // // Get labels.
-// // if err = issue.GetLabels(); err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetLabels)", err)
-// // return
-// // }
-// // labels, err := models.GetLabels(ctx.Repo.Repository.Id)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetLabels.2)", err)
-// // return
-// // }
-// // checkLabels(issue.Labels, labels)
-// // ctx.Data["Labels"] = labels
-
-// // // Get assigned milestone.
-// // if issue.MilestoneId > 0 {
-// // ctx.Data["Milestone"], err = models.GetMilestoneById(issue.MilestoneId)
-// // if err != nil {
-// // if err == models.ErrMilestoneNotExist {
-// // log.Warn("issue.ViewIssue(GetMilestoneById): %v", err)
-// // } else {
-// // ctx.Handle(500, "issue.ViewIssue(GetMilestoneById)", err)
-// // return
-// // }
-// // }
-// // }
-
-// // // Get all milestones.
-// // ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, false)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err)
-// // return
-// // }
-// // ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, true)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err)
-// // return
-// // }
-
-// // // Get all collaborators.
-// // ctx.Data["Collaborators"], err = models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
-// // if err != nil {
-// // ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
-// // return
-// // }
-
-// // if ctx.IsSigned {
-// // // Update issue-user.
-// // if err = models.UpdateIssueUserPairByRead(ctx.User.Id, issue.Id); err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(UpdateIssueUserPairByRead): %v", err)
-// // return
-// // }
-// // }
-
-// // // Get poster and Assignee.
-// // if err = issue.GetPoster(); err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetPoster): %v", err)
-// // return
-// // } else if err = issue.GetAssignee(); err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetAssignee): %v", err)
-// // return
-// // }
-// // issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
-
-// // // Get comments.
-// // comments, err := models.GetIssueComments(issue.Id)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetIssueComments): %v", err)
-// // return
-// // }
-
-// // // Get posters.
-// // for i := range comments {
-// // u, err := models.GetUserById(comments[i].PosterId)
-// // if err != nil {
-// // ctx.Handle(500, "issue.ViewIssue(GetUserById.2): %v", err)
-// // return
-// // }
-// // comments[i].Poster = u
-
-// // if comments[i].Type == models.COMMENT {
-// // comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink))
-// // }
-// // }
-
-// // ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes
-
-// // ctx.Data["Title"] = issue.Name
-// // ctx.Data["Issue"] = issue
-// // ctx.Data["Comments"] = comments
-// // ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = false
-// // ctx.HTML(200, ISSUE_VIEW)
-// // }
-
-// // func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
-// // idx, _ := base.StrTo(params["index"]).Int64()
-// // if idx <= 0 {
-// // ctx.Error(404)
-// // return
-// // }
-
-// // issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
-// // if err != nil {
-// // if err == models.ErrIssueNotExist {
-// // ctx.Handle(404, "issue.UpdateIssue", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateIssue(GetIssueByIndex)", err)
-// // }
-// // return
-// // }
-
-// // if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
-// // ctx.Error(403)
-// // return
-// // }
-
-// // issue.Name = form.IssueName
-// // issue.MilestoneId = form.MilestoneId
-// // issue.AssigneeId = form.AssigneeId
-// // issue.LabelIds = form.Labels
-// // issue.Content = form.Content
-// // // try get content from text, ignore conflict with preview ajax
-// // if form.Content == "" {
-// // issue.Content = ctx.Query("text")
-// // }
-// // if err = models.UpdateIssue(issue); err != nil {
-// // ctx.Handle(500, "issue.UpdateIssue(UpdateIssue)", err)
-// // return
-// // }
-
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // "title": issue.Name,
-// // "content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)),
-// // })
-// // }
-
-// // func UpdateIssueLabel(ctx *middleware.Context, params martini.Params) {
-// // if !ctx.Repo.IsOwner {
-// // ctx.Error(403)
-// // return
-// // }
-
-// // idx, _ := base.StrTo(params["index"]).Int64()
-// // if idx <= 0 {
-// // ctx.Error(404)
-// // return
-// // }
-
-// // issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
-// // if err != nil {
-// // if err == models.ErrIssueNotExist {
-// // ctx.Handle(404, "issue.UpdateIssueLabel(GetIssueByIndex)", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateIssueLabel(GetIssueByIndex)", err)
-// // }
-// // return
-// // }
-
-// // isAttach := ctx.Query("action") == "attach"
-// // labelStrId := ctx.Query("id")
-// // labelId, _ := base.StrTo(labelStrId).Int64()
-// // label, err := models.GetLabelById(labelId)
-// // if err != nil {
-// // if err == models.ErrLabelNotExist {
-// // ctx.Handle(404, "issue.UpdateIssueLabel(GetLabelById)", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateIssueLabel(GetLabelById)", err)
-// // }
-// // return
-// // }
-
-// // isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|")
-// // isNeedUpdate := false
-// // if isAttach {
-// // if !isHad {
-// // issue.LabelIds += "$" + labelStrId + "|"
-// // isNeedUpdate = true
-// // }
-// // } else {
-// // if isHad {
-// // issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1)
-// // isNeedUpdate = true
-// // }
-// // }
-
-// // if isNeedUpdate {
-// // if err = models.UpdateIssue(issue); err != nil {
-// // ctx.Handle(500, "issue.UpdateIssueLabel(UpdateIssue)", err)
-// // return
-// // }
-
-// // if isAttach {
-// // label.NumIssues++
-// // if issue.IsClosed {
-// // label.NumClosedIssues++
-// // }
-// // } else {
-// // label.NumIssues--
-// // if issue.IsClosed {
-// // label.NumClosedIssues--
-// // }
-// // }
-// // if err = models.UpdateLabel(label); err != nil {
-// // ctx.Handle(500, "issue.UpdateIssueLabel(UpdateLabel)", err)
-// // return
-// // }
-// // }
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // })
-// // }
-
-// // func UpdateIssueMilestone(ctx *middleware.Context) {
-// // if !ctx.Repo.IsOwner {
-// // ctx.Error(403)
-// // return
-// // }
-
-// // issueId, err := base.StrTo(ctx.Query("issue")).Int64()
-// // if err != nil {
-// // ctx.Error(404)
-// // return
-// // }
-
-// // issue, err := models.GetIssueById(issueId)
-// // if err != nil {
-// // if err == models.ErrIssueNotExist {
-// // ctx.Handle(404, "issue.UpdateIssueMilestone(GetIssueById)", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateIssueMilestone(GetIssueById)", err)
-// // }
-// // return
-// // }
-
-// // oldMid := issue.MilestoneId
-// // mid, _ := base.StrTo(ctx.Query("milestone")).Int64()
-// // if oldMid == mid {
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // })
-// // return
-// // }
-
-// // // Not check for invalid milestone id and give responsibility to owners.
-// // issue.MilestoneId = mid
-// // if err = models.ChangeMilestoneAssign(oldMid, mid, issue); err != nil {
-// // ctx.Handle(500, "issue.UpdateIssueMilestone(ChangeMilestoneAssign)", err)
-// // return
-// // } else if err = models.UpdateIssue(issue); err != nil {
-// // ctx.Handle(500, "issue.UpdateIssueMilestone(UpdateIssue)", err)
-// // return
-// // }
-
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // })
-// // }
-
-// // func UpdateAssignee(ctx *middleware.Context) {
-// // if !ctx.Repo.IsOwner {
-// // ctx.Error(403)
-// // return
-// // }
-
-// // issueId, err := base.StrTo(ctx.Query("issue")).Int64()
-// // if err != nil {
-// // ctx.Error(404)
-// // return
-// // }
-
-// // issue, err := models.GetIssueById(issueId)
-// // if err != nil {
-// // if err == models.ErrIssueNotExist {
-// // ctx.Handle(404, "issue.UpdateAssignee(GetIssueById)", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateAssignee(GetIssueById)", err)
-// // }
-// // return
-// // }
-
-// // aid, _ := base.StrTo(ctx.Query("assigneeid")).Int64()
-// // // Not check for invalid assignne id and give responsibility to owners.
-// // issue.AssigneeId = aid
-// // if err = models.UpdateIssueUserPairByAssignee(aid, issue.Id); err != nil {
-// // ctx.Handle(500, "issue.UpdateAssignee(UpdateIssueUserPairByAssignee): %v", err)
-// // return
-// // } else if err = models.UpdateIssue(issue); err != nil {
-// // ctx.Handle(500, "issue.UpdateAssignee(UpdateIssue)", err)
-// // return
-// // }
-
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // })
-// // }
-
-// // func uploadFiles(ctx *middleware.Context, issueId, commentId int64) {
-// // if !setting.AttachmentEnabled {
-// // return
-// // }
-
-// // allowedTypes := strings.Split(setting.AttachmentAllowedTypes, "|")
-// // attachments := ctx.Req.MultipartForm.File["attachments"]
-
-// // if len(attachments) > setting.AttachmentMaxFiles {
-// // ctx.Handle(400, "issue.Comment", ErrTooManyFiles)
-// // return
-// // }
-
-// // for _, header := range attachments {
-// // file, err := header.Open()
-
-// // if err != nil {
-// // ctx.Handle(500, "issue.Comment(header.Open)", err)
-// // return
-// // }
-
-// // defer file.Close()
-
-// // allowed := false
-// // fileType := mime.TypeByExtension(header.Filename)
-
-// // for _, t := range allowedTypes {
-// // t := strings.Trim(t, " ")
-
-// // if t == "*/*" || t == fileType {
-// // allowed = true
-// // break
-// // }
-// // }
-
-// // if !allowed {
-// // ctx.Handle(400, "issue.Comment", ErrFileTypeForbidden)
-// // return
-// // }
-
-// // out, err := ioutil.TempFile(setting.AttachmentPath, "attachment_")
-
-// // if err != nil {
-// // ctx.Handle(500, "issue.Comment(ioutil.TempFile)", err)
-// // return
-// // }
-
-// // defer out.Close()
-
-// // _, err = io.Copy(out, file)
-
-// // if err != nil {
-// // ctx.Handle(500, "issue.Comment(io.Copy)", err)
-// // return
-// // }
-
-// // _, err = models.CreateAttachment(issueId, commentId, header.Filename, out.Name())
-
-// // if err != nil {
-// // ctx.Handle(500, "issue.Comment(io.Copy)", err)
-// // return
-// // }
-// // }
-// // }
-
-// // func Comment(ctx *middleware.Context, params martini.Params) {
-// // send := func(status int, data interface{}, err error) {
-// // if err != nil {
-// // log.Error("issue.Comment(?): %s", err.Error())
-
-// // ctx.JSON(status, map[string]interface{}{
-// // "ok": false,
-// // "status": status,
-// // "error": err.Error(),
-// // })
-// // } else {
-// // ctx.JSON(status, map[string]interface{}{
-// // "ok": true,
-// // "status": status,
-// // "data": data,
-// // })
-// // }
-// // }
-
-// // index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
-// // if err != nil {
-// // send(404, nil, err)
-// // return
-// // }
-
-// // issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
-// // if err != nil {
-// // if err == models.ErrIssueNotExist {
-// // send(404, nil, err)
-// // } else {
-// // send(200, nil, err)
-// // }
-
-// // return
-// // }
-
-// // // Check if issue owner changes the status of issue.
-// // var newStatus string
-// // if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
-// // newStatus = ctx.Query("change_status")
-// // }
-// // if len(newStatus) > 0 {
-// // if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) ||
-// // (strings.Contains(newStatus, "Close") && !issue.IsClosed) {
-// // issue.IsClosed = !issue.IsClosed
-// // if err = models.UpdateIssue(issue); err != nil {
-// // send(500, nil, err)
-// // return
-// // } else if err = models.UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // // Change open/closed issue counter for the associated milestone
-// // if issue.MilestoneId > 0 {
-// // if err = models.ChangeMilestoneIssueStats(issue); err != nil {
-// // send(500, nil, err)
-// // }
-// // }
-
-// // cmtType := models.CLOSE
-// // if !issue.IsClosed {
-// // cmtType = models.REOPEN
-// // }
-
-// // if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, "", nil); err != nil {
-// // send(200, nil, err)
-// // return
-// // }
-// // log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed)
-// // }
-// // }
-
-// // var comment *models.Comment
-
-// // var ms []string
-// // content := ctx.Query("content")
-// // // Fix #321. Allow empty comments, as long as we have attachments.
-// // if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 {
-// // switch params["action"] {
-// // case "new":
-// // if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT, content, nil); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // // Update mentions.
-// // ms = base.MentionPattern.FindAllString(issue.Content, -1)
-// // if len(ms) > 0 {
-// // for i := range ms {
-// // ms[i] = ms[i][1:]
-// // }
-
-// // if err := models.UpdateMentions(ms, issue.Id); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-// // }
-
-// // log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
-// // default:
-// // ctx.Handle(404, "issue.Comment", err)
-// // return
-// // }
-// // }
-
-// // if comment != nil {
-// // uploadFiles(ctx, issue.Id, comment.Id)
-// // }
-
-// // // Notify watchers.
-// // act := &models.Action{
-// // ActUserId: ctx.User.Id,
-// // ActUserName: ctx.User.LowerName,
-// // ActEmail: ctx.User.Email,
-// // OpType: models.OP_COMMENT_ISSUE,
-// // Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
-// // RepoId: ctx.Repo.Repository.Id,
-// // RepoUserName: ctx.Repo.Owner.LowerName,
-// // RepoName: ctx.Repo.Repository.LowerName,
-// // }
-// // if err = models.NotifyWatchers(act); err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // // Mail watchers and mentions.
-// // if setting.Service.EnableNotifyMail {
-// // issue.Content = content
-// // tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
-// // if err != nil {
-// // send(500, nil, err)
-// // return
-// // }
-
-// // tos = append(tos, ctx.User.LowerName)
-// // newTos := make([]string, 0, len(ms))
-// // for _, m := range ms {
-// // 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 {
-// // send(500, nil, err)
-// // return
-// // }
-// // }
-
-// // send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil)
-// // }
-
-// // func NewLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
-// // if ctx.HasError() {
-// // Issues(ctx)
-// // return
-// // }
-
-// // l := &models.Label{
-// // RepoId: ctx.Repo.Repository.Id,
-// // Name: form.Title,
-// // Color: form.Color,
-// // }
-// // if err := models.NewLabel(l); err != nil {
-// // ctx.Handle(500, "issue.NewLabel(NewLabel)", err)
-// // return
-// // }
-// // ctx.Redirect(ctx.Repo.RepoLink + "/issues")
-// // }
-
-// // func UpdateLabel(ctx *middleware.Context, params martini.Params, form auth.CreateLabelForm) {
-// // id, _ := base.StrTo(ctx.Query("id")).Int64()
-// // if id == 0 {
-// // ctx.Error(404)
-// // return
-// // }
-
-// // l := &models.Label{
-// // Id: id,
-// // Name: form.Title,
-// // Color: form.Color,
-// // }
-// // if err := models.UpdateLabel(l); err != nil {
-// // ctx.Handle(500, "issue.UpdateLabel(UpdateLabel)", err)
-// // return
-// // }
-// // ctx.Redirect(ctx.Repo.RepoLink + "/issues")
-// // }
-
-// // func DeleteLabel(ctx *middleware.Context) {
-// // removes := ctx.Query("remove")
-// // if len(strings.TrimSpace(removes)) == 0 {
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // })
-// // return
-// // }
-
-// // strIds := strings.Split(removes, ",")
-// // for _, strId := range strIds {
-// // if err := models.DeleteLabel(ctx.Repo.Repository.Id, strId); err != nil {
-// // ctx.Handle(500, "issue.DeleteLabel(DeleteLabel)", err)
-// // return
-// // }
-// // }
-
-// // ctx.JSON(200, map[string]interface{}{
-// // "ok": true,
-// // })
-// // }
-
-// // func Milestones(ctx *middleware.Context) {
-// // ctx.Data["Title"] = "Milestones"
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = true
-
-// // isShowClosed := ctx.Query("state") == "closed"
-
-// // miles, err := models.GetMilestones(ctx.Repo.Repository.Id, isShowClosed)
-// // if err != nil {
-// // ctx.Handle(500, "issue.Milestones(GetMilestones)", err)
-// // return
-// // }
-// // for _, m := range miles {
-// // m.RenderedContent = string(base.RenderSpecialLink([]byte(m.Content), ctx.Repo.RepoLink))
-// // m.CalOpenIssues()
-// // }
-// // ctx.Data["Milestones"] = miles
-
-// // if isShowClosed {
-// // ctx.Data["State"] = "closed"
-// // } else {
-// // ctx.Data["State"] = "open"
-// // }
-// // ctx.HTML(200, MILESTONE)
-// // }
-
-// // func NewMilestone(ctx *middleware.Context) {
-// // ctx.Data["Title"] = "New Milestone"
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = true
-// // ctx.HTML(200, MILESTONE_NEW)
-// // }
-
-// // func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
-// // ctx.Data["Title"] = "New Milestone"
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = true
-
-// // if ctx.HasError() {
-// // ctx.HTML(200, MILESTONE_NEW)
-// // return
-// // }
-
-// // var deadline time.Time
-// // var err error
-// // if len(form.Deadline) == 0 {
-// // form.Deadline = "12/31/9999"
-// // }
-// // deadline, err = time.Parse("01/02/2006", form.Deadline)
-// // if err != nil {
-// // ctx.Handle(500, "issue.NewMilestonePost(time.Parse)", err)
-// // return
-// // }
-
-// // mile := &models.Milestone{
-// // RepoId: ctx.Repo.Repository.Id,
-// // Index: int64(ctx.Repo.Repository.NumMilestones) + 1,
-// // Name: form.Title,
-// // Content: form.Content,
-// // Deadline: deadline,
-// // }
-// // if err = models.NewMilestone(mile); err != nil {
-// // ctx.Handle(500, "issue.NewMilestonePost(NewMilestone)", err)
-// // return
-// // }
-
-// // ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
-// // }
-
-// // func UpdateMilestone(ctx *middleware.Context, params martini.Params) {
-// // ctx.Data["Title"] = "Update Milestone"
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = true
-
-// // idx, _ := base.StrTo(params["index"]).Int64()
-// // if idx == 0 {
-// // ctx.Handle(404, "issue.UpdateMilestone", nil)
-// // return
-// // }
-
-// // mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, idx)
-// // if err != nil {
-// // if err == models.ErrMilestoneNotExist {
-// // ctx.Handle(404, "issue.UpdateMilestone(GetMilestoneByIndex)", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateMilestone(GetMilestoneByIndex)", err)
-// // }
-// // return
-// // }
-
-// // action := params["action"]
-// // if len(action) > 0 {
-// // switch action {
-// // case "open":
-// // if mile.IsClosed {
-// // if err = models.ChangeMilestoneStatus(mile, false); err != nil {
-// // ctx.Handle(500, "issue.UpdateMilestone(ChangeMilestoneStatus)", err)
-// // return
-// // }
-// // }
-// // case "close":
-// // if !mile.IsClosed {
-// // mile.ClosedDate = time.Now()
-// // if err = models.ChangeMilestoneStatus(mile, true); err != nil {
-// // ctx.Handle(500, "issue.UpdateMilestone(ChangeMilestoneStatus)", err)
-// // return
-// // }
-// // }
-// // case "delete":
-// // if err = models.DeleteMilestone(mile); err != nil {
-// // ctx.Handle(500, "issue.UpdateMilestone(DeleteMilestone)", err)
-// // return
-// // }
-// // }
-// // ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
-// // return
-// // }
-
-// // mile.DeadlineString = mile.Deadline.UTC().Format("01/02/2006")
-// // if mile.DeadlineString == "12/31/9999" {
-// // mile.DeadlineString = ""
-// // }
-// // ctx.Data["Milestone"] = mile
-
-// // ctx.HTML(200, MILESTONE_EDIT)
-// // }
-
-// // func UpdateMilestonePost(ctx *middleware.Context, params martini.Params, form auth.CreateMilestoneForm) {
-// // ctx.Data["Title"] = "Update Milestone"
-// // ctx.Data["IsRepoToolbarIssues"] = true
-// // ctx.Data["IsRepoToolbarIssuesList"] = true
-
-// // idx, _ := base.StrTo(params["index"]).Int64()
-// // if idx == 0 {
-// // ctx.Handle(404, "issue.UpdateMilestonePost", nil)
-// // return
-// // }
-
-// // mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, idx)
-// // if err != nil {
-// // if err == models.ErrMilestoneNotExist {
-// // ctx.Handle(404, "issue.UpdateMilestonePost(GetMilestoneByIndex)", err)
-// // } else {
-// // ctx.Handle(500, "issue.UpdateMilestonePost(GetMilestoneByIndex)", err)
-// // }
-// // return
-// // }
-
-// // if ctx.HasError() {
-// // ctx.HTML(200, MILESTONE_EDIT)
-// // return
-// // }
-
-// // var deadline time.Time
-// // if len(form.Deadline) == 0 {
-// // form.Deadline = "12/31/9999"
-// // }
-// // deadline, err = time.Parse("01/02/2006", form.Deadline)
-// // if err != nil {
-// // ctx.Handle(500, "issue.UpdateMilestonePost(time.Parse)", err)
-// // return
-// // }
-
-// // mile.Name = form.Title
-// // mile.Content = form.Content
-// // mile.Deadline = deadline
-// // if err = models.UpdateMilestone(mile); err != nil {
-// // ctx.Handle(500, "issue.UpdateMilestonePost(UpdateMilestone)", err)
-// // return
-// // }
-
-// // ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
-// // }
-
-// // func IssueGetAttachment(ctx *middleware.Context, params martini.Params) {
-// // id, err := base.StrTo(params["id"]).Int64()
-
-// // if err != nil {
-// // ctx.Handle(400, "issue.IssueGetAttachment(base.StrTo.Int64)", err)
-// // return
-// // }
-
-// // attachment, err := models.GetAttachmentById(id)
-
-// // if err != nil {
-// // ctx.Handle(404, "issue.IssueGetAttachment(models.GetAttachmentById)", err)
-// // return
-// // }
-
-// // // Fix #312. Attachments with , in their name are not handled correctly by Google Chrome.
-// // // We must put the name in " manually.
-// // ctx.ServeFile(attachment.Path, "\""+attachment.Name+"\"")
-// // }
+import (
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/Unknwon/com"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/auth"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/log"
+ "github.com/gogits/gogs/modules/mailer"
+ "github.com/gogits/gogs/modules/middleware"
+ "github.com/gogits/gogs/modules/setting"
+)
+
+const (
+ ISSUES base.TplName = "repo/issue/list"
+ ISSUE_CREATE base.TplName = "repo/issue/create"
+ ISSUE_VIEW base.TplName = "repo/issue/view"
+
+ MILESTONE base.TplName = "repo/issue/milestone"
+ MILESTONE_NEW base.TplName = "repo/issue/milestone_new"
+ MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit"
+)
+
+var (
+ ErrFileTypeForbidden = errors.New("File type is not allowed")
+ ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded")
+)
+
+func Issues(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Issues"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = true
+
+ viewType := ctx.Query("type")
+ types := []string{"assigned", "created_by", "mentioned"}
+ if !com.IsSliceContainsStr(types, viewType) {
+ viewType = "all"
+ }
+
+ isShowClosed := ctx.Query("state") == "closed"
+
+ if viewType != "all" && !ctx.IsSigned {
+ ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
+ ctx.Redirect("/user/login")
+ return
+ }
+
+ var assigneeId, posterId int64
+ var filterMode int
+ switch viewType {
+ case "assigned":
+ assigneeId = ctx.User.Id
+ filterMode = models.FM_ASSIGN
+ case "created_by":
+ posterId = ctx.User.Id
+ filterMode = models.FM_CREATE
+ case "mentioned":
+ filterMode = models.FM_MENTION
+ }
+
+ var mid int64
+ midx, _ := com.StrTo(ctx.Query("milestone")).Int64()
+ if midx > 0 {
+ mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, midx)
+ if err != nil {
+ ctx.Handle(500, "issue.Issues(GetMilestoneByIndex): %v", err)
+ return
+ }
+ mid = mile.Id
+ }
+
+ selectLabels := ctx.Query("labels")
+ labels, err := models.GetLabels(ctx.Repo.Repository.Id)
+ if err != nil {
+ ctx.Handle(500, "issue.Issues(GetLabels): %v", err)
+ return
+ }
+ for _, l := range labels {
+ l.CalOpenIssues()
+ }
+ ctx.Data["Labels"] = labels
+
+ page, _ := com.StrTo(ctx.Query("page")).Int()
+
+ // Get issues.
+ issues, err := models.GetIssues(assigneeId, ctx.Repo.Repository.Id, posterId, mid, page,
+ isShowClosed, selectLabels, ctx.Query("sortType"))
+ if err != nil {
+ ctx.Handle(500, "issue.Issues(GetIssues): %v", err)
+ return
+ }
+
+ // Get issue-user pairs.
+ pairs, err := models.GetIssueUserPairs(ctx.Repo.Repository.Id, posterId, isShowClosed)
+ if err != nil {
+ ctx.Handle(500, "issue.Issues(GetIssueUserPairs): %v", err)
+ return
+ }
+
+ // Get posters.
+ for i := range issues {
+ if err = issues[i].GetLabels(); err != nil {
+ ctx.Handle(500, "GetLabels", fmt.Errorf("[#%d]%v", issues[i].Id, err))
+ return
+ }
+
+ idx := models.PairsContains(pairs, issues[i].Id)
+
+ if filterMode == models.FM_MENTION && (idx == -1 || !pairs[idx].IsMentioned) {
+ continue
+ }
+
+ if idx > -1 {
+ issues[i].IsRead = pairs[idx].IsRead
+ } else {
+ issues[i].IsRead = true
+ }
+
+ if err = issues[i].GetPoster(); err != nil {
+ ctx.Handle(500, "issue.Issues(GetPoster)", fmt.Errorf("[#%d]%v", issues[i].Id, err))
+ return
+ }
+ }
+
+ var uid int64 = -1
+ if ctx.User != nil {
+ uid = ctx.User.Id
+ }
+ issueStats := models.GetIssueStats(ctx.Repo.Repository.Id, uid, isShowClosed, filterMode)
+ ctx.Data["IssueStats"] = issueStats
+ ctx.Data["SelectLabels"], _ = com.StrTo(selectLabels).Int64()
+ ctx.Data["ViewType"] = viewType
+ ctx.Data["Issues"] = issues
+ ctx.Data["IsShowClosed"] = isShowClosed
+ if isShowClosed {
+ ctx.Data["State"] = "closed"
+ ctx.Data["ShowCount"] = issueStats.ClosedCount
+ } else {
+ ctx.Data["ShowCount"] = issueStats.OpenCount
+ }
+ ctx.HTML(200, ISSUES)
+}
+
+func CreateIssue(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Create issue"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = false
+ ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled
+
+ var err error
+ // Get all milestones.
+ ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, false)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err)
+ return
+ }
+ ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, true)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err)
+ return
+ }
+
+ us, err := models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
+ if err != nil {
+ ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
+ return
+ }
+
+ ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes
+ ctx.Data["Collaborators"] = us
+
+ ctx.HTML(200, ISSUE_CREATE)
+}
+
+func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
+ send := func(status int, data interface{}, err error) {
+ if err != nil {
+ log.Error(4, "issue.CreateIssuePost(?): %s", err)
+
+ ctx.JSON(status, map[string]interface{}{
+ "ok": false,
+ "status": status,
+ "error": err.Error(),
+ })
+ } else {
+ ctx.JSON(status, map[string]interface{}{
+ "ok": true,
+ "status": status,
+ "data": data,
+ })
+ }
+ }
+
+ var err error
+ // Get all milestones.
+ _, err = models.GetMilestones(ctx.Repo.Repository.Id, false)
+ if err != nil {
+ send(500, nil, err)
+ return
+ }
+ _, err = models.GetMilestones(ctx.Repo.Repository.Id, true)
+ if err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ _, err = models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
+ if err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ if ctx.HasError() {
+ send(400, nil, errors.New(ctx.Flash.ErrorMsg))
+ return
+ }
+
+ // Only collaborators can assign.
+ if !ctx.Repo.IsOwner {
+ form.AssigneeId = 0
+ }
+ issue := &models.Issue{
+ RepoId: ctx.Repo.Repository.Id,
+ Index: int64(ctx.Repo.Repository.NumIssues) + 1,
+ Name: form.IssueName,
+ PosterId: ctx.User.Id,
+ MilestoneId: form.MilestoneId,
+ AssigneeId: form.AssigneeId,
+ LabelIds: form.Labels,
+ Content: form.Content,
+ }
+ if err := models.NewIssue(issue); err != nil {
+ send(500, nil, err)
+ return
+ } else if err := models.NewIssueUserPairs(issue.RepoId, issue.Id, ctx.Repo.Owner.Id,
+ ctx.User.Id, form.AssigneeId, ctx.Repo.Repository.Name); err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ if setting.AttachmentEnabled {
+ uploadFiles(ctx, issue.Id, 0)
+ }
+
+ // Update mentions.
+ ms := base.MentionPattern.FindAllString(issue.Content, -1)
+ if len(ms) > 0 {
+ for i := range ms {
+ ms[i] = ms[i][1:]
+ }
+
+ if err := models.UpdateMentions(ms, issue.Id); err != nil {
+ send(500, nil, err)
+ return
+ }
+ }
+
+ act := &models.Action{
+ ActUserId: ctx.User.Id,
+ ActUserName: ctx.User.Name,
+ ActEmail: ctx.User.Email,
+ OpType: models.CREATE_ISSUE,
+ Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
+ RepoId: ctx.Repo.Repository.Id,
+ RepoUserName: ctx.Repo.Owner.Name,
+ RepoName: ctx.Repo.Repository.Name,
+ RefName: ctx.Repo.BranchName,
+ IsPrivate: ctx.Repo.Repository.IsPrivate,
+ }
+ // Notify watchers.
+ if err := models.NotifyWatchers(act); err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ // Mail watchers and mentions.
+ if setting.Service.EnableNotifyMail {
+ tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
+ if err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ tos = append(tos, ctx.User.LowerName)
+ newTos := make([]string, 0, len(ms))
+ for _, m := range ms {
+ 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 {
+ send(500, nil, err)
+ return
+ }
+ }
+ log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id)
+
+ send(200, fmt.Sprintf("/%s/%s/issues/%d", ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil)
+}
+
+func checkLabels(labels, allLabels []*models.Label) {
+ for _, l := range labels {
+ for _, l2 := range allLabels {
+ if l.Id == l2.Id {
+ l2.IsChecked = true
+ break
+ }
+ }
+ }
+}
+
+func ViewIssue(ctx *middleware.Context) {
+ ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled
+
+ idx := com.StrTo(ctx.Params(":index")).MustInt64()
+ if idx == 0 {
+ ctx.Handle(404, "issue.ViewIssue", nil)
+ return
+ }
+
+ issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "issue.ViewIssue(GetIssueByIndex)", err)
+ } else {
+ ctx.Handle(500, "issue.ViewIssue(GetIssueByIndex)", err)
+ }
+ return
+ }
+
+ // Get labels.
+ if err = issue.GetLabels(); err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetLabels)", err)
+ return
+ }
+ labels, err := models.GetLabels(ctx.Repo.Repository.Id)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetLabels.2)", err)
+ return
+ }
+ checkLabels(issue.Labels, labels)
+ ctx.Data["Labels"] = labels
+
+ // Get assigned milestone.
+ if issue.MilestoneId > 0 {
+ ctx.Data["Milestone"], err = models.GetMilestoneById(issue.MilestoneId)
+ if err != nil {
+ if err == models.ErrMilestoneNotExist {
+ log.Warn("issue.ViewIssue(GetMilestoneById): %v", err)
+ } else {
+ ctx.Handle(500, "issue.ViewIssue(GetMilestoneById)", err)
+ return
+ }
+ }
+ }
+
+ // Get all milestones.
+ ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, false)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err)
+ return
+ }
+ ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, true)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err)
+ return
+ }
+
+ // Get all collaborators.
+ ctx.Data["Collaborators"], err = models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
+ if err != nil {
+ ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
+ return
+ }
+
+ if ctx.IsSigned {
+ // Update issue-user.
+ if err = models.UpdateIssueUserPairByRead(ctx.User.Id, issue.Id); err != nil {
+ ctx.Handle(500, "issue.ViewIssue(UpdateIssueUserPairByRead): %v", err)
+ return
+ }
+ }
+
+ // Get poster and Assignee.
+ if err = issue.GetPoster(); err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetPoster): %v", err)
+ return
+ } else if err = issue.GetAssignee(); err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetAssignee): %v", err)
+ return
+ }
+ issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
+
+ // Get comments.
+ comments, err := models.GetIssueComments(issue.Id)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetIssueComments): %v", err)
+ return
+ }
+
+ // Get posters.
+ for i := range comments {
+ u, err := models.GetUserById(comments[i].PosterId)
+ if err != nil {
+ ctx.Handle(500, "issue.ViewIssue(GetUserById.2): %v", err)
+ return
+ }
+ comments[i].Poster = u
+
+ if comments[i].Type == models.COMMENT {
+ comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink))
+ }
+ }
+
+ ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes
+
+ ctx.Data["Title"] = issue.Name
+ ctx.Data["Issue"] = issue
+ ctx.Data["Comments"] = comments
+ ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = false
+ ctx.HTML(200, ISSUE_VIEW)
+}
+
+func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) {
+ idx := com.StrTo(ctx.Params(":index")).MustInt64()
+ if idx <= 0 {
+ ctx.Error(404)
+ return
+ }
+
+ issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "issue.UpdateIssue", err)
+ } else {
+ ctx.Handle(500, "issue.UpdateIssue(GetIssueByIndex)", err)
+ }
+ return
+ }
+
+ if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
+ ctx.Error(403)
+ return
+ }
+
+ issue.Name = form.IssueName
+ issue.MilestoneId = form.MilestoneId
+ issue.AssigneeId = form.AssigneeId
+ issue.LabelIds = form.Labels
+ issue.Content = form.Content
+ // try get content from text, ignore conflict with preview ajax
+ if form.Content == "" {
+ issue.Content = ctx.Query("text")
+ }
+ if err = models.UpdateIssue(issue); err != nil {
+ ctx.Handle(500, "issue.UpdateIssue(UpdateIssue)", err)
+ return
+ }
+
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ "title": issue.Name,
+ "content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)),
+ })
+}
+
+func UpdateIssueLabel(ctx *middleware.Context) {
+ if !ctx.Repo.IsOwner {
+ ctx.Error(403)
+ return
+ }
+
+ idx := com.StrTo(ctx.Params(":index")).MustInt64()
+ if idx <= 0 {
+ ctx.Error(404)
+ return
+ }
+
+ issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx)
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "issue.UpdateIssueLabel(GetIssueByIndex)", err)
+ } else {
+ ctx.Handle(500, "issue.UpdateIssueLabel(GetIssueByIndex)", err)
+ }
+ return
+ }
+
+ isAttach := ctx.Query("action") == "attach"
+ labelStrId := ctx.Query("id")
+ labelId := com.StrTo(labelStrId).MustInt64()
+ label, err := models.GetLabelById(labelId)
+ if err != nil {
+ if err == models.ErrLabelNotExist {
+ ctx.Handle(404, "issue.UpdateIssueLabel(GetLabelById)", err)
+ } else {
+ ctx.Handle(500, "issue.UpdateIssueLabel(GetLabelById)", err)
+ }
+ return
+ }
+
+ isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|")
+ isNeedUpdate := false
+ if isAttach {
+ if !isHad {
+ issue.LabelIds += "$" + labelStrId + "|"
+ isNeedUpdate = true
+ }
+ } else {
+ if isHad {
+ issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1)
+ isNeedUpdate = true
+ }
+ }
+
+ if isNeedUpdate {
+ if err = models.UpdateIssue(issue); err != nil {
+ ctx.Handle(500, "issue.UpdateIssueLabel(UpdateIssue)", err)
+ return
+ }
+
+ if isAttach {
+ label.NumIssues++
+ if issue.IsClosed {
+ label.NumClosedIssues++
+ }
+ } else {
+ label.NumIssues--
+ if issue.IsClosed {
+ label.NumClosedIssues--
+ }
+ }
+ if err = models.UpdateLabel(label); err != nil {
+ ctx.Handle(500, "issue.UpdateIssueLabel(UpdateLabel)", err)
+ return
+ }
+ }
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+}
+
+func UpdateIssueMilestone(ctx *middleware.Context) {
+ if !ctx.Repo.IsOwner {
+ ctx.Error(403)
+ return
+ }
+
+ issueId := com.StrTo(ctx.Params(":issue")).MustInt64()
+ if issueId == 0 {
+ ctx.Error(404)
+ return
+ }
+
+ issue, err := models.GetIssueById(issueId)
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "issue.UpdateIssueMilestone(GetIssueById)", err)
+ } else {
+ ctx.Handle(500, "issue.UpdateIssueMilestone(GetIssueById)", err)
+ }
+ return
+ }
+
+ oldMid := issue.MilestoneId
+ mid := com.StrTo(ctx.Params(":milestone")).MustInt64()
+ if oldMid == mid {
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+ return
+ }
+
+ // Not check for invalid milestone id and give responsibility to owners.
+ issue.MilestoneId = mid
+ if err = models.ChangeMilestoneAssign(oldMid, mid, issue); err != nil {
+ ctx.Handle(500, "issue.UpdateIssueMilestone(ChangeMilestoneAssign)", err)
+ return
+ } else if err = models.UpdateIssue(issue); err != nil {
+ ctx.Handle(500, "issue.UpdateIssueMilestone(UpdateIssue)", err)
+ return
+ }
+
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+}
+
+func UpdateAssignee(ctx *middleware.Context) {
+ if !ctx.Repo.IsOwner {
+ ctx.Error(403)
+ return
+ }
+
+ issueId := com.StrTo(ctx.Params(":index")).MustInt64()
+ if issueId == 0 {
+ ctx.Error(404)
+ return
+ }
+
+ issue, err := models.GetIssueById(issueId)
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "GetIssueById", err)
+ } else {
+ ctx.Handle(500, "GetIssueById", err)
+ }
+ return
+ }
+
+ aid := com.StrTo(ctx.Params(":assigneeid")).MustInt64()
+ // Not check for invalid assignne id and give responsibility to owners.
+ issue.AssigneeId = aid
+ if err = models.UpdateIssueUserPairByAssignee(aid, issue.Id); err != nil {
+ ctx.Handle(500, "UpdateIssueUserPairByAssignee: %v", err)
+ return
+ } else if err = models.UpdateIssue(issue); err != nil {
+ ctx.Handle(500, "UpdateIssue", err)
+ return
+ }
+
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+}
+
+func uploadFiles(ctx *middleware.Context, issueId, commentId int64) {
+ if !setting.AttachmentEnabled {
+ return
+ }
+
+ allowedTypes := strings.Split(setting.AttachmentAllowedTypes, "|")
+ attachments := ctx.Req.MultipartForm.File["attachments"]
+
+ if len(attachments) > setting.AttachmentMaxFiles {
+ ctx.Handle(400, "issue.Comment", ErrTooManyFiles)
+ return
+ }
+
+ for _, header := range attachments {
+ file, err := header.Open()
+
+ if err != nil {
+ ctx.Handle(500, "issue.Comment(header.Open)", err)
+ return
+ }
+
+ defer file.Close()
+
+ buf := make([]byte, 1024)
+ n, _ := file.Read(buf)
+ if n > 0 {
+ buf = buf[:n]
+ }
+ fileType := http.DetectContentType(buf)
+ fmt.Println(fileType)
+
+ allowed := false
+
+ for _, t := range allowedTypes {
+ t := strings.Trim(t, " ")
+
+ if t == "*/*" || t == fileType {
+ allowed = true
+ break
+ }
+ }
+
+ if !allowed {
+ ctx.Handle(400, "issue.Comment", ErrFileTypeForbidden)
+ return
+ }
+
+ out, err := ioutil.TempFile(setting.AttachmentPath, "attachment_")
+
+ if err != nil {
+ ctx.Handle(500, "ioutil.TempFile", err)
+ return
+ }
+
+ defer out.Close()
+
+ out.Write(buf)
+ _, err = io.Copy(out, file)
+ if err != nil {
+ ctx.Handle(500, "io.Copy", err)
+ return
+ }
+
+ _, err = models.CreateAttachment(issueId, commentId, header.Filename, out.Name())
+ if err != nil {
+ ctx.Handle(500, "CreateAttachment", err)
+ return
+ }
+ }
+}
+
+func Comment(ctx *middleware.Context) {
+ send := func(status int, data interface{}, err error) {
+ if err != nil {
+ log.Error(4, "issue.Comment(?): %s", err)
+
+ ctx.JSON(status, map[string]interface{}{
+ "ok": false,
+ "status": status,
+ "error": err.Error(),
+ })
+ } else {
+ ctx.JSON(status, map[string]interface{}{
+ "ok": true,
+ "status": status,
+ "data": data,
+ })
+ }
+ }
+
+ index := com.StrTo(ctx.Query("issueIndex")).MustInt64()
+ if index == 0 {
+ ctx.Error(404)
+ return
+ }
+
+ issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ send(404, nil, err)
+ } else {
+ send(200, nil, err)
+ }
+
+ return
+ }
+
+ // Check if issue owner changes the status of issue.
+ var newStatus string
+ if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
+ newStatus = ctx.Query("change_status")
+ }
+ if len(newStatus) > 0 {
+ if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) ||
+ (strings.Contains(newStatus, "Close") && !issue.IsClosed) {
+ issue.IsClosed = !issue.IsClosed
+ if err = models.UpdateIssue(issue); err != nil {
+ send(500, nil, err)
+ return
+ } else if err = models.UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ // Change open/closed issue counter for the associated milestone
+ if issue.MilestoneId > 0 {
+ if err = models.ChangeMilestoneIssueStats(issue); err != nil {
+ send(500, nil, err)
+ }
+ }
+
+ cmtType := models.CLOSE
+ if !issue.IsClosed {
+ cmtType = models.REOPEN
+ }
+
+ if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, "", nil); err != nil {
+ send(200, nil, err)
+ return
+ }
+ log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed)
+ }
+ }
+
+ var comment *models.Comment
+
+ var ms []string
+ content := ctx.Query("content")
+ // Fix #321. Allow empty comments, as long as we have attachments.
+ if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 {
+ switch ctx.Params(":action") {
+ case "new":
+ if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.COMMENT, content, nil); err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ // Update mentions.
+ ms = base.MentionPattern.FindAllString(issue.Content, -1)
+ if len(ms) > 0 {
+ for i := range ms {
+ ms[i] = ms[i][1:]
+ }
+
+ if err := models.UpdateMentions(ms, issue.Id); err != nil {
+ send(500, nil, err)
+ return
+ }
+ }
+
+ log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
+ default:
+ ctx.Handle(404, "issue.Comment", err)
+ return
+ }
+ }
+
+ if comment != nil {
+ uploadFiles(ctx, issue.Id, comment.Id)
+ }
+
+ // Notify watchers.
+ act := &models.Action{
+ ActUserId: ctx.User.Id,
+ ActUserName: ctx.User.LowerName,
+ ActEmail: ctx.User.Email,
+ OpType: models.COMMENT_ISSUE,
+ Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
+ RepoId: ctx.Repo.Repository.Id,
+ RepoUserName: ctx.Repo.Owner.LowerName,
+ RepoName: ctx.Repo.Repository.LowerName,
+ }
+ if err = models.NotifyWatchers(act); err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ // Mail watchers and mentions.
+ if setting.Service.EnableNotifyMail {
+ issue.Content = content
+ tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
+ if err != nil {
+ send(500, nil, err)
+ return
+ }
+
+ tos = append(tos, ctx.User.LowerName)
+ newTos := make([]string, 0, len(ms))
+ for _, m := range ms {
+ 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 {
+ send(500, nil, err)
+ return
+ }
+ }
+
+ send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil)
+}
+
+func NewLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
+ if ctx.HasError() {
+ Issues(ctx)
+ return
+ }
+
+ l := &models.Label{
+ RepoId: ctx.Repo.Repository.Id,
+ Name: form.Title,
+ Color: form.Color,
+ }
+ if err := models.NewLabel(l); err != nil {
+ ctx.Handle(500, "issue.NewLabel(NewLabel)", err)
+ return
+ }
+ ctx.Redirect(ctx.Repo.RepoLink + "/issues")
+}
+
+func UpdateLabel(ctx *middleware.Context, form auth.CreateLabelForm) {
+ id := com.StrTo(ctx.Query("id")).MustInt64()
+ if id == 0 {
+ ctx.Error(404)
+ return
+ }
+
+ l := &models.Label{
+ Id: id,
+ Name: form.Title,
+ Color: form.Color,
+ }
+ if err := models.UpdateLabel(l); err != nil {
+ ctx.Handle(500, "issue.UpdateLabel(UpdateLabel)", err)
+ return
+ }
+ ctx.Redirect(ctx.Repo.RepoLink + "/issues")
+}
+
+func DeleteLabel(ctx *middleware.Context) {
+ removes := ctx.Query("remove")
+ if len(strings.TrimSpace(removes)) == 0 {
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+ return
+ }
+
+ strIds := strings.Split(removes, ",")
+ for _, strId := range strIds {
+ if err := models.DeleteLabel(ctx.Repo.Repository.Id, strId); err != nil {
+ ctx.Handle(500, "issue.DeleteLabel(DeleteLabel)", err)
+ return
+ }
+ }
+
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+}
+
+func Milestones(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Milestones"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = true
+
+ isShowClosed := ctx.Query("state") == "closed"
+
+ miles, err := models.GetMilestones(ctx.Repo.Repository.Id, isShowClosed)
+ if err != nil {
+ ctx.Handle(500, "issue.Milestones(GetMilestones)", err)
+ return
+ }
+ for _, m := range miles {
+ m.RenderedContent = string(base.RenderSpecialLink([]byte(m.Content), ctx.Repo.RepoLink))
+ m.CalOpenIssues()
+ }
+ ctx.Data["Milestones"] = miles
+
+ if isShowClosed {
+ ctx.Data["State"] = "closed"
+ } else {
+ ctx.Data["State"] = "open"
+ }
+ ctx.HTML(200, MILESTONE)
+}
+
+func NewMilestone(ctx *middleware.Context) {
+ ctx.Data["Title"] = "New Milestone"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = true
+ ctx.HTML(200, MILESTONE_NEW)
+}
+
+func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
+ ctx.Data["Title"] = "New Milestone"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = true
+
+ if ctx.HasError() {
+ ctx.HTML(200, MILESTONE_NEW)
+ return
+ }
+
+ var deadline time.Time
+ var err error
+ if len(form.Deadline) == 0 {
+ form.Deadline = "12/31/9999"
+ }
+ deadline, err = time.Parse("01/02/2006", form.Deadline)
+ if err != nil {
+ ctx.Handle(500, "issue.NewMilestonePost(time.Parse)", err)
+ return
+ }
+
+ mile := &models.Milestone{
+ RepoId: ctx.Repo.Repository.Id,
+ Index: int64(ctx.Repo.Repository.NumMilestones) + 1,
+ Name: form.Title,
+ Content: form.Content,
+ Deadline: deadline,
+ }
+ if err = models.NewMilestone(mile); err != nil {
+ ctx.Handle(500, "issue.NewMilestonePost(NewMilestone)", err)
+ return
+ }
+
+ ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
+}
+
+func UpdateMilestone(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Update Milestone"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = true
+
+ idx := com.StrTo(ctx.Params(":index")).MustInt64()
+ if idx == 0 {
+ ctx.Handle(404, "issue.UpdateMilestone", nil)
+ return
+ }
+
+ mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, idx)
+ if err != nil {
+ if err == models.ErrMilestoneNotExist {
+ ctx.Handle(404, "issue.UpdateMilestone(GetMilestoneByIndex)", err)
+ } else {
+ ctx.Handle(500, "issue.UpdateMilestone(GetMilestoneByIndex)", err)
+ }
+ return
+ }
+
+ action := ctx.Params(":action")
+ if len(action) > 0 {
+ switch action {
+ case "open":
+ if mile.IsClosed {
+ if err = models.ChangeMilestoneStatus(mile, false); err != nil {
+ ctx.Handle(500, "issue.UpdateMilestone(ChangeMilestoneStatus)", err)
+ return
+ }
+ }
+ case "close":
+ if !mile.IsClosed {
+ mile.ClosedDate = time.Now()
+ if err = models.ChangeMilestoneStatus(mile, true); err != nil {
+ ctx.Handle(500, "issue.UpdateMilestone(ChangeMilestoneStatus)", err)
+ return
+ }
+ }
+ case "delete":
+ if err = models.DeleteMilestone(mile); err != nil {
+ ctx.Handle(500, "issue.UpdateMilestone(DeleteMilestone)", err)
+ return
+ }
+ }
+ ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
+ return
+ }
+
+ mile.DeadlineString = mile.Deadline.UTC().Format("01/02/2006")
+ if mile.DeadlineString == "12/31/9999" {
+ mile.DeadlineString = ""
+ }
+ ctx.Data["Milestone"] = mile
+
+ ctx.HTML(200, MILESTONE_EDIT)
+}
+
+func UpdateMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
+ ctx.Data["Title"] = "Update Milestone"
+ ctx.Data["IsRepoToolbarIssues"] = true
+ ctx.Data["IsRepoToolbarIssuesList"] = true
+
+ idx := com.StrTo(ctx.Params(":index")).MustInt64()
+ if idx == 0 {
+ ctx.Handle(404, "issue.UpdateMilestonePost", nil)
+ return
+ }
+
+ mile, err := models.GetMilestoneByIndex(ctx.Repo.Repository.Id, idx)
+ if err != nil {
+ if err == models.ErrMilestoneNotExist {
+ ctx.Handle(404, "issue.UpdateMilestonePost(GetMilestoneByIndex)", err)
+ } else {
+ ctx.Handle(500, "issue.UpdateMilestonePost(GetMilestoneByIndex)", err)
+ }
+ return
+ }
+
+ if ctx.HasError() {
+ ctx.HTML(200, MILESTONE_EDIT)
+ return
+ }
+
+ var deadline time.Time
+ if len(form.Deadline) == 0 {
+ form.Deadline = "12/31/9999"
+ }
+ deadline, err = time.Parse("01/02/2006", form.Deadline)
+ if err != nil {
+ ctx.Handle(500, "issue.UpdateMilestonePost(time.Parse)", err)
+ return
+ }
+
+ mile.Name = form.Title
+ mile.Content = form.Content
+ mile.Deadline = deadline
+ if err = models.UpdateMilestone(mile); err != nil {
+ ctx.Handle(500, "issue.UpdateMilestonePost(UpdateMilestone)", err)
+ return
+ }
+
+ ctx.Redirect(ctx.Repo.RepoLink + "/issues/milestones")
+}
+
+func IssueGetAttachment(ctx *middleware.Context) {
+ id := com.StrTo(ctx.Params(":id")).MustInt64()
+ if id == 0 {
+ ctx.Error(404)
+ return
+ }
+
+ attachment, err := models.GetAttachmentById(id)
+
+ if err != nil {
+ ctx.Handle(404, "issue.IssueGetAttachment(models.GetAttachmentById)", err)
+ return
+ }
+
+ // Fix #312. Attachments with , in their name are not handled correctly by Google Chrome.
+ // We must put the name in " manually.
+ ctx.ServeFile(attachment.Path, "\""+attachment.Name+"\"")
+}
diff --git a/routers/repo/release.go b/routers/repo/release.go
index 509796fb19..addeb1ce5f 100644
--- a/routers/repo/release.go
+++ b/routers/repo/release.go
@@ -5,13 +5,11 @@
package repo
import (
- // "github.com/go-martini/martini"
-
- // "github.com/gogits/gogs/models"
- // "github.com/gogits/gogs/modules/auth"
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
- // "github.com/gogits/gogs/modules/log"
- // "github.com/gogits/gogs/modules/middleware"
+ "github.com/gogits/gogs/modules/log"
+ "github.com/gogits/gogs/modules/middleware"
)
const (
@@ -20,215 +18,215 @@ const (
RELEASE_EDIT base.TplName = "repo/release/edit"
)
-// func Releases(ctx *middleware.Context) {
-// ctx.Data["Title"] = "Releases"
-// ctx.Data["IsRepoToolbarReleases"] = true
-// ctx.Data["IsRepoReleaseNew"] = false
-// rawTags, err := ctx.Repo.GitRepo.GetTags()
-// if err != nil {
-// ctx.Handle(500, "release.Releases(GetTags)", err)
-// return
-// }
-
-// rels, err := models.GetReleasesByRepoId(ctx.Repo.Repository.Id)
-// if err != nil {
-// ctx.Handle(500, "release.Releases(GetReleasesByRepoId)", err)
-// return
-// }
-
-// commitsCount, err := ctx.Repo.Commit.CommitsCount()
-// if err != nil {
-// ctx.Handle(500, "release.Releases(CommitsCount)", err)
-// return
-// }
-
-// // Temproray cache commits count of used branches to speed up.
-// countCache := make(map[string]int)
-
-// tags := make([]*models.Release, len(rawTags))
-// for i, rawTag := range rawTags {
-// for _, rel := range rels {
-// if rel.IsDraft && !ctx.Repo.IsOwner {
-// continue
-// }
-// if rel.TagName == rawTag {
-// rel.Publisher, err = models.GetUserById(rel.PublisherId)
-// if err != nil {
-// ctx.Handle(500, "release.Releases(GetUserById)", err)
-// return
-// }
-// // Get corresponding target if it's not the current branch.
-// if ctx.Repo.BranchName != rel.Target {
-// // Get count if not exists.
-// if _, ok := countCache[rel.Target]; !ok {
-// commit, err := ctx.Repo.GitRepo.GetCommitOfTag(rel.TagName)
-// if err != nil {
-// ctx.Handle(500, "release.Releases(GetCommitOfTag)", err)
-// return
-// }
-// countCache[rel.Target], err = commit.CommitsCount()
-// if err != nil {
-// ctx.Handle(500, "release.Releases(CommitsCount2)", err)
-// return
-// }
-// }
-// rel.NumCommitsBehind = countCache[rel.Target] - rel.NumCommits
-// } else {
-// rel.NumCommitsBehind = commitsCount - rel.NumCommits
-// }
-
-// rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink)
-// tags[i] = rel
-// break
-// }
-// }
-
-// if tags[i] == nil {
-// commit, err := ctx.Repo.GitRepo.GetCommitOfTag(rawTag)
-// if err != nil {
-// ctx.Handle(500, "release.Releases(GetCommitOfTag2)", err)
-// return
-// }
-
-// tags[i] = &models.Release{
-// Title: rawTag,
-// TagName: rawTag,
-// Sha1: commit.Id.String(),
-// }
-
-// tags[i].NumCommits, err = ctx.Repo.GitRepo.CommitsCount(commit.Id.String())
-// if err != nil {
-// ctx.Handle(500, "release.Releases(CommitsCount)", err)
-// return
-// }
-// tags[i].NumCommitsBehind = commitsCount - tags[i].NumCommits
-// }
-// }
-// models.SortReleases(tags)
-// ctx.Data["Releases"] = tags
-// ctx.HTML(200, RELEASES)
-// }
-
-// func NewRelease(ctx *middleware.Context) {
-// if !ctx.Repo.IsOwner {
-// ctx.Handle(403, "release.ReleasesNew", nil)
-// return
-// }
-
-// ctx.Data["Title"] = "New Release"
-// 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"] = "New Release"
-// ctx.Data["IsRepoToolbarReleases"] = true
-// ctx.Data["IsRepoReleaseNew"] = true
-
-// if ctx.HasError() {
-// ctx.HTML(200, RELEASE_NEW)
-// return
-// }
-
-// commitsCount, err := ctx.Repo.Commit.CommitsCount()
-// if err != nil {
-// ctx.Handle(500, "release.ReleasesNewPost(CommitsCount)", err)
-// return
-// }
-
-// if !ctx.Repo.GitRepo.IsBranchExist(form.Target) {
-// ctx.RenderWithErr("Target branch does not exist", "release/new", &form)
-// return
-// }
-
-// rel := &models.Release{
-// RepoId: ctx.Repo.Repository.Id,
-// PublisherId: ctx.User.Id,
-// Title: form.Title,
-// TagName: form.TagName,
-// Target: form.Target,
-// Sha1: ctx.Repo.Commit.Id.String(),
-// NumCommits: commitsCount,
-// Note: form.Content,
-// IsDraft: len(form.Draft) > 0,
-// IsPrerelease: form.Prerelease,
-// }
-
-// if err = models.CreateRelease(ctx.Repo.GitRepo, rel); err != nil {
-// if err == models.ErrReleaseAlreadyExist {
-// ctx.RenderWithErr("Release with this tag name has already existed", "release/new", &form)
-// } else {
-// ctx.Handle(500, "release.ReleasesNewPost(IsReleaseExist)", err)
-// }
-// return
-// }
-// log.Trace("%s Release created: %s/%s:%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.Name, form.TagName)
-
-// ctx.Redirect(ctx.Repo.RepoLink + "/releases")
-// }
-
-// func EditRelease(ctx *middleware.Context, params martini.Params) {
-// if !ctx.Repo.IsOwner {
-// ctx.Handle(403, "release.ReleasesEdit", nil)
-// return
-// }
-
-// tagName := params["tagname"]
-// rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName)
-// if err != nil {
-// if err == models.ErrReleaseNotExist {
-// ctx.Handle(404, "release.ReleasesEdit(GetRelease)", err)
-// } else {
-// ctx.Handle(500, "release.ReleasesEdit(GetRelease)", err)
-// }
-// return
-// }
-// ctx.Data["Release"] = rel
-
-// ctx.Data["Title"] = "Edit Release"
-// ctx.Data["IsRepoToolbarReleases"] = true
-// ctx.HTML(200, RELEASE_EDIT)
-// }
-
-// func EditReleasePost(ctx *middleware.Context, params martini.Params, form auth.EditReleaseForm) {
-// if !ctx.Repo.IsOwner {
-// ctx.Handle(403, "release.EditReleasePost", nil)
-// return
-// }
-
-// tagName := params["tagname"]
-// rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName)
-// if err != nil {
-// if err == models.ErrReleaseNotExist {
-// ctx.Handle(404, "release.EditReleasePost(GetRelease)", err)
-// } else {
-// ctx.Handle(500, "release.EditReleasePost(GetRelease)", err)
-// }
-// return
-// }
-// ctx.Data["Release"] = rel
-
-// if ctx.HasError() {
-// ctx.HTML(200, RELEASE_EDIT)
-// return
-// }
-
-// ctx.Data["Title"] = "Edit Release"
-// ctx.Data["IsRepoToolbarReleases"] = true
-
-// rel.Title = form.Title
-// rel.Note = form.Content
-// rel.IsDraft = len(form.Draft) > 0
-// rel.IsPrerelease = form.Prerelease
-// if err = models.UpdateRelease(ctx.Repo.GitRepo, rel); err != nil {
-// ctx.Handle(500, "release.EditReleasePost(UpdateRelease)", err)
-// return
-// }
-// ctx.Redirect(ctx.Repo.RepoLink + "/releases")
-// }
+func Releases(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Releases"
+ ctx.Data["IsRepoToolbarReleases"] = true
+ ctx.Data["IsRepoReleaseNew"] = false
+ rawTags, err := ctx.Repo.GitRepo.GetTags()
+ if err != nil {
+ ctx.Handle(500, "release.Releases(GetTags)", err)
+ return
+ }
+
+ rels, err := models.GetReleasesByRepoId(ctx.Repo.Repository.Id)
+ if err != nil {
+ ctx.Handle(500, "release.Releases(GetReleasesByRepoId)", err)
+ return
+ }
+
+ commitsCount, err := ctx.Repo.Commit.CommitsCount()
+ if err != nil {
+ ctx.Handle(500, "release.Releases(CommitsCount)", err)
+ return
+ }
+
+ // Temproray cache commits count of used branches to speed up.
+ countCache := make(map[string]int)
+
+ tags := make([]*models.Release, len(rawTags))
+ for i, rawTag := range rawTags {
+ for _, rel := range rels {
+ if rel.IsDraft && !ctx.Repo.IsOwner {
+ continue
+ }
+ if rel.TagName == rawTag {
+ rel.Publisher, err = models.GetUserById(rel.PublisherId)
+ if err != nil {
+ ctx.Handle(500, "GetUserById", err)
+ return
+ }
+ // Get corresponding target if it's not the current branch.
+ if ctx.Repo.BranchName != rel.Target {
+ // Get count if not exists.
+ if _, ok := countCache[rel.Target]; !ok {
+ commit, err := ctx.Repo.GitRepo.GetCommitOfTag(rel.TagName)
+ if err != nil {
+ ctx.Handle(500, "GetCommitOfTag", err)
+ return
+ }
+ countCache[rel.Target], err = commit.CommitsCount()
+ if err != nil {
+ ctx.Handle(500, "CommitsCount2", err)
+ return
+ }
+ }
+ rel.NumCommitsBehind = countCache[rel.Target] - rel.NumCommits
+ } else {
+ rel.NumCommitsBehind = commitsCount - rel.NumCommits
+ }
+
+ rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink)
+ tags[i] = rel
+ break
+ }
+ }
+
+ if tags[i] == nil {
+ commit, err := ctx.Repo.GitRepo.GetCommitOfTag(rawTag)
+ if err != nil {
+ ctx.Handle(500, "GetCommitOfTag2", err)
+ return
+ }
+
+ tags[i] = &models.Release{
+ Title: rawTag,
+ TagName: rawTag,
+ Sha1: commit.Id.String(),
+ }
+
+ tags[i].NumCommits, err = ctx.Repo.GitRepo.CommitsCount(commit.Id.String())
+ if err != nil {
+ ctx.Handle(500, "CommitsCount", err)
+ return
+ }
+ tags[i].NumCommitsBehind = commitsCount - tags[i].NumCommits
+ }
+ }
+ models.SortReleases(tags)
+ ctx.Data["Releases"] = tags
+ ctx.HTML(200, RELEASES)
+}
+
+func NewRelease(ctx *middleware.Context) {
+ if !ctx.Repo.IsOwner {
+ ctx.Handle(403, "release.ReleasesNew", nil)
+ return
+ }
+
+ ctx.Data["Title"] = "New Release"
+ 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"] = "New Release"
+ ctx.Data["IsRepoToolbarReleases"] = true
+ ctx.Data["IsRepoReleaseNew"] = true
+
+ if ctx.HasError() {
+ ctx.HTML(200, RELEASE_NEW)
+ return
+ }
+
+ commitsCount, err := ctx.Repo.Commit.CommitsCount()
+ if err != nil {
+ ctx.Handle(500, "release.ReleasesNewPost(CommitsCount)", err)
+ return
+ }
+
+ if !ctx.Repo.GitRepo.IsBranchExist(form.Target) {
+ ctx.RenderWithErr("Target branch does not exist", "release/new", &form)
+ return
+ }
+
+ rel := &models.Release{
+ RepoId: ctx.Repo.Repository.Id,
+ PublisherId: ctx.User.Id,
+ Title: form.Title,
+ TagName: form.TagName,
+ Target: form.Target,
+ Sha1: ctx.Repo.Commit.Id.String(),
+ NumCommits: commitsCount,
+ Note: form.Content,
+ IsDraft: len(form.Draft) > 0,
+ IsPrerelease: form.Prerelease,
+ }
+
+ if err = models.CreateRelease(ctx.Repo.GitRepo, rel); err != nil {
+ if err == models.ErrReleaseAlreadyExist {
+ ctx.RenderWithErr("Release with this tag name has already existed", "release/new", &form)
+ } else {
+ ctx.Handle(500, "release.ReleasesNewPost(IsReleaseExist)", err)
+ }
+ return
+ }
+ log.Trace("%s Release created: %s/%s:%s", ctx.Req.RequestURI, 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
+ }
+
+ tagName := ctx.Params(":tagname")
+ rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName)
+ if err != nil {
+ if err == models.ErrReleaseNotExist {
+ ctx.Handle(404, "release.ReleasesEdit(GetRelease)", err)
+ } else {
+ ctx.Handle(500, "release.ReleasesEdit(GetRelease)", err)
+ }
+ return
+ }
+ ctx.Data["Release"] = rel
+
+ ctx.Data["Title"] = "Edit Release"
+ ctx.Data["IsRepoToolbarReleases"] = true
+ ctx.HTML(200, RELEASE_EDIT)
+}
+
+func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) {
+ if !ctx.Repo.IsOwner {
+ ctx.Handle(403, "release.EditReleasePost", nil)
+ return
+ }
+
+ tagName := ctx.Params(":tagname")
+ rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName)
+ if err != nil {
+ if err == models.ErrReleaseNotExist {
+ ctx.Handle(404, "release.EditReleasePost(GetRelease)", err)
+ } else {
+ ctx.Handle(500, "release.EditReleasePost(GetRelease)", err)
+ }
+ return
+ }
+ ctx.Data["Release"] = rel
+
+ if ctx.HasError() {
+ ctx.HTML(200, RELEASE_EDIT)
+ return
+ }
+
+ ctx.Data["Title"] = "Edit Release"
+ ctx.Data["IsRepoToolbarReleases"] = true
+
+ rel.Title = form.Title
+ rel.Note = form.Content
+ rel.IsDraft = len(form.Draft) > 0
+ rel.IsPrerelease = form.Prerelease
+ if err = models.UpdateRelease(ctx.Repo.GitRepo, rel); err != nil {
+ ctx.Handle(500, "release.EditReleasePost(UpdateRelease)", err)
+ return
+ }
+ ctx.Redirect(ctx.Repo.RepoLink + "/releases")
+}
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index d1e196a0bd..8de1e0936e 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -5,8 +5,10 @@
package repo
import (
+ "fmt"
"os"
"path"
+ "strings"
"github.com/Unknwon/com"
@@ -34,22 +36,22 @@ func Create(ctx *middleware.Context) {
ctx.Data["Licenses"] = models.Licenses
ctxUser := ctx.User
- // orgId := com.StrTo(ctx.Query("org")).MustInt64()
- // if orgId > 0 {
- // org, err := models.GetUserById(orgId)
- // if err != nil && err != models.ErrUserNotExist {
- // ctx.Handle(500, "home.Dashboard(GetUserById)", err)
- // return
- // }
- // ctxUser = org
- // }
+ orgId := com.StrTo(ctx.Query("org")).MustInt64()
+ if orgId > 0 {
+ org, err := models.GetUserById(orgId)
+ if err != nil && err != models.ErrUserNotExist {
+ ctx.Handle(500, "home.Dashboard(GetUserById)", err)
+ return
+ }
+ ctxUser = org
+ }
ctx.Data["ContextUser"] = ctxUser
- // if err := ctx.User.GetOrganizations(); err != nil {
- // ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
- // return
- // }
- // ctx.Data["AllUsers"] = append([]*models.User{ctx.User}, ctx.User.Orgs...)
+ if err := ctx.User.GetOrganizations(); err != nil {
+ ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+ return
+ }
+ ctx.Data["AllUsers"] = append([]*models.User{ctx.User}, ctx.User.Orgs...)
ctx.HTML(200, CREATE)
}
@@ -62,22 +64,22 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
ctx.Data["Licenses"] = models.Licenses
ctxUser := ctx.User
- // orgId := com.StrTo(ctx.Query("org")).MustInt64()
- // if orgId > 0 {
- // org, err := models.GetUserById(orgId)
- // if err != nil && err != models.ErrUserNotExist {
- // ctx.Handle(500, "home.Dashboard(GetUserById)", err)
- // return
- // }
- // ctxUser = org
- // }
+ orgId := com.StrTo(ctx.Query("org")).MustInt64()
+ if orgId > 0 {
+ org, err := models.GetUserById(orgId)
+ if err != nil && err != models.ErrUserNotExist {
+ ctx.Handle(500, "home.Dashboard(GetUserById)", err)
+ return
+ }
+ ctxUser = org
+ }
ctx.Data["ContextUser"] = ctxUser
- // if err := ctx.User.GetOrganizations(); err != nil {
- // ctx.Handle(500, "home.CreatePost(GetOrganizations)", err)
- // return
- // }
- // ctx.Data["Orgs"] = ctx.User.Orgs
+ if err := ctx.User.GetOrganizations(); err != nil {
+ ctx.Handle(500, "home.CreatePost(GetOrganizations)", err)
+ return
+ }
+ ctx.Data["Orgs"] = ctx.User.Orgs
if ctx.HasError() {
ctx.HTML(200, CREATE)
@@ -127,78 +129,78 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
ctx.Handle(500, "CreateRepository", err)
}
-// func Migrate(ctx *middleware.Context) {
-// ctx.Data["Title"] = "Migrate repository"
-// ctx.Data["PageIsNewRepo"] = true
+func Migrate(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Migrate repository"
+ ctx.Data["PageIsNewRepo"] = true
-// if err := ctx.User.GetOrganizations(); err != nil {
-// ctx.Handle(500, "home.Migrate(GetOrganizations)", err)
-// return
-// }
-// ctx.Data["Orgs"] = ctx.User.Orgs
+ if err := ctx.User.GetOrganizations(); err != nil {
+ ctx.Handle(500, "home.Migrate(GetOrganizations)", err)
+ return
+ }
+ ctx.Data["Orgs"] = ctx.User.Orgs
-// ctx.HTML(200, MIGRATE)
-// }
+ ctx.HTML(200, MIGRATE)
+}
-// func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
-// ctx.Data["Title"] = "Migrate repository"
-// ctx.Data["PageIsNewRepo"] = true
+func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
+ ctx.Data["Title"] = "Migrate repository"
+ ctx.Data["PageIsNewRepo"] = true
-// if err := ctx.User.GetOrganizations(); err != nil {
-// ctx.Handle(500, "home.MigratePost(GetOrganizations)", err)
-// return
-// }
-// ctx.Data["Orgs"] = ctx.User.Orgs
+ if err := ctx.User.GetOrganizations(); err != nil {
+ ctx.Handle(500, "home.MigratePost(GetOrganizations)", err)
+ return
+ }
+ ctx.Data["Orgs"] = ctx.User.Orgs
-// if ctx.HasError() {
-// ctx.HTML(200, MIGRATE)
-// return
-// }
+ if ctx.HasError() {
+ ctx.HTML(200, MIGRATE)
+ return
+ }
-// u := ctx.User
-// // Not equal means current user is an organization.
-// if u.Id != form.Uid {
-// var err error
-// u, err = models.GetUserById(form.Uid)
-// if err != nil {
-// if err == models.ErrUserNotExist {
-// ctx.Handle(404, "home.MigratePost(GetUserById)", err)
-// } else {
-// ctx.Handle(500, "home.MigratePost(GetUserById)", err)
-// }
-// return
-// }
-// }
+ u := ctx.User
+ // Not equal means current user is an organization.
+ if u.Id != form.Uid {
+ var err error
+ u, err = models.GetUserById(form.Uid)
+ if err != nil {
+ if err == models.ErrUserNotExist {
+ ctx.Handle(404, "home.MigratePost(GetUserById)", err)
+ } else {
+ ctx.Handle(500, "home.MigratePost(GetUserById)", err)
+ }
+ return
+ }
+ }
-// authStr := strings.Replace(fmt.Sprintf("://%s:%s",
-// form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
-// url := strings.Replace(form.Url, "://", authStr+"@", 1)
-// repo, err := models.MigrateRepository(u, form.RepoName, form.Description, form.Private,
-// form.Mirror, url)
-// if err == nil {
-// log.Trace("%s Repository migrated: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName)
-// ctx.Redirect("/" + u.Name + "/" + form.RepoName)
-// return
-// } else if err == models.ErrRepoAlreadyExist {
-// ctx.RenderWithErr("Repository name has already been used", MIGRATE, &form)
-// return
-// } else if err == models.ErrRepoNameIllegal {
-// ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), MIGRATE, &form)
-// return
-// }
+ authStr := strings.Replace(fmt.Sprintf("://%s:%s",
+ form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
+ url := strings.Replace(form.Url, "://", authStr+"@", 1)
+ repo, err := models.MigrateRepository(u, form.RepoName, form.Description, form.Private,
+ form.Mirror, url)
+ if err == nil {
+ log.Trace("%s Repository migrated: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName)
+ ctx.Redirect("/" + u.Name + "/" + form.RepoName)
+ return
+ } else if err == models.ErrRepoAlreadyExist {
+ ctx.RenderWithErr("Repository name has already been used", MIGRATE, &form)
+ return
+ } else if err == models.ErrRepoNameIllegal {
+ ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), MIGRATE, &form)
+ return
+ }
-// if repo != nil {
-// if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
-// log.Error("repo.MigratePost(DeleteRepository): %v", errDelete)
-// }
-// }
+ if repo != nil {
+ if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
+ log.Error(4, "DeleteRepository: %v", errDelete)
+ }
+ }
-// if strings.Contains(err.Error(), "Authentication failed") {
-// ctx.RenderWithErr(err.Error(), MIGRATE, &form)
-// return
-// }
-// ctx.Handle(500, "repo.Migrate(MigrateRepository)", err)
-// }
+ if strings.Contains(err.Error(), "Authentication failed") {
+ ctx.RenderWithErr(err.Error(), MIGRATE, &form)
+ return
+ }
+ ctx.Handle(500, "MigrateRepository", err)
+}
// func Action(ctx *middleware.Context, params martini.Params) {
// var err error
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index 48f2e219ed..26f391346e 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -4,362 +4,362 @@
package repo
-// import (
-// "fmt"
-// "strings"
-// "time"
-
-// "github.com/go-martini/martini"
-
-// "github.com/gogits/gogs-ng/models"
-// "github.com/gogits/gogs/modules/auth"
-// "github.com/gogits/gogs/modules/base"
-// "github.com/gogits/gogs/modules/log"
-// "github.com/gogits/gogs/modules/mailer"
-// "github.com/gogits/gogs/modules/middleware"
-// "github.com/gogits/gogs/modules/setting"
-// )
-
-// const (
-// SETTING base.TplName = "repo/setting"
-// COLLABORATION base.TplName = "repo/collaboration"
-
-// HOOKS base.TplName = "repo/hooks"
-// HOOK_ADD base.TplName = "repo/hook_add"
-// HOOK_EDIT base.TplName = "repo/hook_edit"
-// )
-
-// func Setting(ctx *middleware.Context) {
-// ctx.Data["IsRepoToolbarSetting"] = true
-// ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - settings"
-// ctx.HTML(200, SETTING)
-// }
-
-// func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
-// ctx.Data["IsRepoToolbarSetting"] = true
-
-// switch ctx.Query("action") {
-// case "update":
-// if ctx.HasError() {
-// ctx.HTML(200, SETTING)
-// return
-// }
-
-// newRepoName := form.RepoName
-// // Check if repository name has been changed.
-// if ctx.Repo.Repository.Name != newRepoName {
-// isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName)
-// if err != nil {
-// ctx.Handle(500, "setting.SettingPost(update: check existence)", err)
-// return
-// } else if isExist {
-// ctx.RenderWithErr("Repository name has been taken in your repositories.", SETTING, nil)
-// return
-// } else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
-// ctx.Handle(500, "setting.SettingPost(change repository name)", err)
-// return
-// }
-// log.Trace("%s Repository name changed: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newRepoName)
-
-// ctx.Repo.Repository.Name = newRepoName
-// }
-
-// br := form.Branch
-
-// if ctx.Repo.GitRepo.IsBranchExist(br) {
-// ctx.Repo.Repository.DefaultBranch = br
-// }
-// ctx.Repo.Repository.Description = form.Description
-// ctx.Repo.Repository.Website = form.Website
-// ctx.Repo.Repository.IsPrivate = form.Private
-// ctx.Repo.Repository.IsGoget = form.GoGet
-// if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
-// ctx.Handle(404, "setting.SettingPost(update)", err)
-// return
-// }
-// log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
-
-// if ctx.Repo.Repository.IsMirror {
-// if form.Interval > 0 {
-// ctx.Repo.Mirror.Interval = form.Interval
-// ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(form.Interval) * time.Hour)
-// if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
-// log.Error("setting.SettingPost(UpdateMirror): %v", err)
-// }
-// }
-// }
-
-// ctx.Flash.Success("Repository options has been successfully updated.")
-// ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
-// case "transfer":
-// if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
-// ctx.RenderWithErr("Please make sure you entered repository name is correct.", SETTING, nil)
-// return
-// } else if ctx.Repo.Repository.IsMirror {
-// ctx.Error(404)
-// return
-// }
-
-// newOwner := ctx.Query("owner")
-// // Check if new owner exists.
-// isExist, err := models.IsUserExist(newOwner)
-// if err != nil {
-// ctx.Handle(500, "setting.SettingPost(transfer: check existence)", err)
-// return
-// } else if !isExist {
-// ctx.RenderWithErr("Please make sure you entered owner name is correct.", SETTING, nil)
-// return
-// } else if err = models.TransferOwnership(ctx.Repo.Owner, newOwner, ctx.Repo.Repository); err != nil {
-// ctx.Handle(500, "setting.SettingPost(transfer repository)", err)
-// return
-// }
-// log.Trace("%s Repository transfered: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newOwner)
-
-// ctx.Redirect("/")
-// case "delete":
-// if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
-// ctx.RenderWithErr("Please make sure you entered repository name is correct.", SETTING, nil)
-// return
-// }
-
-// if ctx.Repo.Owner.IsOrganization() &&
-// !ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
-// ctx.Error(403)
-// return
-// }
-
-// if err := models.DeleteRepository(ctx.Repo.Owner.Id, ctx.Repo.Repository.Id, ctx.Repo.Owner.Name); err != nil {
-// ctx.Handle(500, "setting.Delete(DeleteRepository)", err)
-// return
-// }
-// log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.LowerName, ctx.Repo.Repository.LowerName)
-
-// if ctx.Repo.Owner.IsOrganization() {
-// ctx.Redirect("/org/" + ctx.Repo.Owner.Name + "/dashboard")
-// } else {
-// ctx.Redirect("/")
-// }
-// }
-// }
-
-// func Collaboration(ctx *middleware.Context) {
-// repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/")
-// ctx.Data["IsRepoToolbarCollaboration"] = true
-// ctx.Data["Title"] = repoLink + " - collaboration"
-
-// // Delete collaborator.
-// remove := strings.ToLower(ctx.Query("remove"))
-// if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
-// if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil {
-// ctx.Handle(500, "setting.Collaboration(DeleteAccess)", err)
-// return
-// }
-// ctx.Flash.Success("Collaborator has been removed.")
-// ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
-// return
-// }
-
-// names, err := models.GetCollaboratorNames(repoLink)
-// if err != nil {
-// ctx.Handle(500, "setting.Collaboration(GetCollaborators)", err)
-// return
-// }
-
-// us := make([]*models.User, len(names))
-// for i, name := range names {
-// us[i], err = models.GetUserByName(name)
-// if err != nil {
-// ctx.Handle(500, "setting.Collaboration(GetUserByName)", err)
-// return
-// }
-// }
-
-// ctx.Data["Collaborators"] = us
-// ctx.HTML(200, COLLABORATION)
-// }
-
-// func CollaborationPost(ctx *middleware.Context) {
-// repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/")
-// name := strings.ToLower(ctx.Query("collaborator"))
-// if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
-// ctx.Redirect(ctx.Req.RequestURI)
-// return
-// }
-// has, err := models.HasAccess(name, repoLink, models.WRITABLE)
-// if err != nil {
-// ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err)
-// return
-// } else if has {
-// ctx.Redirect(ctx.Req.RequestURI)
-// return
-// }
-
-// u, err := models.GetUserByName(name)
-// if err != nil {
-// if err == models.ErrUserNotExist {
-// ctx.Flash.Error("Given user does not exist.")
-// ctx.Redirect(ctx.Req.RequestURI)
-// } else {
-// ctx.Handle(500, "setting.CollaborationPost(GetUserByName)", err)
-// }
-// return
-// }
-
-// if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink,
-// Mode: models.WRITABLE}); err != nil {
-// ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err)
-// return
-// }
-
-// if setting.Service.EnableNotifyMail {
-// if err = mailer.SendCollaboratorMail(ctx.Render, u, ctx.User, ctx.Repo.Repository); err != nil {
-// ctx.Handle(500, "setting.CollaborationPost(SendCollaboratorMail)", err)
-// return
-// }
-// }
-
-// ctx.Flash.Success("New collaborator has been added.")
-// ctx.Redirect(ctx.Req.RequestURI)
-// }
-
-// func WebHooks(ctx *middleware.Context) {
-// ctx.Data["IsRepoToolbarWebHooks"] = true
-// ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhooks"
-
-// // Delete webhook.
-// remove, _ := base.StrTo(ctx.Query("remove")).Int64()
-// if remove > 0 {
-// if err := models.DeleteWebhook(remove); err != nil {
-// ctx.Handle(500, "setting.WebHooks(DeleteWebhook)", err)
-// return
-// }
-// ctx.Flash.Success("Webhook has been removed.")
-// ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks")
-// return
-// }
-
-// ws, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.Id)
-// if err != nil {
-// ctx.Handle(500, "setting.WebHooks(GetWebhooksByRepoId)", err)
-// return
-// }
-
-// ctx.Data["Webhooks"] = ws
-// ctx.HTML(200, HOOKS)
-// }
-
-// func WebHooksAdd(ctx *middleware.Context) {
-// ctx.Data["IsRepoToolbarWebHooks"] = true
-// ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
-// ctx.HTML(200, HOOK_ADD)
-// }
-
-// func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
-// ctx.Data["IsRepoToolbarWebHooks"] = true
-// ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
-
-// if ctx.HasError() {
-// ctx.HTML(200, HOOK_ADD)
-// return
-// }
-
-// ct := models.JSON
-// if form.ContentType == "2" {
-// ct = models.FORM
-// }
-
-// w := &models.Webhook{
-// RepoId: ctx.Repo.Repository.Id,
-// Url: form.Url,
-// ContentType: ct,
-// Secret: form.Secret,
-// HookEvent: &models.HookEvent{
-// PushOnly: form.PushOnly,
-// },
-// IsActive: form.Active,
-// }
-// if err := w.UpdateEvent(); err != nil {
-// ctx.Handle(500, "setting.WebHooksAddPost(UpdateEvent)", err)
-// return
-// } else if err := models.CreateWebhook(w); err != nil {
-// ctx.Handle(500, "setting.WebHooksAddPost(CreateWebhook)", err)
-// return
-// }
-
-// ctx.Flash.Success("New webhook has been added.")
-// ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks")
-// }
-
-// func WebHooksEdit(ctx *middleware.Context, params martini.Params) {
-// ctx.Data["IsRepoToolbarWebHooks"] = true
-// ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook"
-
-// hookId, _ := base.StrTo(params["id"]).Int64()
-// if hookId == 0 {
-// ctx.Handle(404, "setting.WebHooksEdit", nil)
-// return
-// }
-
-// w, err := models.GetWebhookById(hookId)
-// if err != nil {
-// if err == models.ErrWebhookNotExist {
-// ctx.Handle(404, "setting.WebHooksEdit(GetWebhookById)", nil)
-// } else {
-// ctx.Handle(500, "setting.WebHooksEdit(GetWebhookById)", err)
-// }
-// return
-// }
-
-// w.GetEvent()
-// ctx.Data["Webhook"] = w
-// ctx.HTML(200, HOOK_EDIT)
-// }
-
-// func WebHooksEditPost(ctx *middleware.Context, params martini.Params, form auth.NewWebhookForm) {
-// ctx.Data["IsRepoToolbarWebHooks"] = true
-// ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook"
-
-// hookId, _ := base.StrTo(params["id"]).Int64()
-// if hookId == 0 {
-// ctx.Handle(404, "setting.WebHooksEditPost", nil)
-// return
-// }
-
-// w, err := models.GetWebhookById(hookId)
-// if err != nil {
-// if err == models.ErrWebhookNotExist {
-// ctx.Handle(404, "setting.WebHooksEditPost(GetWebhookById)", nil)
-// } else {
-// ctx.Handle(500, "setting.WebHooksEditPost(GetWebhookById)", err)
-// }
-// return
-// }
-
-// if ctx.HasError() {
-// ctx.HTML(200, HOOK_EDIT)
-// return
-// }
-
-// ct := models.JSON
-// if form.ContentType == "2" {
-// ct = models.FORM
-// }
-
-// w.Url = form.Url
-// w.ContentType = ct
-// w.Secret = form.Secret
-// w.HookEvent = &models.HookEvent{
-// PushOnly: form.PushOnly,
-// }
-// w.IsActive = form.Active
-// if err := w.UpdateEvent(); err != nil {
-// ctx.Handle(500, "setting.WebHooksEditPost(UpdateEvent)", err)
-// return
-// } else if err := models.UpdateWebhook(w); err != nil {
-// ctx.Handle(500, "setting.WebHooksEditPost(WebHooksEditPost)", err)
-// return
-// }
-
-// ctx.Flash.Success("Webhook has been updated.")
-// ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId))
-// }
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/Unknwon/com"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/auth"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/log"
+ "github.com/gogits/gogs/modules/mailer"
+ "github.com/gogits/gogs/modules/middleware"
+ "github.com/gogits/gogs/modules/setting"
+)
+
+const (
+ SETTING base.TplName = "repo/setting"
+ COLLABORATION base.TplName = "repo/collaboration"
+
+ HOOKS base.TplName = "repo/hooks"
+ HOOK_ADD base.TplName = "repo/hook_add"
+ HOOK_EDIT base.TplName = "repo/hook_edit"
+)
+
+func Setting(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarSetting"] = true
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - settings"
+ ctx.HTML(200, SETTING)
+}
+
+func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
+ ctx.Data["IsRepoToolbarSetting"] = true
+
+ switch ctx.Query("action") {
+ case "update":
+ if ctx.HasError() {
+ ctx.HTML(200, SETTING)
+ return
+ }
+
+ newRepoName := form.RepoName
+ // Check if repository name has been changed.
+ if ctx.Repo.Repository.Name != newRepoName {
+ isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName)
+ if err != nil {
+ ctx.Handle(500, "setting.SettingPost(update: check existence)", err)
+ return
+ } else if isExist {
+ ctx.RenderWithErr("Repository name has been taken in your repositories.", SETTING, nil)
+ return
+ } else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
+ ctx.Handle(500, "setting.SettingPost(change repository name)", err)
+ return
+ }
+ log.Trace("%s Repository name changed: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newRepoName)
+
+ ctx.Repo.Repository.Name = newRepoName
+ }
+
+ br := form.Branch
+
+ if ctx.Repo.GitRepo.IsBranchExist(br) {
+ ctx.Repo.Repository.DefaultBranch = br
+ }
+ ctx.Repo.Repository.Description = form.Description
+ ctx.Repo.Repository.Website = form.Website
+ ctx.Repo.Repository.IsPrivate = form.Private
+ ctx.Repo.Repository.IsGoget = form.GoGet
+ if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
+ ctx.Handle(404, "UpdateRepository", err)
+ return
+ }
+ log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
+
+ if ctx.Repo.Repository.IsMirror {
+ if form.Interval > 0 {
+ ctx.Repo.Mirror.Interval = form.Interval
+ ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(form.Interval) * time.Hour)
+ if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
+ log.Error(4, "UpdateMirror: %v", err)
+ }
+ }
+ }
+
+ ctx.Flash.Success("Repository options has been successfully updated.")
+ ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
+ case "transfer":
+ if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
+ ctx.RenderWithErr("Please make sure you entered repository name is correct.", SETTING, nil)
+ return
+ } else if ctx.Repo.Repository.IsMirror {
+ ctx.Error(404)
+ return
+ }
+
+ newOwner := ctx.Query("owner")
+ // Check if new owner exists.
+ isExist, err := models.IsUserExist(newOwner)
+ if err != nil {
+ ctx.Handle(500, "setting.SettingPost(transfer: check existence)", err)
+ return
+ } else if !isExist {
+ ctx.RenderWithErr("Please make sure you entered owner name is correct.", SETTING, nil)
+ return
+ } else if err = models.TransferOwnership(ctx.Repo.Owner, newOwner, ctx.Repo.Repository); err != nil {
+ ctx.Handle(500, "setting.SettingPost(transfer repository)", err)
+ return
+ }
+ log.Trace("%s Repository transfered: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newOwner)
+
+ ctx.Redirect("/")
+ case "delete":
+ if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
+ ctx.RenderWithErr("Please make sure you entered repository name is correct.", SETTING, nil)
+ return
+ }
+
+ if ctx.Repo.Owner.IsOrganization() &&
+ !ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
+ ctx.Error(403)
+ return
+ }
+
+ if err := models.DeleteRepository(ctx.Repo.Owner.Id, ctx.Repo.Repository.Id, ctx.Repo.Owner.Name); err != nil {
+ ctx.Handle(500, "setting.Delete(DeleteRepository)", err)
+ return
+ }
+ log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.LowerName, ctx.Repo.Repository.LowerName)
+
+ if ctx.Repo.Owner.IsOrganization() {
+ ctx.Redirect("/org/" + ctx.Repo.Owner.Name + "/dashboard")
+ } else {
+ ctx.Redirect("/")
+ }
+ }
+}
+
+func Collaboration(ctx *middleware.Context) {
+ repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/")
+ ctx.Data["IsRepoToolbarCollaboration"] = true
+ ctx.Data["Title"] = repoLink + " - collaboration"
+
+ // Delete collaborator.
+ remove := strings.ToLower(ctx.Query("remove"))
+ if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
+ if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil {
+ ctx.Handle(500, "setting.Collaboration(DeleteAccess)", err)
+ return
+ }
+ ctx.Flash.Success("Collaborator has been removed.")
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
+ return
+ }
+
+ names, err := models.GetCollaboratorNames(repoLink)
+ if err != nil {
+ ctx.Handle(500, "setting.Collaboration(GetCollaborators)", err)
+ return
+ }
+
+ us := make([]*models.User, len(names))
+ for i, name := range names {
+ us[i], err = models.GetUserByName(name)
+ if err != nil {
+ ctx.Handle(500, "setting.Collaboration(GetUserByName)", err)
+ return
+ }
+ }
+
+ ctx.Data["Collaborators"] = us
+ ctx.HTML(200, COLLABORATION)
+}
+
+func CollaborationPost(ctx *middleware.Context) {
+ repoLink := strings.TrimPrefix(ctx.Repo.RepoLink, "/")
+ name := strings.ToLower(ctx.Query("collaborator"))
+ if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
+ ctx.Redirect(ctx.Req.RequestURI)
+ return
+ }
+ has, err := models.HasAccess(name, repoLink, models.WRITABLE)
+ if err != nil {
+ ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err)
+ return
+ } else if has {
+ ctx.Redirect(ctx.Req.RequestURI)
+ return
+ }
+
+ u, err := models.GetUserByName(name)
+ if err != nil {
+ if err == models.ErrUserNotExist {
+ ctx.Flash.Error("Given user does not exist.")
+ ctx.Redirect(ctx.Req.RequestURI)
+ } else {
+ ctx.Handle(500, "setting.CollaborationPost(GetUserByName)", err)
+ }
+ return
+ }
+
+ if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink,
+ Mode: models.WRITABLE}); err != nil {
+ ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err)
+ return
+ }
+
+ if setting.Service.EnableNotifyMail {
+ if err = mailer.SendCollaboratorMail(ctx.Render, u, ctx.User, ctx.Repo.Repository); err != nil {
+ ctx.Handle(500, "setting.CollaborationPost(SendCollaboratorMail)", err)
+ return
+ }
+ }
+
+ ctx.Flash.Success("New collaborator has been added.")
+ ctx.Redirect(ctx.Req.RequestURI)
+}
+
+func WebHooks(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarWebHooks"] = true
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhooks"
+
+ // Delete webhook.
+ remove := com.StrTo(ctx.Query("remove")).MustInt64()
+ if remove > 0 {
+ if err := models.DeleteWebhook(remove); err != nil {
+ ctx.Handle(500, "setting.WebHooks(DeleteWebhook)", err)
+ return
+ }
+ ctx.Flash.Success("Webhook has been removed.")
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks")
+ return
+ }
+
+ ws, err := models.GetWebhooksByRepoId(ctx.Repo.Repository.Id)
+ if err != nil {
+ ctx.Handle(500, "setting.WebHooks(GetWebhooksByRepoId)", err)
+ return
+ }
+
+ ctx.Data["Webhooks"] = ws
+ ctx.HTML(200, HOOKS)
+}
+
+func WebHooksAdd(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarWebHooks"] = true
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
+ ctx.HTML(200, HOOK_ADD)
+}
+
+func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
+ ctx.Data["IsRepoToolbarWebHooks"] = true
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
+
+ if ctx.HasError() {
+ ctx.HTML(200, HOOK_ADD)
+ return
+ }
+
+ ct := models.JSON
+ if form.ContentType == "2" {
+ ct = models.FORM
+ }
+
+ w := &models.Webhook{
+ RepoId: ctx.Repo.Repository.Id,
+ Url: form.Url,
+ ContentType: ct,
+ Secret: form.Secret,
+ HookEvent: &models.HookEvent{
+ PushOnly: form.PushOnly,
+ },
+ IsActive: form.Active,
+ }
+ if err := w.UpdateEvent(); err != nil {
+ ctx.Handle(500, "setting.WebHooksAddPost(UpdateEvent)", err)
+ return
+ } else if err := models.CreateWebhook(w); err != nil {
+ ctx.Handle(500, "setting.WebHooksAddPost(CreateWebhook)", err)
+ return
+ }
+
+ ctx.Flash.Success("New webhook has been added.")
+ ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks")
+}
+
+func WebHooksEdit(ctx *middleware.Context) {
+ ctx.Data["IsRepoToolbarWebHooks"] = true
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook"
+
+ hookId := com.StrTo(ctx.Params(":id")).MustInt64()
+ if hookId == 0 {
+ ctx.Handle(404, "setting.WebHooksEdit", nil)
+ return
+ }
+
+ w, err := models.GetWebhookById(hookId)
+ if err != nil {
+ if err == models.ErrWebhookNotExist {
+ ctx.Handle(404, "setting.WebHooksEdit(GetWebhookById)", nil)
+ } else {
+ ctx.Handle(500, "setting.WebHooksEdit(GetWebhookById)", err)
+ }
+ return
+ }
+
+ w.GetEvent()
+ ctx.Data["Webhook"] = w
+ ctx.HTML(200, HOOK_EDIT)
+}
+
+func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
+ ctx.Data["IsRepoToolbarWebHooks"] = true
+ ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook"
+
+ hookId := com.StrTo(ctx.Params(":id")).MustInt64()
+ if hookId == 0 {
+ ctx.Handle(404, "setting.WebHooksEditPost", nil)
+ return
+ }
+
+ w, err := models.GetWebhookById(hookId)
+ if err != nil {
+ if err == models.ErrWebhookNotExist {
+ ctx.Handle(404, "GetWebhookById", nil)
+ } else {
+ ctx.Handle(500, "GetWebhookById", err)
+ }
+ return
+ }
+
+ if ctx.HasError() {
+ ctx.HTML(200, HOOK_EDIT)
+ return
+ }
+
+ ct := models.JSON
+ if form.ContentType == "2" {
+ ct = models.FORM
+ }
+
+ w.Url = form.Url
+ w.ContentType = ct
+ w.Secret = form.Secret
+ w.HookEvent = &models.HookEvent{
+ PushOnly: form.PushOnly,
+ }
+ w.IsActive = form.Active
+ if err := w.UpdateEvent(); err != nil {
+ ctx.Handle(500, "UpdateEvent", err)
+ return
+ } else if err := models.UpdateWebhook(w); err != nil {
+ ctx.Handle(500, "WebHooksEditPost", err)
+ return
+ }
+
+ ctx.Flash.Success("Webhook has been updated.")
+ ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId))
+}
diff --git a/routers/user/home.go b/routers/user/home.go
index 16e88a9427..b5a789ae0e 100644
--- a/routers/user/home.go
+++ b/routers/user/home.go
@@ -28,11 +28,11 @@ func Dashboard(ctx *middleware.Context) {
ctx.Data["PageIsDashboard"] = true
ctx.Data["PageIsNews"] = true
- // if err := ctx.User.GetOrganizations(); err != nil {
- // ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
- // return
- // }
- // ctx.Data["Orgs"] = ctx.User.Orgs
+ if err := ctx.User.GetOrganizations(); err != nil {
+ ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+ return
+ }
+ ctx.Data["Orgs"] = ctx.User.Orgs
ctx.Data["ContextUser"] = ctx.User
repos, err := models.GetRepositories(ctx.User.Id, true)
@@ -40,13 +40,16 @@ func Dashboard(ctx *middleware.Context) {
ctx.Handle(500, "GetRepositories", err)
return
}
+ for _, repo := range repos {
+ repo.Owner = ctx.User
+ }
ctx.Data["Repos"] = repos
- // ctx.Data["CollaborativeRepos"], err = models.GetCollaborativeRepos(ctx.User.Name)
- // if err != nil {
- // ctx.Handle(500, "home.Dashboard(GetCollaborativeRepos)", err)
- // return
- // }
+ ctx.Data["CollaborativeRepos"], err = models.GetCollaborativeRepos(ctx.User.Name)
+ if err != nil {
+ ctx.Handle(500, "GetCollaborativeRepos", err)
+ return
+ }
actions, err := models.GetFeeds(ctx.User.Id, 0, true)
if err != nil {
diff --git a/routers/user/setting.go b/routers/user/setting.go
index e4d6ff9ce7..761052144f 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -19,6 +19,7 @@ const (
SETTINGS_PASSWORD base.TplName = "user/settings/password"
SETTINGS_SSH_KEYS base.TplName = "user/settings/sshkeys"
SETTINGS_SOCIAL base.TplName = "user/settings/social"
+ SETTINGS_ORGS base.TplName = "user/settings/orgs"
SETTINGS_DELETE base.TplName = "user/settings/delete"
NOTIFICATION base.TplName = "user/notification"
SECURITY base.TplName = "user/security"
@@ -232,6 +233,13 @@ func SettingsSocial(ctx *middleware.Context) {
ctx.HTML(200, SETTINGS_SOCIAL)
}
+func SettingsOrgs(ctx *middleware.Context) {
+ ctx.Data["Title"] = ctx.Tr("settings")
+ ctx.Data["PageIsUserSettings"] = true
+ ctx.Data["PageIsSettingsOrgs"] = true
+ ctx.HTML(200, SETTINGS_ORGS)
+}
+
func SettingsDelete(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsUserSettings"] = true
diff --git a/templates/.VERSION b/templates/.VERSION
index 036f90911f..a4f4593d76 100644
--- a/templates/.VERSION
+++ b/templates/.VERSION
@@ -1 +1 @@
-0.4.7.0725 Alpha \ No newline at end of file
+0.4.7.0726 Alpha \ No newline at end of file
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 10a53b5397..34e710bf62 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -176,11 +176,11 @@
<dt>Enable Set Cookie</dt>
<dd><i class="fa fa{{if .SessionConfig.EnableSetCookie}}-check{{end}}-square-o"></i></dd>
<dt>GC Interval Time</dt>
- <dd>{{.SessionConfig.GcIntervalTime}} seconds</dd>
+ <dd>{{.SessionConfig.Gclifetime}} seconds</dd>
<dt>Session Life Time</dt>
- <dd>{{.SessionConfig.SessionLifeTime}} seconds</dd>
+ <dd>{{.SessionConfig.Maxlifetime}} seconds</dd>
<dt>HTTPS Only</dt>
- <dd><i class="fa fa{{if .SessionConfig.CookieSecure}}-check{{end}}-square-o"></i></dd>
+ <dd><i class="fa fa{{if .SessionConfig.Secure}}-check{{end}}-square-o"></i></dd>
<dt>Cookie Life Time</dt>
<dd>{{.SessionConfig.CookieLifeTime}} seconds</dd>
<dt>Session ID Hash Function</dt>
diff --git a/templates/ng/base/head.tmpl b/templates/ng/base/head.tmpl
index 0cd7686ffb..bab914bfe7 100644
--- a/templates/ng/base/head.tmpl
+++ b/templates/ng/base/head.tmpl
@@ -12,10 +12,10 @@
<!-- Stylesheet -->
<link rel="stylesheet" href="/ng/css/ui.css">
<link rel="stylesheet" href="/ng/css/gogs.css">
- <link rel="stylesheet" href="/ng/css/font-awesome.min.css">
+ <link rel="stylesheet" href="/css/font-awesome.min.css">
<link rel="stylesheet" href="/ng/fonts/octicons.css">
<!-- <link rel="stylesheet" href="http://cdn.bootcss.com/highlight.js/8.1/styles/github.min.css"> -->
- <link rel="stylesheet" href="/ng/css/github.min.css">
+ <link rel="stylesheet" href="/css/github.min.css">
<!-- JavaScript -->
<script src="/ng/js/lib/jquery-1.11.1.min.js"></script>
diff --git a/templates/repo/commits.tmpl b/templates/repo/commits.tmpl
index 385f9d5bae..420e973a50 100644
--- a/templates/repo/commits.tmpl
+++ b/templates/repo/commits.tmpl
@@ -34,7 +34,7 @@
<td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td>
<td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
<td class="message">{{.Summary}} </td>
- <td class="date">{{TimeSince .Author.When}}</td>
+ <td class="date">{{TimeSince .Author.When $.Lang}}</td>
</tr>
{{end}}
</tbody>
diff --git a/templates/repo/diff.tmpl b/templates/repo/diff.tmpl
index c85caa21ec..6adea04593 100644
--- a/templates/repo/diff.tmpl
+++ b/templates/repo/diff.tmpl
@@ -20,7 +20,7 @@
<p class="author">
<img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>
<a class="name" href="/user/email2user?email={{.Commit.Author.Email}}"><strong>{{.Commit.Author.Name}}</strong></a>
- <span class="time">{{TimeSince .Commit.Author.When}}</span>
+ <span class="time">{{TimeSince .Commit.Author.When $.Lang}}</span>
</p>
</div>
</div>
diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl
index ffbdcc8379..099e41b2dd 100644
--- a/templates/repo/issue/list.tmpl
+++ b/templates/repo/issue/list.tmpl
@@ -86,7 +86,7 @@
<p class="info">
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
<a href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
- <span class="time">{{TimeSince .Created}}</span>
+ <span class="time">{{TimeSince .Created $.Lang}}</span>
<span class="comment"><i class="fa fa-comments"></i> {{.NumComments}}</span>
</p>
</div>
diff --git a/templates/repo/issue/view.tmpl b/templates/repo/issue/view.tmpl
index aec50ca62e..c12de7dd7e 100644
--- a/templates/repo/issue/view.tmpl
+++ b/templates/repo/issue/view.tmpl
@@ -18,7 +18,7 @@
<a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="{{.RepoLink}}/issues/{{.Issue.Index}}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a>{{end}}
<span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span>
<a href="/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
- <span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments
+ <span class="time">{{TimeSince .Issue.Created $.Lang}}</span> · {{.Issue.NumComments}} comments
</p>
</div>
<div class="issue-main">
@@ -66,7 +66,7 @@
<a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content panel panel-default">
<div class="panel-heading">
- <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
+ <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created $.Lang}}</span>
<!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
<a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
<span class="role label label-default pull-right">Owner</span>
@@ -95,14 +95,14 @@
<div class="issue-child issue-opened">
<a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
<div class="issue-content">
- <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created}}</span>
+ <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
</div>
</div>
{{else if eq .Type 2}}
<div class="issue-child issue-closed">
<a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content">
- <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created}}</span>
+ <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
</div>
</div>
{{else if eq .Type 4}}
diff --git a/templates/status/401.tmpl b/templates/status/401.tmpl
index 6e24302fef..2c38d90fb5 100644
--- a/templates/status/401.tmpl
+++ b/templates/status/401.tmpl
@@ -1,6 +1,6 @@
-{{template "base/head" .}}
-{{template "base/header" .}}
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
<div class="container">
401 Unauthorized: {{.ErrorMsg}}
</div>
-{{template "base/footer" .}} \ No newline at end of file
+{{template "ng/base/footer" .}} \ No newline at end of file
diff --git a/templates/status/404.tmpl b/templates/status/404.tmpl
index 7062fb122e..2d04b55917 100644
--- a/templates/status/404.tmpl
+++ b/templates/status/404.tmpl
@@ -6,5 +6,6 @@
<br>
<p>Application Version: {{AppVer}}</p>
<p>If you think this is an error, please open an issue on <a href="https://github.com/gogits/gogs/issues/new">GitHub</a>.</p>
+ <h3>We're currently working on 0.5 beta version, many pages may be missing at this time. Sorry for confusion!</h3>
</div>
{{template "ng/base/footer" .}}
diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl
index e9027230a5..209a495b58 100644
--- a/templates/user/dashboard/dashboard.tmpl
+++ b/templates/user/dashboard/dashboard.tmpl
@@ -70,15 +70,7 @@
<div class="panel-body">
<ul class="list-no-style">
{{range .Repos}}
- <li {{if .IsPrivate}}class="private"{{end}}>
- <a href="{{$.ContextUser.Name}}/{{.Name}}">
- <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
- <span class="repo-name">
- <!-- <span class="repo-name-prefix">gogits / </span> -->
- <strong class="repo">{{.Name}}</strong>
- </span>
- </a>
- </li>
+ {{template "user/dashboard/repo_list" .}}
{{end}}
</ul>
</div>
@@ -87,42 +79,9 @@
</div>
<div class="panel-body">
<ul class="list-no-style">
- <li>
- <a href="#">
- <i class="octicon octicon-repo"></i>
- <span class="repo-name">
- <span class="repo-name-prefix">gogits / </span>
- <strong class="repo">gogs</strong>
- </span>
- <span class="right repo-star">
- <i class="octicon octicon-star"></i>2048
- </span>
- </a>
- </li>
- <li>
- <a href="#">
- <i class="octicon octicon-repo"></i>
- <span class="repo-name">
- <span class="repo-name-prefix">astaxie / </span>
- <strong class="repo">beego</strong>
- </span>
- <span class="right repo-star">
- <i class="octicon octicon-star"></i>2301
- </span>
- </a>
- </li>
- <li>
- <a href="#">
- <i class="octicon octicon-repo"></i>
- <span class="repo-name">
- <span class="repo-name-prefix">gogits / </span>
- <strong class="repo">scaffold</strong>
- </span>
- <span class="right repo-star">
- <i class="octicon octicon-star"></i>0
- </span>
- </a>
- </li>
+ {{range .CollaborativeRepos}}
+ {{template "user/dashboard/repo_list" .}}
+ {{end}}
</ul>
</div>
</div>
diff --git a/templates/user/dashboard/repo_list.tmpl b/templates/user/dashboard/repo_list.tmpl
new file mode 100644
index 0000000000..e3d35e8ecc
--- /dev/null
+++ b/templates/user/dashboard/repo_list.tmpl
@@ -0,0 +1,12 @@
+<li {{if .IsPrivate}}class="private"{{end}}>
+ <a href="{{.Owner.Name}}/{{.Name}}">
+ <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
+ <span class="repo-name">
+ <!-- <span class="repo-name-prefix">gogits / </span> -->
+ <strong class="repo">{{.Name}}</strong>
+ </span>
+ <span class="right repo-star">
+ <i class="octicon octicon-star"></i>{{.NumStars}}
+ </span>
+ </a>
+</li> \ No newline at end of file
diff --git a/templates/user/issues.tmpl b/templates/user/issues.tmpl
index c4ad64a4cf..93e798aa30 100644
--- a/templates/user/issues.tmpl
+++ b/templates/user/issues.tmpl
@@ -41,7 +41,7 @@
<p class="info">
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
<a href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
- <span class="time">{{TimeSince .Created}}</span>
+ <span class="time">{{TimeSince .Created $.Lang}}</span>
<span class="comment"><i class="fa fa-comments"></i> {{.NumComments}}</span>
</p>
</div>
diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl
index 0c9ada0130..4f80f1659d 100644
--- a/templates/user/profile.tmpl
+++ b/templates/user/profile.tmpl
@@ -50,8 +50,8 @@
<ul class="list-unstyled activity-list">
{{range .Feeds}}
<li>
- <i class="icon fa fa-{{ActionIcon .OpType}}"></i>
- <div class="info"><span class="meta">{{TimeSince .Created}}</span><br>{{ActionDesc . | str2html}}</div>
+ <i class="icon fa fa-{{ActionIcon .GetOpType}}"></i>
+ <div class="info"><span class="meta">{{TimeSince .Created $.Lang}}</span><br>{{ActionDesc . | str2html}}</div>
<span class="clearfix"></span>
</li>
{{else}}
@@ -69,7 +69,7 @@
<a href="/{{$.Owner.Name}}/{{.Name}}">{{.Name}}{{if .IsPrivate}} <span class="label label-default">Private</span>{{end}}</a>
</h4>
<p class="desc">{{.Description}}</p>
- <div class="info">Last updated {{.Updated|TimeSince}}</div>
+ <div class="info">Last updated {{TimeSince .Updated $.Lang}}</div>
</li>
{{end}}
</ul>
diff --git a/templates/user/settings/nav.tmpl b/templates/user/settings/nav.tmpl
index d6d20dee96..cae120527c 100644
--- a/templates/user/settings/nav.tmpl
+++ b/templates/user/settings/nav.tmpl
@@ -6,6 +6,7 @@
<li {{if .PageIsSettingsPassword}}class="current"{{end}}><a href="/user/settings/password">{{.i18n.Tr "settings.password"}}</a></li>
<li {{if .PageIsSettingsSSHKeys}}class="current"{{end}}><a href="/user/settings/ssh">{{.i18n.Tr "settings.ssh_keys"}}</a></li>
<li {{if .PageIsSettingsSocial}}class="current"{{end}}><a href="/user/settings/social">{{.i18n.Tr "settings.social"}}</a></li>
+ <li {{if .PageIsSettingsOrgs}}class="current"{{end}}><a href="/user/settings/orgs">{{.i18n.Tr "settings.orgs"}}</a></li>
<li {{if .PageIsSettingsDelete}}class="current"{{end}}><a href="/user/settings/delete">{{.i18n.Tr "settings.delete"}}</a></li>
</ul>
</div>
diff --git a/templates/user/settings/orgs.tmpl b/templates/user/settings/orgs.tmpl
new file mode 100644
index 0000000000..fb9096c3da
--- /dev/null
+++ b/templates/user/settings/orgs.tmpl
@@ -0,0 +1,18 @@
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+<div id="setting-wrapper" class="main-wrapper">
+ <div id="user-profile-setting" class="container clear">
+ {{template "user/settings/nav" .}}
+ <div class="grid-4-5 left">
+ <div class="setting-content">
+ {{template "ng/base/alert" .}}
+ <div id="setting-content">
+ <div id="user-profile-setting-content" class="panel panel-radius">
+ <p class="panel-header"><strong>{{.i18n.Tr "settings.manage_orgs"}}</strong></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{{template "ng/base/footer" .}} \ No newline at end of file