aboutsummaryrefslogtreecommitdiff
path: root/routers
diff options
context:
space:
mode:
Diffstat (limited to 'routers')
-rw-r--r--routers/admin/admin.go169
-rw-r--r--routers/admin/user.go144
-rw-r--r--routers/dashboard.go40
-rw-r--r--routers/dev/template.go25
-rw-r--r--routers/repo/branch.go38
-rw-r--r--routers/repo/commit.go41
-rw-r--r--routers/repo/issue.go125
-rw-r--r--routers/repo/pull.go21
-rw-r--r--routers/repo/repo.go365
-rw-r--r--routers/user/setting.go176
-rw-r--r--routers/user/user.go338
11 files changed, 1482 insertions, 0 deletions
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
new file mode 100644
index 00000000..0b5e3d8e
--- /dev/null
+++ b/routers/admin/admin.go
@@ -0,0 +1,169 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package admin
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/codegangsta/martini"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+var startTime = time.Now()
+
+var sysStatus struct {
+ Uptime string
+ NumGoroutine int
+
+ // General statistics.
+ MemAllocated string // bytes allocated and still in use
+ MemTotal string // bytes allocated (even if freed)
+ MemSys string // bytes obtained from system (sum of XxxSys below)
+ Lookups uint64 // number of pointer lookups
+ MemMallocs uint64 // number of mallocs
+ MemFrees uint64 // number of frees
+
+ // Main allocation heap statistics.
+ HeapAlloc string // bytes allocated and still in use
+ HeapSys string // bytes obtained from system
+ HeapIdle string // bytes in idle spans
+ HeapInuse string // bytes in non-idle span
+ HeapReleased string // bytes released to the OS
+ HeapObjects uint64 // total number of allocated objects
+
+ // Low-level fixed-size structure allocator statistics.
+ // Inuse is bytes used now.
+ // Sys is bytes obtained from system.
+ StackInuse string // bootstrap stacks
+ StackSys string
+ MSpanInuse string // mspan structures
+ MSpanSys string
+ MCacheInuse string // mcache structures
+ MCacheSys string
+ BuckHashSys string // profiling bucket hash table
+ GCSys string // GC metadata
+ OtherSys string // other system allocations
+
+ // Garbage collector statistics.
+ NextGC string // next run in HeapAlloc time (bytes)
+ LastGC string // last run in absolute time (ns)
+ PauseTotalNs string
+ PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
+ NumGC uint32
+}
+
+func updateSystemStatus() {
+ sysStatus.Uptime = base.TimeSincePro(startTime)
+
+ m := new(runtime.MemStats)
+ runtime.ReadMemStats(m)
+ sysStatus.NumGoroutine = runtime.NumGoroutine()
+
+ sysStatus.MemAllocated = base.FileSize(int64(m.Alloc))
+ sysStatus.MemTotal = base.FileSize(int64(m.TotalAlloc))
+ sysStatus.MemSys = base.FileSize(int64(m.Sys))
+ sysStatus.Lookups = m.Lookups
+ sysStatus.MemMallocs = m.Mallocs
+ sysStatus.MemFrees = m.Frees
+
+ sysStatus.HeapAlloc = base.FileSize(int64(m.HeapAlloc))
+ sysStatus.HeapSys = base.FileSize(int64(m.HeapSys))
+ sysStatus.HeapIdle = base.FileSize(int64(m.HeapIdle))
+ sysStatus.HeapInuse = base.FileSize(int64(m.HeapInuse))
+ sysStatus.HeapReleased = base.FileSize(int64(m.HeapReleased))
+ sysStatus.HeapObjects = m.HeapObjects
+
+ sysStatus.StackInuse = base.FileSize(int64(m.StackInuse))
+ sysStatus.StackSys = base.FileSize(int64(m.StackSys))
+ sysStatus.MSpanInuse = base.FileSize(int64(m.MSpanInuse))
+ sysStatus.MSpanSys = base.FileSize(int64(m.MSpanSys))
+ sysStatus.MCacheInuse = base.FileSize(int64(m.MCacheInuse))
+ sysStatus.MCacheSys = base.FileSize(int64(m.MCacheSys))
+ sysStatus.BuckHashSys = base.FileSize(int64(m.BuckHashSys))
+ sysStatus.GCSys = base.FileSize(int64(m.GCSys))
+ sysStatus.OtherSys = base.FileSize(int64(m.OtherSys))
+
+ sysStatus.NextGC = base.FileSize(int64(m.NextGC))
+ sysStatus.LastGC = fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000)
+ sysStatus.PauseTotalNs = fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000)
+ sysStatus.PauseNs = fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000)
+ sysStatus.NumGC = m.NumGC
+}
+
+func Dashboard(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Admin Dashboard"
+ ctx.Data["PageIsDashboard"] = true
+ ctx.Data["Stats"] = models.GetStatistic()
+ updateSystemStatus()
+ ctx.Data["SysStatus"] = sysStatus
+ ctx.HTML(200, "admin/dashboard")
+}
+
+func Users(ctx *middleware.Context) {
+ ctx.Data["Title"] = "User Management"
+ ctx.Data["PageIsUsers"] = true
+
+ var err error
+ ctx.Data["Users"], err = models.GetUsers(100, 0)
+ if err != nil {
+ ctx.Handle(200, "admin.Users", err)
+ return
+ }
+ ctx.HTML(200, "admin/users")
+}
+
+func Repositories(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Repository Management"
+ ctx.Data["PageIsRepos"] = true
+
+ var err error
+ ctx.Data["Repos"], err = models.GetRepos(100, 0)
+ if err != nil {
+ ctx.Handle(200, "admin.Repositories", err)
+ return
+ }
+ ctx.HTML(200, "admin/repos")
+}
+
+func Config(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Server Configuration"
+ ctx.Data["PageIsConfig"] = true
+
+ ctx.Data["AppUrl"] = base.AppUrl
+ ctx.Data["Domain"] = base.Domain
+ ctx.Data["RunUser"] = base.RunUser
+ ctx.Data["RunMode"] = strings.Title(martini.Env)
+ ctx.Data["EnableHttpsClone"] = base.EnableHttpsClone
+ ctx.Data["RepoRootPath"] = base.RepoRootPath
+
+ ctx.Data["Service"] = base.Service
+
+ ctx.Data["DbCfg"] = models.DbCfg
+
+ ctx.Data["MailerEnabled"] = false
+ if base.MailService != nil {
+ ctx.Data["MailerEnabled"] = true
+ ctx.Data["Mailer"] = base.MailService
+ }
+
+ ctx.Data["CacheAdapter"] = base.CacheAdapter
+ ctx.Data["CacheConfig"] = base.CacheConfig
+
+ ctx.Data["SessionProvider"] = base.SessionProvider
+ ctx.Data["SessionConfig"] = base.SessionConfig
+
+ ctx.Data["PictureService"] = base.PictureService
+
+ ctx.Data["LogMode"] = base.LogMode
+ ctx.Data["LogConfig"] = base.LogConfig
+
+ ctx.HTML(200, "admin/config")
+}
diff --git a/routers/admin/user.go b/routers/admin/user.go
new file mode 100644
index 00000000..7f66c552
--- /dev/null
+++ b/routers/admin/user.go
@@ -0,0 +1,144 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package admin
+
+import (
+ "strings"
+
+ "github.com/codegangsta/martini"
+
+ "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"
+)
+
+func NewUser(ctx *middleware.Context, form auth.RegisterForm) {
+ ctx.Data["Title"] = "New Account"
+ ctx.Data["PageIsUsers"] = true
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "admin/users/new")
+ return
+ }
+
+ if form.Password != form.RetypePasswd {
+ ctx.Data["HasError"] = true
+ ctx.Data["Err_Password"] = true
+ ctx.Data["Err_RetypePasswd"] = true
+ ctx.Data["ErrorMsg"] = "Password and re-type password are not same"
+ auth.AssignForm(form, ctx.Data)
+ }
+
+ if ctx.HasError() {
+ ctx.HTML(200, "admin/users/new")
+ return
+ }
+
+ u := &models.User{
+ Name: form.UserName,
+ Email: form.Email,
+ Passwd: form.Password,
+ IsActive: true,
+ }
+
+ var err error
+ if u, err = models.RegisterUser(u); err != nil {
+ switch err {
+ case models.ErrUserAlreadyExist:
+ ctx.RenderWithErr("Username has been already taken", "admin/users/new", &form)
+ case models.ErrEmailAlreadyUsed:
+ ctx.RenderWithErr("E-mail address has been already used", "admin/users/new", &form)
+ case models.ErrUserNameIllegal:
+ ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "admin/users/new", &form)
+ default:
+ ctx.Handle(200, "admin.user.NewUser", err)
+ }
+ return
+ }
+
+ log.Trace("%s User created by admin(%s): %s", ctx.Req.RequestURI,
+ ctx.User.LowerName, strings.ToLower(form.UserName))
+
+ ctx.Redirect("/admin/users")
+}
+
+func EditUser(ctx *middleware.Context, params martini.Params, form auth.AdminEditUserForm) {
+ ctx.Data["Title"] = "Edit Account"
+ ctx.Data["PageIsUsers"] = true
+
+ uid, err := base.StrTo(params["userid"]).Int()
+ if err != nil {
+ ctx.Handle(200, "admin.user.EditUser", err)
+ return
+ }
+
+ u, err := models.GetUserById(int64(uid))
+ if err != nil {
+ ctx.Handle(200, "admin.user.EditUser", err)
+ return
+ }
+
+ if ctx.Req.Method == "GET" {
+ ctx.Data["User"] = u
+ ctx.HTML(200, "admin/users/edit")
+ return
+ }
+
+ u.Email = form.Email
+ u.Website = form.Website
+ u.Location = form.Location
+ u.Avatar = base.EncodeMd5(form.Avatar)
+ u.AvatarEmail = form.Avatar
+ u.IsActive = form.Active == "on"
+ u.IsAdmin = form.Admin == "on"
+ if err := models.UpdateUser(u); err != nil {
+ ctx.Handle(200, "admin.user.EditUser", err)
+ return
+ }
+
+ ctx.Data["IsSuccess"] = true
+ ctx.Data["User"] = u
+ ctx.HTML(200, "admin/users/edit")
+
+ log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI,
+ ctx.User.LowerName, ctx.User.LowerName)
+}
+
+func DeleteUser(ctx *middleware.Context, params martini.Params) {
+ ctx.Data["Title"] = "Edit Account"
+ ctx.Data["PageIsUsers"] = true
+
+ uid, err := base.StrTo(params["userid"]).Int()
+ if err != nil {
+ ctx.Handle(200, "admin.user.EditUser", err)
+ return
+ }
+
+ u, err := models.GetUserById(int64(uid))
+ if err != nil {
+ ctx.Handle(200, "admin.user.EditUser", err)
+ return
+ }
+
+ if err = models.DeleteUser(u); err != nil {
+ ctx.Data["HasError"] = true
+ switch err {
+ case models.ErrUserOwnRepos:
+ ctx.Data["ErrorMsg"] = "This account still has ownership of repository, owner has to delete or transfer them first."
+ ctx.Data["User"] = u
+ ctx.HTML(200, "admin/users/edit")
+ default:
+ ctx.Handle(200, "admin.user.DeleteUser", err)
+ }
+ return
+ }
+
+ log.Trace("%s User deleted by admin(%s): %s", ctx.Req.RequestURI,
+ ctx.User.LowerName, ctx.User.LowerName)
+
+ ctx.Redirect("/admin/users")
+}
diff --git a/routers/dashboard.go b/routers/dashboard.go
new file mode 100644
index 00000000..2c81cf23
--- /dev/null
+++ b/routers/dashboard.go
@@ -0,0 +1,40 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package routers
+
+import (
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+ "github.com/gogits/gogs/routers/user"
+)
+
+func Home(ctx *middleware.Context) {
+ if ctx.IsSigned {
+ user.Dashboard(ctx)
+ return
+ }
+
+ // Check auto-login.
+ userName := ctx.GetCookie(base.CookieUserName)
+ if len(userName) != 0 {
+ ctx.Redirect("/user/login")
+ return
+ }
+
+ ctx.Data["PageIsHome"] = true
+ ctx.HTML(200, "home")
+}
+
+func Help(ctx *middleware.Context) {
+ ctx.Data["PageIsHelp"] = true
+ ctx.Data["Title"] = "Help"
+ ctx.HTML(200, "help")
+}
+
+func NotFound(ctx *middleware.Context) {
+ ctx.Data["PageIsNotFound"] = true
+ ctx.Data["Title"] = "Page Not Found"
+ ctx.Handle(404, "home.NotFound", nil)
+}
diff --git a/routers/dev/template.go b/routers/dev/template.go
new file mode 100644
index 00000000..d2f77ac4
--- /dev/null
+++ b/routers/dev/template.go
@@ -0,0 +1,25 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package dev
+
+import (
+ "github.com/codegangsta/martini"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/base"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+func TemplatePreview(ctx *middleware.Context, params martini.Params) {
+ ctx.Data["User"] = models.User{Name: "Unknown"}
+ ctx.Data["AppName"] = base.AppName
+ ctx.Data["AppVer"] = base.AppVer
+ ctx.Data["AppUrl"] = base.AppUrl
+ ctx.Data["AppLogo"] = base.AppLogo
+ ctx.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374"
+ ctx.Data["ActiveCodeLives"] = base.Service.ActiveCodeLives / 60
+ ctx.Data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives / 60
+ ctx.HTML(200, params["_1"])
+}
diff --git a/routers/repo/branch.go b/routers/repo/branch.go
new file mode 100644
index 00000000..8c953f2e
--- /dev/null
+++ b/routers/repo/branch.go
@@ -0,0 +1,38 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "github.com/codegangsta/martini"
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+func Branches(ctx *middleware.Context, params martini.Params) {
+ if !ctx.Repo.IsValid {
+ return
+ }
+
+ brs, err := models.GetBranches(params["username"], params["reponame"])
+ if err != nil {
+ ctx.Handle(200, "repo.Branches", err)
+ return
+ } else if len(brs) == 0 {
+ ctx.Handle(404, "repo.Branches", nil)
+ return
+ }
+
+ ctx.Data["Username"] = params["username"]
+ ctx.Data["Reponame"] = params["reponame"]
+
+ if len(params["branchname"]) == 0 {
+ params["branchname"] = "master"
+ }
+ ctx.Data["Branchname"] = params["branchname"]
+ ctx.Data["Branches"] = brs
+ ctx.Data["IsRepoToolbarBranches"] = true
+
+ ctx.HTML(200, "repo/branches")
+}
diff --git a/routers/repo/commit.go b/routers/repo/commit.go
new file mode 100644
index 00000000..e038998f
--- /dev/null
+++ b/routers/repo/commit.go
@@ -0,0 +1,41 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "github.com/codegangsta/martini"
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+func Commits(ctx *middleware.Context, params martini.Params) {
+ brs, err := models.GetBranches(params["username"], params["reponame"])
+ if err != nil {
+ ctx.Handle(200, "repo.Commits", err)
+ return
+ } else if len(brs) == 0 {
+ ctx.Handle(404, "repo.Commits", nil)
+ return
+ }
+
+ ctx.Data["IsRepoToolbarCommits"] = true
+ commits, err := models.GetCommits(params["username"],
+ params["reponame"], params["branchname"])
+ if err != nil {
+ ctx.Handle(404, "repo.Commits", nil)
+ return
+ }
+ ctx.Data["Username"] = params["username"]
+ ctx.Data["Reponame"] = params["reponame"]
+ ctx.Data["CommitCount"] = commits.Len()
+ ctx.Data["Commits"] = commits
+ ctx.HTML(200, "repo/commits")
+}
+
+func Diff(ctx *middleware.Context,params martini.Params){
+ ctx.Data["Title"] = "commit-sha"
+ ctx.Data["IsRepoToolbarCommits"] = true
+ ctx.HTML(200,"repo/diff")
+}
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
new file mode 100644
index 00000000..e03f115e
--- /dev/null
+++ b/routers/repo/issue.go
@@ -0,0 +1,125 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "fmt"
+
+ "github.com/codegangsta/martini"
+
+ "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"
+)
+
+func Issues(ctx *middleware.Context, params martini.Params) {
+ ctx.Data["Title"] = "Issues"
+ ctx.Data["IsRepoToolbarIssues"] = true
+
+ milestoneId, _ := base.StrTo(params["milestone"]).Int()
+ page, _ := base.StrTo(params["page"]).Int()
+
+ var err error
+ ctx.Data["Issues"], err = models.GetIssues(0, ctx.Repo.Repository.Id, 0,
+ int64(milestoneId), page, params["state"] == "closed", false, params["labels"], params["sortType"])
+ if err != nil {
+ ctx.Handle(200, "issue.Issues: %v", err)
+ return
+ }
+
+ if len(params["branchname"]) == 0 {
+ params["branchname"] = "master"
+ }
+ ctx.Data["Branchname"] = params["branchname"]
+ ctx.HTML(200, "repo/issues")
+}
+
+func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
+ if !ctx.Repo.IsOwner {
+ ctx.Handle(404, "issue.CreateIssue", nil)
+ return
+ }
+
+ ctx.Data["Title"] = "Create issue"
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "issue/create")
+ return
+ }
+
+ if ctx.HasError() {
+ ctx.HTML(200, "issue/create")
+ return
+ }
+
+ issue, err := models.CreateIssue(ctx.User.Id, form.RepoId, form.MilestoneId, form.AssigneeId,
+ form.IssueName, form.Labels, form.Content, false)
+ if err == nil {
+ log.Trace("%s Issue created: %d", form.RepoId, issue.Id)
+ ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
+ return
+ }
+ ctx.Handle(200, "issue.CreateIssue", err)
+}
+
+func ViewIssue(ctx *middleware.Context, params martini.Params) {
+ index, err := base.StrTo(params["index"]).Int()
+ if err != nil {
+ ctx.Handle(404, "issue.ViewIssue", err)
+ return
+ }
+
+ issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "issue.ViewIssue", err)
+ } else {
+ ctx.Handle(200, "issue.ViewIssue", err)
+ }
+ return
+ }
+
+ ctx.Data["Title"] = issue.Name
+ ctx.Data["Issue"] = issue
+ ctx.HTML(200, "issue/view")
+}
+
+func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
+ if !ctx.Repo.IsOwner {
+ ctx.Handle(404, "issue.UpdateIssue", nil)
+ return
+ }
+
+ index, err := base.StrTo(params["index"]).Int()
+ if err != nil {
+ ctx.Handle(404, "issue.UpdateIssue", err)
+ return
+ }
+
+ issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
+ if err != nil {
+ if err == models.ErrIssueNotExist {
+ ctx.Handle(404, "issue.UpdateIssue", err)
+ } else {
+ ctx.Handle(200, "issue.UpdateIssue", err)
+ }
+ return
+ }
+
+ issue.Name = form.IssueName
+ issue.MilestoneId = form.MilestoneId
+ issue.AssigneeId = form.AssigneeId
+ issue.Labels = form.Labels
+ issue.Content = form.Content
+ if err = models.UpdateIssue(issue); err != nil {
+ ctx.Handle(200, "issue.UpdateIssue", err)
+ return
+ }
+
+ ctx.Data["Title"] = issue.Name
+ ctx.Data["Issue"] = issue
+}
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
new file mode 100644
index 00000000..16c60389
--- /dev/null
+++ b/routers/repo/pull.go
@@ -0,0 +1,21 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "github.com/codegangsta/martini"
+
+ "github.com/gogits/gogs/modules/middleware"
+)
+
+func Pulls(ctx *middleware.Context, params martini.Params) {
+ ctx.Data["IsRepoToolbarPulls"] = true
+ if len(params["branchname"]) == 0 {
+ params["branchname"] = "master"
+ }
+
+ ctx.Data["Branchname"] = params["branchname"]
+ ctx.HTML(200, "repo/pulls")
+}
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
new file mode 100644
index 00000000..cd28d52c
--- /dev/null
+++ b/routers/repo/repo.go
@@ -0,0 +1,365 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "path"
+ "path/filepath"
+ "strings"
+
+ "github.com/codegangsta/martini"
+
+ "github.com/gogits/webdav"
+
+ "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"
+)
+
+func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
+ ctx.Data["Title"] = "Create repository"
+ ctx.Data["PageIsNewRepo"] = true // For navbar arrow.
+ ctx.Data["LanguageIgns"] = models.LanguageIgns
+ ctx.Data["Licenses"] = models.Licenses
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "repo/create")
+ return
+ }
+
+ if ctx.HasError() {
+ ctx.HTML(200, "repo/create")
+ return
+ }
+
+ _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
+ form.Language, form.License, form.Visibility == "private", form.InitReadme == "on")
+ if err == nil {
+ log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
+ ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
+ return
+ } else if err == models.ErrRepoAlreadyExist {
+ ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
+ return
+ } else if err == models.ErrRepoNameIllegal {
+ ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/create", &form)
+ return
+ }
+ ctx.Handle(200, "repo.Create", err)
+}
+
+func Single(ctx *middleware.Context, params martini.Params) {
+ if !ctx.Repo.IsValid {
+ return
+ }
+
+ if len(params["branchname"]) == 0 {
+ params["branchname"] = "master"
+ }
+
+ // Get tree path
+ treename := params["_1"]
+
+ if len(treename) > 0 && treename[len(treename)-1] == '/' {
+ ctx.Redirect("/" + ctx.Repo.Owner.LowerName + "/" +
+ ctx.Repo.Repository.Name + "/src/" + params["branchname"] + "/" + treename[:len(treename)-1])
+ return
+ }
+
+ ctx.Data["IsRepoToolbarSource"] = true
+
+ // Branches.
+ brs, err := models.GetBranches(params["username"], params["reponame"])
+ if err != nil {
+ //log.Error("repo.Single(GetBranches): %v", err)
+ ctx.Handle(404, "repo.Single(GetBranches)", err)
+ return
+ } else if ctx.Repo.Repository.IsBare {
+ ctx.Data["IsBareRepo"] = true
+ ctx.HTML(200, "repo/single")
+ return
+ }
+
+ ctx.Data["Branches"] = brs
+
+ repoFile, err := models.GetTargetFile(params["username"], params["reponame"],
+ params["branchname"], params["commitid"], treename)
+
+ if err != nil && err != models.ErrRepoFileNotExist {
+ //log.Error("repo.Single(GetTargetFile): %v", err)
+ ctx.Handle(404, "repo.Single(GetTargetFile)", err)
+ return
+ }
+
+ branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + params["branchname"]
+ rawLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/raw/" + params["branchname"]
+
+ if len(treename) != 0 && repoFile == nil {
+ ctx.Handle(404, "repo.Single", nil)
+ return
+ }
+
+ if repoFile != nil && repoFile.IsFile() {
+ if blob, err := repoFile.LookupBlob(); err != nil {
+ ctx.Handle(404, "repo.Single(repoFile.LookupBlob)", err)
+ } else {
+ ctx.Data["FileSize"] = repoFile.Size
+ ctx.Data["IsFile"] = true
+ ctx.Data["FileName"] = repoFile.Name
+ ext := path.Ext(repoFile.Name)
+ if len(ext) > 0 {
+ ext = ext[1:]
+ }
+ ctx.Data["FileExt"] = ext
+ ctx.Data["FileLink"] = rawLink + "/" + treename
+
+ data := blob.Contents()
+ _, isTextFile := base.IsTextFile(data)
+ ctx.Data["FileIsText"] = isTextFile
+
+ readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name)
+ ctx.Data["ReadmeExist"] = readmeExist
+ if readmeExist {
+ ctx.Data["FileContent"] = string(base.RenderMarkdown(data, ""))
+ } else {
+ if isTextFile {
+ ctx.Data["FileContent"] = string(data)
+ }
+ }
+ }
+
+ } else {
+ // Directory and file list.
+ files, err := models.GetReposFiles(params["username"], params["reponame"],
+ params["branchname"], params["commitid"], treename)
+ if err != nil {
+ //log.Error("repo.Single(GetReposFiles): %v", err)
+ ctx.Handle(404, "repo.Single(GetReposFiles)", err)
+ return
+ }
+
+ ctx.Data["Files"] = files
+
+ var readmeFile *models.RepoFile
+
+ for _, f := range files {
+ if !f.IsFile() || !base.IsReadmeFile(f.Name) {
+ continue
+ } else {
+ readmeFile = f
+ break
+ }
+ }
+
+ if readmeFile != nil {
+ ctx.Data["ReadmeInSingle"] = true
+ ctx.Data["ReadmeExist"] = true
+ if blob, err := readmeFile.LookupBlob(); err != nil {
+ ctx.Handle(404, "repo.Single(readmeFile.LookupBlob)", err)
+ return
+ } else {
+ ctx.Data["FileSize"] = readmeFile.Size
+ ctx.Data["FileLink"] = rawLink + "/" + treename
+ data := blob.Contents()
+ _, isTextFile := base.IsTextFile(data)
+ ctx.Data["FileIsText"] = isTextFile
+ ctx.Data["FileName"] = readmeFile.Name
+ if isTextFile {
+ ctx.Data["FileContent"] = string(base.RenderMarkdown(data, branchLink))
+ }
+ }
+ }
+ }
+
+ ctx.Data["Username"] = params["username"]
+ ctx.Data["Reponame"] = params["reponame"]
+ ctx.Data["Branchname"] = params["branchname"]
+
+ var treenames []string
+ Paths := make([]string, 0)
+
+ if len(treename) > 0 {
+ treenames = strings.Split(treename, "/")
+ for i, _ := range treenames {
+ Paths = append(Paths, strings.Join(treenames[0:i+1], "/"))
+ }
+
+ ctx.Data["HasParentPath"] = true
+ if len(Paths)-2 >= 0 {
+ ctx.Data["ParentPath"] = "/" + Paths[len(Paths)-2]
+ }
+ }
+
+ // Get latest commit according username and repo name
+ commit, err := models.GetCommit(params["username"], params["reponame"],
+ params["branchname"], params["commitid"])
+ if err != nil {
+ log.Error("repo.Single(GetCommit): %v", err)
+ ctx.Handle(404, "repo.Single(GetCommit)", err)
+ return
+ }
+ ctx.Data["LastCommit"] = commit
+
+ ctx.Data["Paths"] = Paths
+ ctx.Data["Treenames"] = treenames
+ ctx.Data["BranchLink"] = branchLink
+ ctx.HTML(200, "repo/single")
+}
+
+func SingleDownload(ctx *middleware.Context, params martini.Params) {
+ if !ctx.Repo.IsValid {
+ ctx.Handle(404, "repo.SingleDownload", nil)
+ return
+ }
+
+ if len(params["branchname"]) == 0 {
+ params["branchname"] = "master"
+ }
+
+ // Get tree path
+ treename := params["_1"]
+
+ repoFile, err := models.GetTargetFile(params["username"], params["reponame"],
+ params["branchname"], params["commitid"], treename)
+
+ if err != nil {
+ ctx.Handle(404, "repo.SingleDownload(GetTargetFile)", err)
+ return
+ }
+
+ blob, err := repoFile.LookupBlob()
+ if err != nil {
+ ctx.Handle(404, "repo.SingleDownload(LookupBlob)", err)
+ return
+ }
+
+ data := blob.Contents()
+ contentType, isTextFile := base.IsTextFile(data)
+ ctx.Res.Header().Set("Content-Type", contentType)
+ if !isTextFile {
+ ctx.Res.Header().Set("Content-Type", contentType)
+ ctx.Res.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(treename))
+ ctx.Res.Header().Set("Content-Transfer-Encoding", "binary")
+ }
+ ctx.Res.Write(data)
+}
+
+func Http(ctx *middleware.Context, params martini.Params) {
+ /*if !ctx.Repo.IsValid {
+ return
+ }*/
+
+ // TODO: access check
+
+ username := params["username"]
+ reponame := params["reponame"]
+ if strings.HasSuffix(reponame, ".git") {
+ reponame = reponame[:len(reponame)-4]
+ }
+
+ prefix := path.Join("/", username, params["reponame"])
+ server := &webdav.Server{
+ Fs: webdav.Dir(models.RepoPath(username, reponame)),
+ TrimPrefix: prefix,
+ Listings: true,
+ }
+
+ server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
+}
+
+func Setting(ctx *middleware.Context, params martini.Params) {
+ if !ctx.Repo.IsOwner {
+ ctx.Handle(404, "repo.Setting", nil)
+ return
+ }
+
+ ctx.Data["IsRepoToolbarSetting"] = true
+
+ if ctx.Repo.Repository.IsBare {
+ ctx.Data["IsBareRepo"] = true
+ ctx.HTML(200, "repo/setting")
+ return
+ }
+
+ var title string
+ if t, ok := ctx.Data["Title"].(string); ok {
+ title = t
+ }
+
+ if len(params["branchname"]) == 0 {
+ params["branchname"] = "master"
+ }
+
+ ctx.Data["Branchname"] = params["branchname"]
+ ctx.Data["Title"] = title + " - settings"
+ ctx.HTML(200, "repo/setting")
+}
+
+func SettingPost(ctx *middleware.Context) {
+ if !ctx.Repo.IsOwner {
+ ctx.Error(404)
+ return
+ }
+
+ switch ctx.Query("action") {
+ case "update":
+ ctx.Repo.Repository.Description = ctx.Query("desc")
+ ctx.Repo.Repository.Website = ctx.Query("site")
+ if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
+ ctx.Handle(404, "repo.SettingPost(update)", err)
+ return
+ }
+ ctx.Data["IsSuccess"] = true
+ ctx.HTML(200, "repo/setting")
+ log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
+ case "delete":
+ if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
+ ctx.Data["ErrorMsg"] = "Please make sure you entered repository name is correct."
+ ctx.HTML(200, "repo/setting")
+ return
+ }
+
+ if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil {
+ ctx.Handle(200, "repo.Delete", err)
+ return
+ }
+
+ log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName)
+ ctx.Redirect("/")
+ }
+}
+
+func Action(ctx *middleware.Context, params martini.Params) {
+ var err error
+ switch params["action"] {
+ case "watch":
+ err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, true)
+ case "unwatch":
+ err = models.WatchRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
+ case "desc":
+ if !ctx.Repo.IsOwner {
+ ctx.Error(404)
+ return
+ }
+
+ ctx.Repo.Repository.Description = ctx.Query("desc")
+ ctx.Repo.Repository.Website = ctx.Query("site")
+ err = models.UpdateRepository(ctx.Repo.Repository)
+ }
+
+ if err != nil {
+ log.Error("repo.Action(%s): %v", params["action"], err)
+ ctx.JSON(200, map[string]interface{}{
+ "ok": false,
+ "err": err.Error(),
+ })
+ return
+ }
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+}
diff --git a/routers/user/setting.go b/routers/user/setting.go
new file mode 100644
index 00000000..75adf2b8
--- /dev/null
+++ b/routers/user/setting.go
@@ -0,0 +1,176 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "strconv"
+
+ "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"
+)
+
+// Render user setting page (email, website modify)
+func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) {
+ ctx.Data["Title"] = "Setting"
+ ctx.Data["PageIsUserSetting"] = true // For navbar arrow.
+ ctx.Data["IsUserPageSetting"] = true // For setting nav highlight.
+
+ user := ctx.User
+ ctx.Data["Owner"] = user
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "user/setting")
+ return
+ }
+
+ // below is for POST requests
+ if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
+ ctx.HTML(200, "user/setting")
+ return
+ }
+
+ user.Email = form.Email
+ user.Website = form.Website
+ user.Location = form.Location
+ user.Avatar = base.EncodeMd5(form.Avatar)
+ user.AvatarEmail = form.Avatar
+ if err := models.UpdateUser(user); err != nil {
+ ctx.Handle(200, "setting.Setting", err)
+ return
+ }
+
+ ctx.Data["IsSuccess"] = true
+ ctx.HTML(200, "user/setting")
+
+ log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
+}
+
+func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
+ ctx.Data["Title"] = "Password"
+ ctx.Data["PageIsUserSetting"] = true
+ ctx.Data["IsUserPageSettingPasswd"] = true
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "user/password")
+ return
+ }
+
+ user := ctx.User
+ newUser := &models.User{Passwd: form.NewPasswd}
+ if err := newUser.EncodePasswd(); err != nil {
+ ctx.Handle(200, "setting.SettingPassword", err)
+ return
+ }
+
+ if user.Passwd != newUser.Passwd {
+ ctx.Data["HasError"] = true
+ ctx.Data["ErrorMsg"] = "Old password is not correct"
+ } else if form.NewPasswd != form.RetypePasswd {
+ ctx.Data["HasError"] = true
+ ctx.Data["ErrorMsg"] = "New password and re-type password are not same"
+ } else {
+ user.Passwd = newUser.Passwd
+ if err := models.UpdateUser(user); err != nil {
+ ctx.Handle(200, "setting.SettingPassword", err)
+ return
+ }
+ ctx.Data["IsSuccess"] = true
+ }
+
+ ctx.Data["Owner"] = user
+ ctx.HTML(200, "user/password")
+ log.Trace("%s User password updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
+}
+
+func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
+ ctx.Data["Title"] = "SSH Keys"
+
+ // Delete SSH key.
+ if ctx.Req.Method == "DELETE" || ctx.Query("_method") == "DELETE" {
+ id, err := strconv.ParseInt(ctx.Query("id"), 10, 64)
+ if err != nil {
+ log.Error("ssh.DelPublicKey: %v", err)
+ ctx.JSON(200, map[string]interface{}{
+ "ok": false,
+ "err": err.Error(),
+ })
+ return
+ }
+ k := &models.PublicKey{
+ Id: id,
+ OwnerId: ctx.User.Id,
+ }
+
+ if err = models.DeletePublicKey(k); err != nil {
+ log.Error("ssh.DelPublicKey: %v", err)
+ ctx.JSON(200, map[string]interface{}{
+ "ok": false,
+ "err": err.Error(),
+ })
+ } else {
+ log.Trace("%s User SSH key deleted: %s", ctx.Req.RequestURI, ctx.User.LowerName)
+ ctx.JSON(200, map[string]interface{}{
+ "ok": true,
+ })
+ }
+ return
+ }
+
+ // Add new SSH key.
+ if ctx.Req.Method == "POST" {
+ if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
+ ctx.HTML(200, "user/publickey")
+ return
+ }
+
+ k := &models.PublicKey{OwnerId: ctx.User.Id,
+ Name: form.KeyName,
+ Content: form.KeyContent,
+ }
+
+ if err := models.AddPublicKey(k); err != nil {
+ if err.Error() == models.ErrKeyAlreadyExist.Error() {
+ ctx.RenderWithErr("Public key name has been used", "user/publickey", &form)
+ return
+ }
+ ctx.Handle(200, "ssh.AddPublicKey", err)
+ log.Trace("%s User SSH key added: %s", ctx.Req.RequestURI, ctx.User.LowerName)
+ return
+ } else {
+ ctx.Data["AddSSHKeySuccess"] = true
+ }
+ }
+
+ // List existed SSH keys.
+ keys, err := models.ListPublicKey(ctx.User.Id)
+ if err != nil {
+ ctx.Handle(200, "ssh.ListPublicKey", err)
+ return
+ }
+
+ ctx.Data["PageIsUserSetting"] = true
+ ctx.Data["IsUserPageSettingSSH"] = true
+ ctx.Data["Keys"] = keys
+ ctx.HTML(200, "user/publickey")
+}
+
+func SettingNotification(ctx *middleware.Context) {
+ // TODO: user setting notification
+ ctx.Data["Title"] = "Notification"
+ ctx.Data["PageIsUserSetting"] = true
+ ctx.Data["IsUserPageSettingNotify"] = true
+ ctx.HTML(200, "user/notification")
+}
+
+func SettingSecurity(ctx *middleware.Context) {
+ // TODO: user setting security
+ ctx.Data["Title"] = "Security"
+ ctx.Data["PageIsUserSetting"] = true
+ ctx.Data["IsUserPageSettingSecurity"] = true
+ ctx.HTML(200, "user/security")
+}
diff --git a/routers/user/user.go b/routers/user/user.go
new file mode 100644
index 00000000..a0321f18
--- /dev/null
+++ b/routers/user/user.go
@@ -0,0 +1,338 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+ "net/url"
+ "strings"
+
+ "github.com/codegangsta/martini"
+
+ "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"
+)
+
+func Dashboard(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Dashboard"
+ ctx.Data["PageIsUserDashboard"] = true
+ repos, err := models.GetRepositories(&models.User{Id: ctx.User.Id})
+ if err != nil {
+ ctx.Handle(200, "user.Dashboard", err)
+ return
+ }
+ ctx.Data["MyRepos"] = repos
+
+ feeds, err := models.GetFeeds(ctx.User.Id, 0, false)
+ if err != nil {
+ ctx.Handle(200, "user.Dashboard", err)
+ return
+ }
+ ctx.Data["Feeds"] = feeds
+ ctx.HTML(200, "user/dashboard")
+}
+
+func Profile(ctx *middleware.Context, params martini.Params) {
+ ctx.Data["Title"] = "Profile"
+
+ // TODO: Need to check view self or others.
+ user, err := models.GetUserByName(params["username"])
+ if err != nil {
+ ctx.Handle(200, "user.Profile", err)
+ return
+ }
+
+ ctx.Data["Owner"] = user
+
+ tab := ctx.Query("tab")
+ ctx.Data["TabName"] = tab
+
+ switch tab {
+ case "activity":
+ feeds, err := models.GetFeeds(user.Id, 0, true)
+ if err != nil {
+ ctx.Handle(200, "user.Profile", err)
+ return
+ }
+ ctx.Data["Feeds"] = feeds
+ default:
+ repos, err := models.GetRepositories(user)
+ if err != nil {
+ ctx.Handle(200, "user.Profile", err)
+ return
+ }
+ ctx.Data["Repos"] = repos
+ }
+
+ ctx.Data["PageIsUserProfile"] = true
+ ctx.HTML(200, "user/profile")
+}
+
+func SignIn(ctx *middleware.Context, form auth.LogInForm) {
+ ctx.Data["Title"] = "Log In"
+
+ if ctx.Req.Method == "GET" {
+ // Check auto-login.
+ userName := ctx.GetCookie(base.CookieUserName)
+ if len(userName) == 0 {
+ ctx.HTML(200, "user/signin")
+ return
+ }
+
+ isSucceed := false
+ defer func() {
+ if !isSucceed {
+ log.Trace("%s auto-login cookie cleared: %s", ctx.Req.RequestURI, userName)
+ ctx.SetCookie(base.CookieUserName, "", -1)
+ ctx.SetCookie(base.CookieRememberName, "", -1)
+ }
+ }()
+
+ user, err := models.GetUserByName(userName)
+ if err != nil {
+ ctx.HTML(200, "user/signin")
+ return
+ }
+
+ secret := base.EncodeMd5(user.Rands + user.Passwd)
+ value, _ := ctx.GetSecureCookie(secret, base.CookieRememberName)
+ if value != user.Name {
+ ctx.HTML(200, "user/signin")
+ return
+ }
+
+ isSucceed = true
+ ctx.Session.Set("userId", user.Id)
+ ctx.Session.Set("userName", user.Name)
+ redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to"))
+ if len(redirectTo) > 0 {
+ ctx.SetCookie("redirect_to", "", -1)
+ ctx.Redirect(redirectTo)
+ } else {
+ ctx.Redirect("/")
+ }
+ return
+ }
+
+ if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
+ ctx.HTML(200, "user/signin")
+ return
+ }
+
+ user, err := models.LoginUserPlain(form.UserName, form.Password)
+ if err != nil {
+ if err == models.ErrUserNotExist {
+ log.Trace("%s Log in failed: %s/%s", ctx.Req.RequestURI, form.UserName, form.Password)
+ ctx.RenderWithErr("Username or password is not correct", "user/signin", &form)
+ return
+ }
+
+ ctx.Handle(200, "user.SignIn", err)
+ return
+ }
+
+ if form.Remember == "on" {
+ secret := base.EncodeMd5(user.Rands + user.Passwd)
+ days := 86400 * base.LogInRememberDays
+ ctx.SetCookie(base.CookieUserName, user.Name, days)
+ ctx.SetSecureCookie(secret, base.CookieRememberName, user.Name, days)
+ }
+
+ ctx.Session.Set("userId", user.Id)
+ ctx.Session.Set("userName", user.Name)
+ redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to"))
+ if len(redirectTo) > 0 {
+ ctx.SetCookie("redirect_to", "", -1)
+ ctx.Redirect(redirectTo)
+ } else {
+ ctx.Redirect("/")
+ }
+}
+
+func SignOut(ctx *middleware.Context) {
+ ctx.Session.Delete("userId")
+ ctx.Session.Delete("userName")
+ ctx.SetCookie(base.CookieUserName, "", -1)
+ ctx.SetCookie(base.CookieRememberName, "", -1)
+ ctx.Redirect("/")
+}
+
+func SignUp(ctx *middleware.Context, form auth.RegisterForm) {
+ ctx.Data["Title"] = "Sign Up"
+ ctx.Data["PageIsSignUp"] = true
+
+ if base.Service.DisenableRegisteration {
+ ctx.Data["DisenableRegisteration"] = true
+ ctx.HTML(200, "user/signup")
+ return
+ }
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "user/signup")
+ return
+ }
+
+ if form.Password != form.RetypePasswd {
+ ctx.Data["HasError"] = true
+ ctx.Data["Err_Password"] = true
+ ctx.Data["Err_RetypePasswd"] = true
+ ctx.Data["ErrorMsg"] = "Password and re-type password are not same"
+ auth.AssignForm(form, ctx.Data)
+ }
+
+ if ctx.HasError() {
+ ctx.HTML(200, "user/signup")
+ return
+ }
+
+ u := &models.User{
+ Name: form.UserName,
+ Email: form.Email,
+ Passwd: form.Password,
+ IsActive: !base.Service.RegisterEmailConfirm,
+ }
+
+ var err error
+ if u, err = models.RegisterUser(u); err != nil {
+ switch err {
+ case models.ErrUserAlreadyExist:
+ ctx.RenderWithErr("Username has been already taken", "user/signup", &form)
+ case models.ErrEmailAlreadyUsed:
+ ctx.RenderWithErr("E-mail address has been already used", "user/signup", &form)
+ case models.ErrUserNameIllegal:
+ ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "user/signup", &form)
+ default:
+ ctx.Handle(200, "user.SignUp", err)
+ }
+ return
+ }
+
+ log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName))
+
+ // Send confirmation e-mail.
+ if base.Service.RegisterEmailConfirm && u.Id > 1 {
+ mailer.SendRegisterMail(ctx.Render, u)
+ ctx.Data["IsSendRegisterMail"] = true
+ ctx.Data["Email"] = u.Email
+ ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
+ ctx.HTML(200, "user/active")
+
+ if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
+ log.Error("Set cache(MailResendLimit) fail: %v", err)
+ }
+ return
+ }
+ ctx.Redirect("/user/login")
+}
+
+func Delete(ctx *middleware.Context) {
+ ctx.Data["Title"] = "Delete Account"
+ ctx.Data["PageIsUserSetting"] = true
+ ctx.Data["IsUserPageSettingDelete"] = true
+
+ if ctx.Req.Method == "GET" {
+ ctx.HTML(200, "user/delete")
+ return
+ }
+
+ tmpUser := models.User{Passwd: ctx.Query("password")}
+ tmpUser.EncodePasswd()
+ if len(tmpUser.Passwd) == 0 || tmpUser.Passwd != ctx.User.Passwd {
+ ctx.Data["HasError"] = true
+ ctx.Data["ErrorMsg"] = "Password is not correct. Make sure you are owner of this account."
+ } else {
+ if err := models.DeleteUser(ctx.User); err != nil {
+ ctx.Data["HasError"] = true
+ switch err {
+ case models.ErrUserOwnRepos:
+ ctx.Data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first."
+ default:
+ ctx.Handle(200, "user.Delete", err)
+ return
+ }
+ } else {
+ ctx.Redirect("/")
+ return
+ }
+ }
+
+ ctx.HTML(200, "user/delete")
+}
+
+const (
+ TPL_FEED = `<i class="icon fa fa-%s"></i>
+ <div class="info"><span class="meta">%s</span><br>%s</div>`
+)
+
+func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
+ actions, err := models.GetFeeds(form.UserId, form.Page*20, false)
+ if err != nil {
+ ctx.JSON(500, err)
+ }
+
+ feeds := make([]string, len(actions))
+ for i := range actions {
+ feeds[i] = fmt.Sprintf(TPL_FEED, base.ActionIcon(actions[i].OpType),
+ base.TimeSince(actions[i].Created), base.ActionDesc(actions[i], ctx.User.AvatarLink()))
+ }
+ ctx.JSON(200, &feeds)
+}
+
+func Issues(ctx *middleware.Context) {
+ ctx.HTML(200, "user/issues")
+}
+
+func Pulls(ctx *middleware.Context) {
+ ctx.HTML(200, "user/pulls")
+}
+
+func Stars(ctx *middleware.Context) {
+ ctx.HTML(200, "user/stars")
+}
+
+func Activate(ctx *middleware.Context) {
+ code := ctx.Query("code")
+ if len(code) == 0 {
+ ctx.Data["IsActivatePage"] = true
+ if ctx.User.IsActive {
+ ctx.Handle(404, "user.Activate", nil)
+ return
+ }
+ // Resend confirmation e-mail.
+ if base.Service.RegisterEmailConfirm {
+ if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
+ ctx.Data["ResendLimited"] = true
+ } else {
+ ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
+ mailer.SendActiveMail(ctx.Render, ctx.User)
+ }
+ } else {
+ ctx.Data["ServiceNotEnabled"] = true
+ }
+ ctx.HTML(200, "user/active")
+ return
+ }
+
+ // Verify code.
+ if user := models.VerifyUserActiveCode(code); user != nil {
+ user.IsActive = true
+ user.Rands = models.GetUserSalt()
+ models.UpdateUser(user)
+
+ log.Trace("%s User activated: %s", ctx.Req.RequestURI, user.LowerName)
+
+ ctx.Session.Set("userId", user.Id)
+ ctx.Session.Set("userName", user.Name)
+ ctx.Redirect("/")
+ return
+ }
+
+ ctx.Data["IsActivateFailed"] = true
+ ctx.HTML(200, "user/active")
+}