fix
This commit is contained in:
parent
f3ed11d177
commit
a4cbe79567
165 changed files with 18302 additions and 0 deletions
168
routers/admin/admin.go
Normal file
168
routers/admin/admin.go
Normal file
|
@ -0,0 +1,168 @@
|
|||
// 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/go-martini/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["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")
|
||||
}
|
144
routers/admin/user.go
Normal file
144
routers/admin/user.go
Normal file
|
@ -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/go-martini/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")
|
||||
}
|
18
routers/api/v1/miscellaneous.go
Normal file
18
routers/api/v1/miscellaneous.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// 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 v1
|
||||
|
||||
import (
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
)
|
||||
|
||||
func Markdown(ctx *middleware.Context) {
|
||||
content := ctx.Query("content")
|
||||
ctx.Render.JSON(200, map[string]interface{}{
|
||||
"ok": true,
|
||||
"content": string(base.RenderMarkdown([]byte(content), ctx.Query("repoLink"))),
|
||||
})
|
||||
}
|
40
routers/dashboard.go
Normal file
40
routers/dashboard.go
Normal file
|
@ -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)
|
||||
}
|
25
routers/dev/template.go
Normal file
25
routers/dev/template.go
Normal file
|
@ -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/go-martini/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"])
|
||||
}
|
201
routers/install.go
Normal file
201
routers/install.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
// 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 (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/goconfig"
|
||||
"github.com/go-martini/martini"
|
||||
"github.com/lunny/xorm"
|
||||
qlog "github.com/qiniu/log"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// Check run mode(Default of martini is Dev).
|
||||
func checkRunMode() {
|
||||
switch base.Cfg.MustValue("", "RUN_MODE") {
|
||||
case "prod":
|
||||
martini.Env = martini.Prod
|
||||
base.IsProdMode = true
|
||||
case "test":
|
||||
martini.Env = martini.Test
|
||||
}
|
||||
log.Info("Run Mode: %s", strings.Title(martini.Env))
|
||||
}
|
||||
|
||||
// GlobalInit is for global configuration reload-able.
|
||||
func GlobalInit() {
|
||||
base.NewConfigContext()
|
||||
mailer.NewMailerContext()
|
||||
models.LoadModelsConfig()
|
||||
models.LoadRepoConfig()
|
||||
models.NewRepoContext()
|
||||
|
||||
if base.InstallLock {
|
||||
if err := models.NewEngine(); err != nil {
|
||||
qlog.Fatal(err)
|
||||
}
|
||||
|
||||
models.HasEngine = true
|
||||
}
|
||||
base.NewServices()
|
||||
checkRunMode()
|
||||
}
|
||||
|
||||
func Install(ctx *middleware.Context, form auth.InstallForm) {
|
||||
if base.InstallLock {
|
||||
ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = "Install"
|
||||
ctx.Data["PageIsInstall"] = true
|
||||
|
||||
if ctx.Req.Method == "GET" {
|
||||
// Get and assign value to install form.
|
||||
if len(form.Host) == 0 {
|
||||
form.Host = models.DbCfg.Host
|
||||
}
|
||||
if len(form.User) == 0 {
|
||||
form.User = models.DbCfg.User
|
||||
}
|
||||
if len(form.Passwd) == 0 {
|
||||
form.Passwd = models.DbCfg.Pwd
|
||||
}
|
||||
if len(form.DatabaseName) == 0 {
|
||||
form.DatabaseName = models.DbCfg.Name
|
||||
}
|
||||
if len(form.DatabasePath) == 0 {
|
||||
form.DatabasePath = models.DbCfg.Path
|
||||
}
|
||||
|
||||
if len(form.RepoRootPath) == 0 {
|
||||
form.RepoRootPath = base.RepoRootPath
|
||||
}
|
||||
if len(form.RunUser) == 0 {
|
||||
form.RunUser = base.RunUser
|
||||
}
|
||||
if len(form.Domain) == 0 {
|
||||
form.Domain = base.Domain
|
||||
}
|
||||
if len(form.AppUrl) == 0 {
|
||||
form.AppUrl = base.AppUrl
|
||||
}
|
||||
|
||||
auth.AssignForm(form, ctx.Data)
|
||||
ctx.HTML(200, "install")
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, "install")
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
ctx.RenderWithErr("Fail to test 'git' command: "+err.Error(), "install", &form)
|
||||
return
|
||||
}
|
||||
|
||||
// Pass basic check, now test configuration.
|
||||
// Test database setting.
|
||||
dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"}
|
||||
models.DbCfg.Type = dbTypes[form.Database]
|
||||
models.DbCfg.Host = form.Host
|
||||
models.DbCfg.User = form.User
|
||||
models.DbCfg.Pwd = form.Passwd
|
||||
models.DbCfg.Name = form.DatabaseName
|
||||
models.DbCfg.SslMode = form.SslMode
|
||||
models.DbCfg.Path = form.DatabasePath
|
||||
|
||||
// Set test engine.
|
||||
var x *xorm.Engine
|
||||
if err := models.NewTestEngine(x); err != nil {
|
||||
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
|
||||
ctx.RenderWithErr("Your release version does not support SQLite3, please download the official binary version "+
|
||||
"from https://github.com/gogits/gogs/wiki/Install-from-binary, NOT the gobuild version.", "install", &form)
|
||||
} else {
|
||||
ctx.RenderWithErr("Database setting is not correct: "+err.Error(), "install", &form)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Test repository root path.
|
||||
if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
|
||||
ctx.RenderWithErr("Repository root path is invalid: "+err.Error(), "install", &form)
|
||||
return
|
||||
}
|
||||
|
||||
// Check run user.
|
||||
curUser := os.Getenv("USERNAME")
|
||||
if len(curUser) == 0 {
|
||||
curUser = os.Getenv("USER")
|
||||
}
|
||||
// Does not check run user when the install lock is off.
|
||||
if form.RunUser != curUser {
|
||||
ctx.RenderWithErr("Run user isn't the current user: "+form.RunUser+" -> "+curUser, "install", &form)
|
||||
return
|
||||
}
|
||||
|
||||
// Save settings.
|
||||
base.Cfg.SetValue("database", "DB_TYPE", models.DbCfg.Type)
|
||||
base.Cfg.SetValue("database", "HOST", models.DbCfg.Host)
|
||||
base.Cfg.SetValue("database", "NAME", models.DbCfg.Name)
|
||||
base.Cfg.SetValue("database", "USER", models.DbCfg.User)
|
||||
base.Cfg.SetValue("database", "PASSWD", models.DbCfg.Pwd)
|
||||
base.Cfg.SetValue("database", "SSL_MODE", models.DbCfg.SslMode)
|
||||
base.Cfg.SetValue("database", "PATH", models.DbCfg.Path)
|
||||
|
||||
base.Cfg.SetValue("repository", "ROOT", form.RepoRootPath)
|
||||
base.Cfg.SetValue("", "RUN_USER", form.RunUser)
|
||||
base.Cfg.SetValue("server", "DOMAIN", form.Domain)
|
||||
base.Cfg.SetValue("server", "ROOT_URL", form.AppUrl)
|
||||
|
||||
if len(strings.TrimSpace(form.SmtpHost)) > 0 {
|
||||
base.Cfg.SetValue("mailer", "ENABLED", "true")
|
||||
base.Cfg.SetValue("mailer", "HOST", form.SmtpHost)
|
||||
base.Cfg.SetValue("mailer", "USER", form.SmtpEmail)
|
||||
base.Cfg.SetValue("mailer", "PASSWD", form.SmtpPasswd)
|
||||
|
||||
base.Cfg.SetValue("service", "REGISTER_EMAIL_CONFIRM", base.ToStr(form.RegisterConfirm == "on"))
|
||||
base.Cfg.SetValue("service", "ENABLE_NOTIFY_MAIL", base.ToStr(form.MailNotify == "on"))
|
||||
}
|
||||
|
||||
base.Cfg.SetValue("", "RUN_MODE", "prod")
|
||||
|
||||
base.Cfg.SetValue("security", "INSTALL_LOCK", "true")
|
||||
|
||||
os.MkdirAll("custom/conf", os.ModePerm)
|
||||
if err := goconfig.SaveConfigFile(base.Cfg, "custom/conf/app.ini"); err != nil {
|
||||
ctx.RenderWithErr("Fail to save configuration: "+err.Error(), "install", &form)
|
||||
return
|
||||
}
|
||||
|
||||
GlobalInit()
|
||||
|
||||
// Create admin account.
|
||||
if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd,
|
||||
IsAdmin: true, IsActive: true}); err != nil {
|
||||
if err != models.ErrUserAlreadyExist {
|
||||
base.InstallLock = false
|
||||
ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), "install", &form)
|
||||
return
|
||||
}
|
||||
log.Info("Admin account already exist")
|
||||
}
|
||||
|
||||
log.Info("First-time run install finished!")
|
||||
ctx.Redirect("/user/login")
|
||||
}
|
28
routers/repo/branch.go
Normal file
28
routers/repo/branch.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
// 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/go-martini/martini"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
)
|
||||
|
||||
func Branches(ctx *middleware.Context, params martini.Params) {
|
||||
brs, err := models.GetBranches(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||||
if err != nil {
|
||||
ctx.Handle(404, "repo.Branches", err)
|
||||
return
|
||||
} else if len(brs) == 0 {
|
||||
ctx.Handle(404, "repo.Branches", nil)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Branches"] = brs
|
||||
ctx.Data["IsRepoToolbarBranches"] = true
|
||||
|
||||
ctx.HTML(200, "repo/branches")
|
||||
}
|
92
routers/repo/commit.go
Normal file
92
routers/repo/commit.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
// 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 (
|
||||
"container/list"
|
||||
"path"
|
||||
|
||||
"github.com/go-martini/martini"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
)
|
||||
|
||||
func Commits(ctx *middleware.Context, params martini.Params) {
|
||||
userName := params["username"]
|
||||
repoName := params["reponame"]
|
||||
branchName := params["branchname"]
|
||||
|
||||
brs, err := models.GetBranches(userName, repoName)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "repo.Commits", err)
|
||||
return
|
||||
} else if len(brs) == 0 {
|
||||
ctx.Handle(404, "repo.Commits", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var commits *list.List
|
||||
if models.IsBranchExist(userName, repoName, branchName) {
|
||||
commits, err = models.GetCommitsByBranch(userName, repoName, branchName)
|
||||
} else {
|
||||
commits, err = models.GetCommitsByCommitId(userName, repoName, branchName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ctx.Handle(404, "repo.Commits", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Username"] = userName
|
||||
ctx.Data["Reponame"] = repoName
|
||||
ctx.Data["CommitCount"] = commits.Len()
|
||||
ctx.Data["Commits"] = commits
|
||||
ctx.Data["IsRepoToolbarCommits"] = true
|
||||
ctx.HTML(200, "repo/commits")
|
||||
}
|
||||
|
||||
func Diff(ctx *middleware.Context, params martini.Params) {
|
||||
userName := ctx.Repo.Owner.Name
|
||||
repoName := ctx.Repo.Repository.Name
|
||||
branchName := ctx.Repo.BranchName
|
||||
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", err)
|
||||
return
|
||||
}
|
||||
|
||||
isImageFile := func(name string) bool {
|
||||
repoFile, err := models.GetTargetFile(userName, repoName,
|
||||
branchName, commitId, name)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
blob, err := repoFile.LookupBlob()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
data := blob.Contents()
|
||||
_, isImage := base.IsImageFile(data)
|
||||
return isImage
|
||||
}
|
||||
|
||||
ctx.Data["IsImageFile"] = isImageFile
|
||||
ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId)
|
||||
ctx.Data["Commit"] = commit
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["IsRepoToolbarCommits"] = true
|
||||
ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
|
||||
ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId)
|
||||
ctx.HTML(200, "repo/diff")
|
||||
}
|
55
routers/repo/git.go
Normal file
55
routers/repo/git.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const advertise_refs = "--advertise-refs"
|
||||
|
||||
func command(cmd string, opts ...string) string {
|
||||
return fmt.Sprintf("git %s %s", cmd, strings.Join(opts, " "))
|
||||
}
|
||||
|
||||
/*func upload_pack(repository_path string, opts ...string) string {
|
||||
cmd = "upload-pack"
|
||||
opts = append(opts, "--stateless-rpc", repository_path)
|
||||
return command(cmd, opts...)
|
||||
}
|
||||
|
||||
func receive_pack(repository_path string, opts ...string) string {
|
||||
cmd = "receive-pack"
|
||||
opts = append(opts, "--stateless-rpc", repository_path)
|
||||
return command(cmd, opts...)
|
||||
}*/
|
||||
|
||||
/*func update_server_info(repository_path, opts = {}, &block)
|
||||
cmd = "update-server-info"
|
||||
args = []
|
||||
opts.each {|k,v| args << command_options[k] if command_options.has_key?(k) }
|
||||
opts[:args] = args
|
||||
Dir.chdir(repository_path) do # "git update-server-info" does not take a parameter to specify the repository, so set the working directory to the repository
|
||||
self.command(cmd, opts, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def get_config_setting(repository_path, key)
|
||||
path = get_config_location(repository_path)
|
||||
raise "Config file could not be found for repository in #{repository_path}." unless path
|
||||
self.command("config", {:args => ["-f #{path}", key]}).chomp
|
||||
end
|
||||
|
||||
def get_config_location(repository_path)
|
||||
non_bare = File.join(repository_path,'.git') # This is where the config file will be if the repository is non-bare
|
||||
if File.exists?(non_bare) then # The repository is non-bare
|
||||
non_bare_config = File.join(non_bare, 'config')
|
||||
return non_bare_config if File.exists?(non_bare_config)
|
||||
else # We are dealing with a bare repository
|
||||
bare_config = File.join(repository_path, "config")
|
||||
return bare_config if File.exists?(bare_config)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
*/
|
471
routers/repo/http.go
Normal file
471
routers/repo/http.go
Normal file
|
@ -0,0 +1,471 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-martini/martini"
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
)
|
||||
|
||||
func Http(ctx *middleware.Context, params martini.Params) {
|
||||
username := params["username"]
|
||||
reponame := params["reponame"]
|
||||
if strings.HasSuffix(reponame, ".git") {
|
||||
reponame = reponame[:len(reponame)-4]
|
||||
}
|
||||
|
||||
var isPull bool
|
||||
service := ctx.Query("service")
|
||||
if service == "git-receive-pack" ||
|
||||
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
|
||||
isPull = false
|
||||
} else if service == "git-upload-pack" ||
|
||||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
|
||||
isPull = true
|
||||
} else {
|
||||
isPull = (ctx.Req.Method == "GET")
|
||||
}
|
||||
|
||||
repoUser, err := models.GetUserByName(username)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "repo.GetUserByName", nil)
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "repo.GetRepositoryByName", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// only public pull don't need auth
|
||||
var askAuth = !(!repo.IsPrivate && isPull)
|
||||
|
||||
// check access
|
||||
if askAuth {
|
||||
baHead := ctx.Req.Header.Get("Authorization")
|
||||
if baHead == "" {
|
||||
// ask auth
|
||||
authRequired(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
auths := strings.Fields(baHead)
|
||||
// currently check basic auth
|
||||
// TODO: support digit auth
|
||||
if len(auths) != 2 || auths[0] != "Basic" {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
}
|
||||
authUsername, passwd, err := basicDecode(auths[1])
|
||||
if err != nil {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
}
|
||||
|
||||
authUser, err := models.GetUserByName(authUsername)
|
||||
if err != nil {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
}
|
||||
|
||||
newUser := &models.User{Passwd: passwd, Salt: authUser.Salt}
|
||||
|
||||
newUser.EncodePasswd()
|
||||
if authUser.Passwd != newUser.Passwd {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var tp = models.AU_WRITABLE
|
||||
if isPull {
|
||||
tp = models.AU_READABLE
|
||||
}
|
||||
|
||||
has, err := models.HasAccess(authUsername, username+"/"+reponame, tp)
|
||||
if err != nil {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
} else if !has {
|
||||
if tp == models.AU_READABLE {
|
||||
has, err = models.HasAccess(authUsername, username+"/"+reponame, models.AU_WRITABLE)
|
||||
if err != nil || !has {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config := Config{base.RepoRootPath, "git", true, true, func(rpc string, input []byte) {
|
||||
//fmt.Println("rpc:", rpc)
|
||||
//fmt.Println("input:", string(input))
|
||||
}}
|
||||
|
||||
handler := HttpBackend(&config)
|
||||
handler(ctx.ResponseWriter, ctx.Req)
|
||||
|
||||
/* Webdav
|
||||
dir := models.RepoPath(username, reponame)
|
||||
|
||||
prefix := path.Join("/", username, params["reponame"])
|
||||
server := webdav.NewServer(
|
||||
dir, prefix, true)
|
||||
|
||||
server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
|
||||
*/
|
||||
}
|
||||
|
||||
type route struct {
|
||||
cr *regexp.Regexp
|
||||
method string
|
||||
handler func(handler)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
ReposRoot string
|
||||
GitBinPath string
|
||||
UploadPack bool
|
||||
ReceivePack bool
|
||||
OnSucceed func(rpc string, input []byte)
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
*Config
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
Dir string
|
||||
File string
|
||||
}
|
||||
|
||||
var routes = []route{
|
||||
{regexp.MustCompile("(.*?)/git-upload-pack$"), "POST", serviceUploadPack},
|
||||
{regexp.MustCompile("(.*?)/git-receive-pack$"), "POST", serviceReceivePack},
|
||||
{regexp.MustCompile("(.*?)/info/refs$"), "GET", getInfoRefs},
|
||||
{regexp.MustCompile("(.*?)/HEAD$"), "GET", getTextFile},
|
||||
{regexp.MustCompile("(.*?)/objects/info/alternates$"), "GET", getTextFile},
|
||||
{regexp.MustCompile("(.*?)/objects/info/http-alternates$"), "GET", getTextFile},
|
||||
{regexp.MustCompile("(.*?)/objects/info/packs$"), "GET", getInfoPacks},
|
||||
{regexp.MustCompile("(.*?)/objects/info/[^/]*$"), "GET", getTextFile},
|
||||
{regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"), "GET", getLooseObject},
|
||||
{regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"), "GET", getPackFile},
|
||||
{regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"), "GET", getIdxFile},
|
||||
}
|
||||
|
||||
// Request handling function
|
||||
func HttpBackend(config *Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
//log.Printf("%s %s %s %s", r.RemoteAddr, r.Method, r.URL.Path, r.Proto)
|
||||
for _, route := range routes {
|
||||
if m := route.cr.FindStringSubmatch(r.URL.Path); m != nil {
|
||||
if route.method != r.Method {
|
||||
renderMethodNotAllowed(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
file := strings.Replace(r.URL.Path, m[1]+"/", "", 1)
|
||||
dir, err := getGitDir(config, m[1])
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
renderNotFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
hr := handler{config, w, r, dir, file}
|
||||
route.handler(hr)
|
||||
return
|
||||
}
|
||||
}
|
||||
renderNotFound(w)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Actual command handling functions
|
||||
|
||||
func serviceUploadPack(hr handler) {
|
||||
serviceRpc("upload-pack", hr)
|
||||
}
|
||||
|
||||
func serviceReceivePack(hr handler) {
|
||||
serviceRpc("receive-pack", hr)
|
||||
}
|
||||
|
||||
func serviceRpc(rpc string, hr handler) {
|
||||
w, r, dir := hr.w, hr.r, hr.Dir
|
||||
access := hasAccess(r, hr.Config, dir, rpc, true)
|
||||
|
||||
if access == false {
|
||||
renderNoAccess(w)
|
||||
return
|
||||
}
|
||||
|
||||
input, _ := ioutil.ReadAll(r.Body)
|
||||
|
||||
w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", rpc))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
args := []string{rpc, "--stateless-rpc", dir}
|
||||
cmd := exec.Command(hr.Config.GitBinPath, args...)
|
||||
cmd.Dir = dir
|
||||
in, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
in.Write(input)
|
||||
io.Copy(w, stdout)
|
||||
cmd.Wait()
|
||||
|
||||
if hr.Config.OnSucceed != nil {
|
||||
hr.Config.OnSucceed(rpc, input)
|
||||
}
|
||||
}
|
||||
|
||||
func getInfoRefs(hr handler) {
|
||||
w, r, dir := hr.w, hr.r, hr.Dir
|
||||
serviceName := getServiceType(r)
|
||||
access := hasAccess(r, hr.Config, dir, serviceName, false)
|
||||
|
||||
if access {
|
||||
args := []string{serviceName, "--stateless-rpc", "--advertise-refs", "."}
|
||||
refs := gitCommand(hr.Config.GitBinPath, dir, args...)
|
||||
|
||||
hdrNocache(w)
|
||||
w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", serviceName))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(packetWrite("# service=git-" + serviceName + "\n"))
|
||||
w.Write(packetFlush())
|
||||
w.Write(refs)
|
||||
} else {
|
||||
updateServerInfo(hr.Config.GitBinPath, dir)
|
||||
hdrNocache(w)
|
||||
sendFile("text/plain; charset=utf-8", hr)
|
||||
}
|
||||
}
|
||||
|
||||
func getInfoPacks(hr handler) {
|
||||
hdrCacheForever(hr.w)
|
||||
sendFile("text/plain; charset=utf-8", hr)
|
||||
}
|
||||
|
||||
func getLooseObject(hr handler) {
|
||||
hdrCacheForever(hr.w)
|
||||
sendFile("application/x-git-loose-object", hr)
|
||||
}
|
||||
|
||||
func getPackFile(hr handler) {
|
||||
hdrCacheForever(hr.w)
|
||||
sendFile("application/x-git-packed-objects", hr)
|
||||
}
|
||||
|
||||
func getIdxFile(hr handler) {
|
||||
hdrCacheForever(hr.w)
|
||||
sendFile("application/x-git-packed-objects-toc", hr)
|
||||
}
|
||||
|
||||
func getTextFile(hr handler) {
|
||||
hdrNocache(hr.w)
|
||||
sendFile("text/plain", hr)
|
||||
}
|
||||
|
||||
// Logic helping functions
|
||||
|
||||
func sendFile(contentType string, hr handler) {
|
||||
w, r := hr.w, hr.r
|
||||
reqFile := path.Join(hr.Dir, hr.File)
|
||||
|
||||
//fmt.Println("sendFile:", reqFile)
|
||||
|
||||
f, err := os.Stat(reqFile)
|
||||
if os.IsNotExist(err) {
|
||||
renderNotFound(w)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", f.Size()))
|
||||
w.Header().Set("Last-Modified", f.ModTime().Format(http.TimeFormat))
|
||||
http.ServeFile(w, r, reqFile)
|
||||
}
|
||||
|
||||
func getGitDir(config *Config, filePath string) (string, error) {
|
||||
root := config.ReposRoot
|
||||
|
||||
if root == "" {
|
||||
cwd, err := os.Getwd()
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
root = cwd
|
||||
}
|
||||
|
||||
f := path.Join(root, filePath)
|
||||
if _, err := os.Stat(f); os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func getServiceType(r *http.Request) string {
|
||||
serviceType := r.FormValue("service")
|
||||
|
||||
if s := strings.HasPrefix(serviceType, "git-"); !s {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.Replace(serviceType, "git-", "", 1)
|
||||
}
|
||||
|
||||
func hasAccess(r *http.Request, config *Config, dir string, rpc string, checkContentType bool) bool {
|
||||
if checkContentType {
|
||||
if r.Header.Get("Content-Type") != fmt.Sprintf("application/x-git-%s-request", rpc) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if !(rpc == "upload-pack" || rpc == "receive-pack") {
|
||||
return false
|
||||
}
|
||||
if rpc == "receive-pack" {
|
||||
return config.ReceivePack
|
||||
}
|
||||
if rpc == "upload-pack" {
|
||||
return config.UploadPack
|
||||
}
|
||||
|
||||
return getConfigSetting(config.GitBinPath, rpc, dir)
|
||||
}
|
||||
|
||||
func getConfigSetting(gitBinPath, serviceName string, dir string) bool {
|
||||
serviceName = strings.Replace(serviceName, "-", "", -1)
|
||||
setting := getGitConfig(gitBinPath, "http."+serviceName, dir)
|
||||
|
||||
if serviceName == "uploadpack" {
|
||||
return setting != "false"
|
||||
}
|
||||
|
||||
return setting == "true"
|
||||
}
|
||||
|
||||
func getGitConfig(gitBinPath, configName string, dir string) string {
|
||||
args := []string{"config", configName}
|
||||
out := string(gitCommand(gitBinPath, dir, args...))
|
||||
return out[0 : len(out)-1]
|
||||
}
|
||||
|
||||
func updateServerInfo(gitBinPath, dir string) []byte {
|
||||
args := []string{"update-server-info"}
|
||||
return gitCommand(gitBinPath, dir, args...)
|
||||
}
|
||||
|
||||
func gitCommand(gitBinPath, dir string, args ...string) []byte {
|
||||
command := exec.Command(gitBinPath, args...)
|
||||
command.Dir = dir
|
||||
out, err := command.Output()
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// HTTP error response handling functions
|
||||
|
||||
func renderMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Proto == "HTTP/1.1" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
w.Write([]byte("Method Not Allowed"))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("Bad Request"))
|
||||
}
|
||||
}
|
||||
|
||||
func renderNotFound(w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte("Not Found"))
|
||||
}
|
||||
|
||||
func renderNoAccess(w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
}
|
||||
|
||||
// Packet-line handling function
|
||||
|
||||
func packetFlush() []byte {
|
||||
return []byte("0000")
|
||||
}
|
||||
|
||||
func packetWrite(str string) []byte {
|
||||
s := strconv.FormatInt(int64(len(str)+4), 16)
|
||||
|
||||
if len(s)%4 != 0 {
|
||||
s = strings.Repeat("0", 4-len(s)%4) + s
|
||||
}
|
||||
|
||||
return []byte(s + str)
|
||||
}
|
||||
|
||||
// Header writing functions
|
||||
|
||||
func hdrNocache(w http.ResponseWriter) {
|
||||
w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
|
||||
w.Header().Set("Pragma", "no-cache")
|
||||
w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
|
||||
}
|
||||
|
||||
func hdrCacheForever(w http.ResponseWriter) {
|
||||
now := time.Now().Unix()
|
||||
expires := now + 31536000
|
||||
w.Header().Set("Date", fmt.Sprintf("%d", now))
|
||||
w.Header().Set("Expires", fmt.Sprintf("%d", expires))
|
||||
w.Header().Set("Cache-Control", "public, max-age=31536000")
|
||||
}
|
||||
|
||||
// Main
|
||||
/*
|
||||
func main() {
|
||||
http.HandleFunc("/", requestHandler())
|
||||
|
||||
err := http.ListenAndServe(":8080", nil)
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}*/
|
296
routers/repo/issue.go
Normal file
296
routers/repo/issue.go
Normal file
|
@ -0,0 +1,296 @@
|
|||
// 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"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-martini/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 Issues(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "Issues"
|
||||
ctx.Data["IsRepoToolbarIssues"] = true
|
||||
ctx.Data["IsRepoToolbarIssuesList"] = true
|
||||
ctx.Data["ViewType"] = "all"
|
||||
|
||||
milestoneId, _ := base.StrTo(ctx.Query("milestone")).Int()
|
||||
page, _ := base.StrTo(ctx.Query("page")).Int()
|
||||
|
||||
ctx.Data["IssueCreatedCount"] = 0
|
||||
|
||||
var posterId int64 = 0
|
||||
isCreatedBy := ctx.Query("type") == "created_by"
|
||||
if isCreatedBy {
|
||||
if !ctx.IsSigned {
|
||||
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
|
||||
ctx.Redirect("/user/login/", 302)
|
||||
return
|
||||
}
|
||||
ctx.Data["ViewType"] = "created_by"
|
||||
}
|
||||
|
||||
// Get issues.
|
||||
issues, err := models.GetIssues(0, ctx.Repo.Repository.Id, posterId, int64(milestoneId), page,
|
||||
ctx.Query("state") == "closed", false, ctx.Query("labels"), ctx.Query("sortType"))
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.Issues: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.IsSigned {
|
||||
posterId = ctx.User.Id
|
||||
}
|
||||
var createdByCount int
|
||||
|
||||
showIssues := make([]models.Issue, 0, len(issues))
|
||||
// Get posters.
|
||||
for i := range issues {
|
||||
u, err := models.GetUserById(issues[i].PosterId)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.Issues(get poster): %v", err)
|
||||
return
|
||||
}
|
||||
if isCreatedBy && u.Id != posterId {
|
||||
continue
|
||||
}
|
||||
if u.Id == posterId {
|
||||
createdByCount++
|
||||
}
|
||||
issues[i].Poster = u
|
||||
showIssues = append(showIssues, issues[i])
|
||||
}
|
||||
|
||||
ctx.Data["Issues"] = showIssues
|
||||
ctx.Data["IssueCount"] = ctx.Repo.Repository.NumIssues
|
||||
ctx.Data["OpenCount"] = ctx.Repo.Repository.NumOpenIssues
|
||||
ctx.Data["ClosedCount"] = ctx.Repo.Repository.NumClosedIssues
|
||||
ctx.Data["IssueCreatedCount"] = createdByCount
|
||||
ctx.Data["IsShowClosed"] = ctx.Query("state") == "closed"
|
||||
ctx.HTML(200, "issue/list")
|
||||
}
|
||||
|
||||
func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
|
||||
ctx.Data["Title"] = "Create issue"
|
||||
ctx.Data["IsRepoToolbarIssues"] = true
|
||||
ctx.Data["IsRepoToolbarIssuesList"] = false
|
||||
|
||||
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, ctx.Repo.Repository.Id, form.MilestoneId, form.AssigneeId,
|
||||
ctx.Repo.Repository.NumIssues, form.IssueName, form.Labels, form.Content, false)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue(CreateIssue)", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Notify watchers.
|
||||
if err = models.NotifyWatchers(&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, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue(NotifyWatchers)", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Mail watchers and mentions.
|
||||
if base.Service.NotifyMail {
|
||||
tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue(SendIssueNotifyMail)", err)
|
||||
return
|
||||
}
|
||||
|
||||
tos = append(tos, ctx.User.LowerName)
|
||||
ms := base.MentionPattern.FindAllString(issue.Content, -1)
|
||||
newTos := make([]string, 0, len(ms))
|
||||
for _, m := range ms {
|
||||
if com.IsSliceContainsStr(tos, m[1:]) {
|
||||
continue
|
||||
}
|
||||
|
||||
newTos = append(newTos, m[1:])
|
||||
}
|
||||
if err = mailer.SendIssueMentionMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository,
|
||||
issue, models.GetUserEmailsByNames(newTos)); err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue(SendIssueMentionMail)", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id)
|
||||
ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", params["username"], params["reponame"], issue.Index))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Get posters.
|
||||
u, err := models.GetUserById(issue.PosterId)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.ViewIssue(get poster): %v", err)
|
||||
return
|
||||
}
|
||||
issue.Poster = u
|
||||
issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
|
||||
|
||||
// Get comments.
|
||||
comments, err := models.GetIssueComments(issue.Id)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.ViewIssue(get comments): %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get posters.
|
||||
for i := range comments {
|
||||
u, err := models.GetUserById(comments[i].PosterId)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.ViewIssue(get poster): %v", err)
|
||||
return
|
||||
}
|
||||
comments[i].Poster = u
|
||||
comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink))
|
||||
}
|
||||
|
||||
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) {
|
||||
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(get issue)", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
|
||||
ctx.Handle(404, "issue.UpdateIssue", nil)
|
||||
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(update issue)", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"ok": true,
|
||||
"title": issue.Name,
|
||||
"content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)),
|
||||
})
|
||||
}
|
||||
|
||||
func Comment(ctx *middleware.Context, params martini.Params) {
|
||||
index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
|
||||
if err != nil {
|
||||
ctx.Handle(404, "issue.Comment(get index)", err)
|
||||
return
|
||||
}
|
||||
|
||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
|
||||
if err != nil {
|
||||
if err == models.ErrIssueNotExist {
|
||||
ctx.Handle(404, "issue.Comment", err)
|
||||
} else {
|
||||
ctx.Handle(200, "issue.Comment(get issue)", 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 {
|
||||
ctx.Handle(200, "issue.Comment(update issue status)", err)
|
||||
return
|
||||
}
|
||||
|
||||
cmtType := models.IT_CLOSE
|
||||
if !issue.IsClosed {
|
||||
cmtType = models.IT_REOPEN
|
||||
}
|
||||
|
||||
if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil {
|
||||
ctx.Handle(200, "issue.Comment(create status change comment)", err)
|
||||
return
|
||||
}
|
||||
log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed)
|
||||
}
|
||||
}
|
||||
|
||||
content := ctx.Query("content")
|
||||
if len(content) > 0 {
|
||||
switch params["action"] {
|
||||
case "new":
|
||||
if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil {
|
||||
ctx.Handle(500, "issue.Comment(create comment)", err)
|
||||
return
|
||||
}
|
||||
log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
|
||||
default:
|
||||
ctx.Handle(404, "issue.Comment", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
|
||||
}
|
16
routers/repo/pull.go
Normal file
16
routers/repo/pull.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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/go-martini/martini"
|
||||
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
)
|
||||
|
||||
func Pulls(ctx *middleware.Context, params martini.Params) {
|
||||
ctx.Data["IsRepoToolbarPulls"] = true
|
||||
ctx.HTML(200, "repo/pulls")
|
||||
}
|
30
routers/repo/release.go
Normal file
30
routers/repo/release.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
// 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/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
)
|
||||
|
||||
func Releases(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "Releases"
|
||||
ctx.Data["IsRepoToolbarReleases"] = true
|
||||
ctx.Data["IsRepoReleaseNew"] = false
|
||||
tags, err := models.GetTags(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||||
if err != nil {
|
||||
ctx.Handle(404, "repo.Releases(GetTags)", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Releases"] = tags
|
||||
ctx.HTML(200, "release/list")
|
||||
}
|
||||
|
||||
func ReleasesNew(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "New Release"
|
||||
ctx.Data["IsRepoToolbarReleases"] = true
|
||||
ctx.Data["IsRepoReleaseNew"] = true
|
||||
ctx.HTML(200, "release/new")
|
||||
}
|
426
routers/repo/repo.go
Normal file
426
routers/repo/repo.go
Normal file
|
@ -0,0 +1,426 @@
|
|||
// 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 (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-martini/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 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 Mirror(ctx *middleware.Context, form auth.CreateRepoForm) {
|
||||
ctx.Data["Title"] = "Mirror repository"
|
||||
ctx.Data["PageIsNewRepo"] = true // For navbar arrow.
|
||||
|
||||
if ctx.Req.Method == "GET" {
|
||||
ctx.HTML(200, "repo/mirror")
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, "repo/mirror")
|
||||
return
|
||||
}
|
||||
|
||||
_, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
|
||||
"", form.License, form.Visibility == "private", false)
|
||||
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/mirror", &form)
|
||||
return
|
||||
} else if err == models.ErrRepoNameIllegal {
|
||||
ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/mirror", &form)
|
||||
return
|
||||
}
|
||||
ctx.Handle(200, "repo.Mirror", err)
|
||||
}
|
||||
|
||||
func Single(ctx *middleware.Context, params martini.Params) {
|
||||
branchName := ctx.Repo.BranchName
|
||||
commitId := ctx.Repo.CommitId
|
||||
userName := ctx.Repo.Owner.Name
|
||||
repoName := ctx.Repo.Repository.Name
|
||||
|
||||
repoLink := ctx.Repo.RepoLink
|
||||
branchLink := ctx.Repo.RepoLink + "/src/" + branchName
|
||||
rawLink := ctx.Repo.RepoLink + "/raw/" + branchName
|
||||
|
||||
// Get tree path
|
||||
treename := params["_1"]
|
||||
|
||||
if len(treename) > 0 && treename[len(treename)-1] == '/' {
|
||||
ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1])
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsRepoToolbarSource"] = true
|
||||
|
||||
// Branches.
|
||||
brs, err := models.GetBranches(userName, repoName)
|
||||
if err != nil {
|
||||
ctx.Handle(404, "repo.Single(GetBranches)", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Branches"] = brs
|
||||
|
||||
isViewBranch := ctx.Repo.IsBranch
|
||||
ctx.Data["IsViewBranch"] = isViewBranch
|
||||
|
||||
repoFile, err := models.GetTargetFile(userName, repoName,
|
||||
branchName, commitId, treename)
|
||||
|
||||
if err != nil && err != models.ErrRepoFileNotExist {
|
||||
ctx.Handle(404, "repo.Single(GetTargetFile)", err)
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
_, isImageFile := base.IsImageFile(data)
|
||||
ctx.Data["FileIsText"] = isTextFile
|
||||
|
||||
if isImageFile {
|
||||
ctx.Data["IsImageFile"] = true
|
||||
} else {
|
||||
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(userName, repoName, ctx.Repo.CommitId, treename)
|
||||
if err != nil {
|
||||
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"] = userName
|
||||
ctx.Data["Reponame"] = repoName
|
||||
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["LastCommit"] = ctx.Repo.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) {
|
||||
// Get tree path
|
||||
treename := params["_1"]
|
||||
|
||||
branchName := params["branchname"]
|
||||
userName := params["username"]
|
||||
repoName := params["reponame"]
|
||||
|
||||
var commitId string
|
||||
if !models.IsBranchExist(userName, repoName, branchName) {
|
||||
commitId = branchName
|
||||
branchName = ""
|
||||
}
|
||||
|
||||
repoFile, err := models.GetTargetFile(userName, repoName,
|
||||
branchName, 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)
|
||||
_, isImageFile := base.IsImageFile(data)
|
||||
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(data)
|
||||
}
|
||||
|
||||
func basicEncode(username, password string) string {
|
||||
auth := username + ":" + password
|
||||
return base64.StdEncoding.EncodeToString([]byte(auth))
|
||||
}
|
||||
|
||||
func basicDecode(encoded string) (user string, name string, err error) {
|
||||
var s []byte
|
||||
s, err = base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
a := strings.Split(string(s), ":")
|
||||
if len(a) == 2 {
|
||||
user, name = a[0], a[1]
|
||||
} else {
|
||||
err = errors.New("decode failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func authRequired(ctx *middleware.Context) {
|
||||
ctx.ResponseWriter.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
|
||||
ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
|
||||
ctx.HTML(401, fmt.Sprintf("status/401"))
|
||||
}
|
||||
|
||||
func Setting(ctx *middleware.Context, params martini.Params) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
ctx.Handle(404, "repo.Setting", nil)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsRepoToolbarSetting"] = true
|
||||
|
||||
var title string
|
||||
if t, ok := ctx.Data["Title"].(string); ok {
|
||||
title = t
|
||||
}
|
||||
|
||||
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":
|
||||
isNameChanged := false
|
||||
newRepoName := ctx.Query("name")
|
||||
// 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(404, "repo.SettingPost(update: check existence)", err)
|
||||
return
|
||||
} else if isExist {
|
||||
ctx.RenderWithErr("Repository name has been taken in your repositories.", "repo/setting", nil)
|
||||
return
|
||||
} else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
|
||||
ctx.Handle(404, "repo.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)
|
||||
|
||||
isNameChanged = true
|
||||
ctx.Repo.Repository.Name = newRepoName
|
||||
}
|
||||
|
||||
ctx.Repo.Repository.Description = ctx.Query("desc")
|
||||
ctx.Repo.Repository.Website = ctx.Query("site")
|
||||
ctx.Repo.Repository.IsGoget = ctx.Query("goget") == "on"
|
||||
if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
|
||||
ctx.Handle(404, "repo.SettingPost(update)", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsSuccess"] = true
|
||||
if isNameChanged {
|
||||
ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
|
||||
} else {
|
||||
ctx.HTML(200, "repo/setting")
|
||||
}
|
||||
log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, 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.", "repo/setting", nil)
|
||||
return
|
||||
}
|
||||
|
||||
newOwner := ctx.Query("owner")
|
||||
// Check if new owner exists.
|
||||
isExist, err := models.IsUserExist(newOwner)
|
||||
if err != nil {
|
||||
ctx.Handle(404, "repo.SettingPost(transfer: check existence)", err)
|
||||
return
|
||||
} else if !isExist {
|
||||
ctx.RenderWithErr("Please make sure you entered owner name is correct.", "repo/setting", nil)
|
||||
return
|
||||
} else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
|
||||
ctx.Handle(404, "repo.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("/")
|
||||
return
|
||||
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.", "repo/setting", nil)
|
||||
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,
|
||||
})
|
||||
}
|
184
routers/user/setting.go
Normal file
184
routers/user/setting.go
Normal file
|
@ -0,0 +1,184 @@
|
|||
// 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.HasError() {
|
||||
ctx.HTML(200, "user/setting")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user name has been changed.
|
||||
if user.Name != form.UserName {
|
||||
isExist, err := models.IsUserExist(form.UserName)
|
||||
if err != nil {
|
||||
ctx.Handle(404, "user.Setting(update: check existence)", err)
|
||||
return
|
||||
} else if isExist {
|
||||
ctx.RenderWithErr("User name has been taken.", "user/setting", &form)
|
||||
return
|
||||
} else if err = models.ChangeUserName(user, form.UserName); err != nil {
|
||||
ctx.Handle(404, "user.Setting(change user name)", err)
|
||||
return
|
||||
}
|
||||
log.Trace("%s User name changed: %s -> %s", ctx.Req.RequestURI, user.Name, form.UserName)
|
||||
|
||||
user.Name = form.UserName
|
||||
}
|
||||
|
||||
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}
|
||||
newUser.EncodePasswd()
|
||||
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 {
|
||||
newUser.Salt = models.GetUserSalt()
|
||||
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")
|
||||
}
|
159
routers/user/social.go
Normal file
159
routers/user/social.go
Normal file
|
@ -0,0 +1,159 @@
|
|||
// 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 (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
"github.com/gogits/gogs/modules/oauth2"
|
||||
)
|
||||
|
||||
type SocialConnector interface {
|
||||
Identity() string
|
||||
Type() int
|
||||
Name() string
|
||||
Email() string
|
||||
Token() string
|
||||
}
|
||||
|
||||
type SocialGithub struct {
|
||||
data struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"login"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
WebToken *oauth.Token
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Identity() string {
|
||||
return strconv.Itoa(s.data.Id)
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Type() int {
|
||||
return models.OT_GITHUB
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Name() string {
|
||||
return s.data.Name
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Email() string {
|
||||
return s.data.Email
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Token() string {
|
||||
data, _ := json.Marshal(s.WebToken)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// Github API refer: https://developer.github.com/v3/users/
|
||||
func (s *SocialGithub) Update() error {
|
||||
scope := "https://api.github.com/user"
|
||||
transport := &oauth.Transport{
|
||||
Token: s.WebToken,
|
||||
}
|
||||
log.Debug("update github info")
|
||||
r, err := transport.Client().Get(scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
return json.NewDecoder(r.Body).Decode(&s.data)
|
||||
}
|
||||
|
||||
func extractPath(next string) string {
|
||||
n, err := url.Parse(next)
|
||||
if err != nil {
|
||||
return "/"
|
||||
}
|
||||
return n.Path
|
||||
}
|
||||
|
||||
// github && google && ...
|
||||
func SocialSignIn(ctx *middleware.Context, tokens oauth2.Tokens) {
|
||||
var socid int64
|
||||
var ok bool
|
||||
next := extractPath(ctx.Query("next"))
|
||||
log.Debug("social signed check %s", next)
|
||||
if socid, ok = ctx.Session.Get("socialId").(int64); ok && socid != 0 {
|
||||
// already login
|
||||
ctx.Redirect(next)
|
||||
log.Info("login soc id: %v", socid)
|
||||
return
|
||||
}
|
||||
config := &oauth.Config{
|
||||
//ClientId: base.OauthService.Github.ClientId,
|
||||
//ClientSecret: base.OauthService.Github.ClientSecret, // FIXME: I don't know why compile error here
|
||||
ClientId: "09383403ff2dc16daaa1",
|
||||
ClientSecret: "0e4aa0c3630df396cdcea01a9d45cacf79925fea",
|
||||
RedirectURL: strings.TrimSuffix(base.AppUrl, "/") + ctx.Req.URL.RequestURI(),
|
||||
Scope: base.OauthService.GitHub.Scopes,
|
||||
AuthURL: "https://github.com/login/oauth/authorize",
|
||||
TokenURL: "https://github.com/login/oauth/access_token",
|
||||
}
|
||||
transport := &oauth.Transport{
|
||||
Config: config,
|
||||
Transport: http.DefaultTransport,
|
||||
}
|
||||
code := ctx.Query("code")
|
||||
if code == "" {
|
||||
// redirect to social login page
|
||||
ctx.Redirect(config.AuthCodeURL(next))
|
||||
return
|
||||
}
|
||||
|
||||
// handle call back
|
||||
tk, err := transport.Exchange(code)
|
||||
if err != nil {
|
||||
log.Error("oauth2 handle callback error: %v", err)
|
||||
return // FIXME, need error page 501
|
||||
}
|
||||
next = extractPath(ctx.Query("state"))
|
||||
log.Debug("success token: %v", tk)
|
||||
|
||||
gh := &SocialGithub{WebToken: tk}
|
||||
if err = gh.Update(); err != nil {
|
||||
// FIXME: handle error page 501
|
||||
log.Error("connect with github error: %s", err)
|
||||
return
|
||||
}
|
||||
var soc SocialConnector = gh
|
||||
log.Info("login: %s", soc.Name())
|
||||
oa, err := models.GetOauth2(soc.Identity())
|
||||
switch err {
|
||||
case nil:
|
||||
ctx.Session.Set("userId", oa.User.Id)
|
||||
ctx.Session.Set("userName", oa.User.Name)
|
||||
case models.ErrOauth2RecordNotExists:
|
||||
oa = &models.Oauth2{}
|
||||
oa.Uid = 0
|
||||
oa.Type = soc.Type()
|
||||
oa.Token = soc.Token()
|
||||
oa.Identity = soc.Identity()
|
||||
log.Debug("oa: %v", oa)
|
||||
if err = models.AddOauth2(oa); err != nil {
|
||||
log.Error("add oauth2 %v", err) // 501
|
||||
return
|
||||
}
|
||||
case models.ErrOauth2NotAssociatedWithUser:
|
||||
// ignore it. judge in /usr/login page
|
||||
default:
|
||||
log.Error(err.Error()) // FIXME: handle error page
|
||||
return
|
||||
}
|
||||
ctx.Session.Set("socialId", oa.Id)
|
||||
log.Debug("socialId: %v", oa.Id)
|
||||
ctx.Redirect(next)
|
||||
}
|
514
routers/user/user.go
Normal file
514
routers/user/user.go
Normal file
|
@ -0,0 +1,514 @@
|
|||
// 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/go-martini/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" {
|
||||
if base.OauthService != nil {
|
||||
ctx.Data["OauthEnabled"] = true
|
||||
ctx.Data["OauthGitHubEnabled"] = base.OauthService.GitHub.Enabled
|
||||
}
|
||||
|
||||
// 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 ctx.HasError() {
|
||||
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.JSON(200, &feeds)
|
||||
}
|
||||
|
||||
func Issues(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "Your Issues"
|
||||
ctx.Data["ViewType"] = "all"
|
||||
|
||||
page, _ := base.StrTo(ctx.Query("page")).Int()
|
||||
repoId, _ := base.StrTo(ctx.Query("repoid")).Int64()
|
||||
|
||||
ctx.Data["RepoId"] = repoId
|
||||
|
||||
var posterId int64 = 0
|
||||
if ctx.Query("type") == "created_by" {
|
||||
posterId = ctx.User.Id
|
||||
ctx.Data["ViewType"] = "created_by"
|
||||
}
|
||||
|
||||
// Get all repositories.
|
||||
repos, err := models.GetRepositories(ctx.User)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "user.Issues(get repositories)", err)
|
||||
return
|
||||
}
|
||||
|
||||
showRepos := make([]models.Repository, 0, len(repos))
|
||||
|
||||
isShowClosed := ctx.Query("state") == "closed"
|
||||
var closedIssueCount, createdByCount, allIssueCount int
|
||||
|
||||
// Get all issues.
|
||||
allIssues := make([]models.Issue, 0, 5*len(repos))
|
||||
for i, repo := range repos {
|
||||
issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, isShowClosed, false, "", "")
|
||||
if err != nil {
|
||||
ctx.Handle(200, "user.Issues(get issues)", err)
|
||||
return
|
||||
}
|
||||
|
||||
allIssueCount += repo.NumIssues
|
||||
closedIssueCount += repo.NumClosedIssues
|
||||
|
||||
// Set repository information to issues.
|
||||
for j := range issues {
|
||||
issues[j].Repo = &repos[i]
|
||||
}
|
||||
allIssues = append(allIssues, issues...)
|
||||
|
||||
repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
|
||||
if repos[i].NumOpenIssues > 0 {
|
||||
showRepos = append(showRepos, repos[i])
|
||||
}
|
||||
}
|
||||
|
||||
showIssues := make([]models.Issue, 0, len(allIssues))
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
|
||||
// Get posters and filter issues.
|
||||
for i := range allIssues {
|
||||
u, err := models.GetUserById(allIssues[i].PosterId)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "user.Issues(get poster): %v", err)
|
||||
return
|
||||
}
|
||||
allIssues[i].Poster = u
|
||||
if u.Id == ctx.User.Id {
|
||||
createdByCount++
|
||||
}
|
||||
|
||||
if repoId > 0 && repoId != allIssues[i].Repo.Id {
|
||||
continue
|
||||
}
|
||||
|
||||
if isShowClosed == allIssues[i].IsClosed {
|
||||
showIssues = append(showIssues, allIssues[i])
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Data["Repos"] = showRepos
|
||||
ctx.Data["Issues"] = showIssues
|
||||
ctx.Data["AllIssueCount"] = allIssueCount
|
||||
ctx.Data["ClosedIssueCount"] = closedIssueCount
|
||||
ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount
|
||||
ctx.Data["CreatedByCount"] = createdByCount
|
||||
ctx.HTML(200, "issue/user")
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
|
||||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
}
|
||||
} 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()
|
||||
if err := models.UpdateUser(user); err != nil {
|
||||
ctx.Handle(404, "user.Activate", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("%s User activated: %s", ctx.Req.RequestURI, user.Name)
|
||||
|
||||
ctx.Session.Set("userId", user.Id)
|
||||
ctx.Session.Set("userName", user.Name)
|
||||
ctx.Redirect("/")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsActivateFailed"] = true
|
||||
ctx.HTML(200, "user/active")
|
||||
}
|
||||
|
||||
func ForgotPasswd(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "Forgot Password"
|
||||
|
||||
if base.MailService == nil {
|
||||
ctx.Data["IsResetDisable"] = true
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsResetRequest"] = true
|
||||
if ctx.Req.Method == "GET" {
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
email := ctx.Query("email")
|
||||
u, err := models.GetUserByEmail(email)
|
||||
if err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.RenderWithErr("This e-mail address does not associate to any account.", "user/forgot_passwd", nil)
|
||||
} else {
|
||||
ctx.Handle(404, "user.ResetPasswd(check existence)", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) {
|
||||
ctx.Data["ResendLimited"] = true
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
mailer.SendResetPasswdMail(ctx.Render, u)
|
||||
if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
|
||||
ctx.Data["Email"] = email
|
||||
ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
|
||||
ctx.Data["IsResetSent"] = true
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
}
|
||||
|
||||
func ResetPasswd(ctx *middleware.Context) {
|
||||
code := ctx.Query("code")
|
||||
if len(code) == 0 {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
ctx.Data["Code"] = code
|
||||
|
||||
if ctx.Req.Method == "GET" {
|
||||
ctx.Data["IsResetForm"] = true
|
||||
ctx.HTML(200, "user/reset_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
if u := models.VerifyUserActiveCode(code); u != nil {
|
||||
// Validate password length.
|
||||
passwd := ctx.Query("passwd")
|
||||
if len(passwd) < 6 || len(passwd) > 30 {
|
||||
ctx.Data["IsResetForm"] = true
|
||||
ctx.RenderWithErr("Password length should be in 6 and 30.", "user/reset_passwd", nil)
|
||||
return
|
||||
}
|
||||
|
||||
u.Passwd = passwd
|
||||
u.Rands = models.GetUserSalt()
|
||||
u.Salt = models.GetUserSalt()
|
||||
u.EncodePasswd()
|
||||
if err := models.UpdateUser(u); err != nil {
|
||||
ctx.Handle(404, "user.ResetPasswd(UpdateUser)", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("%s User password reset: %s", ctx.Req.RequestURI, u.Name)
|
||||
ctx.Redirect("/user/login")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsResetFailed"] = true
|
||||
ctx.HTML(200, "user/reset_passwd")
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue