@@ -4,4 +4,5 @@ gogs | |||
.DS_Store | |||
*.db | |||
*.log | |||
custom/ | |||
custom/ | |||
.vendor/ |
@@ -3,6 +3,8 @@ Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0b | |||
Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language, it currently supports Linux and Max OS X, but Windows has **NOT** supported yet due to installation problem with [libgit2](http://libgit2.github.com/) in Windows. | |||
##### Current version: 0.0.7 Alpha | |||
## Purpose | |||
There are some very good products in this category such as [gitlab](http://gitlab.com), but the environment setup steps often make us crazy. So our goal of Gogs is to build a GitHub-like clone with very easy setup steps, which take advantages of the Go Programming Language. | |||
@@ -15,7 +17,8 @@ Please see [Wiki](https://github.com/gogits/gogs/wiki) for project design, devel | |||
- SSH protocal support. | |||
- Register/delete account. | |||
- Create public repository. | |||
- Create/delete public repository. | |||
- User/repository home page. | |||
- Git repository manipulation. | |||
## Installation |
@@ -3,8 +3,8 @@ RUN_USER = lunny | |||
[repository] | |||
ROOT = /Users/lunny/git/gogs-repositories | |||
LANG_IGNS=Google Go | |||
LICENSES=Apache v2 License | |||
LANG_IGNS=Google Go|C | |||
LICENSES=Apache v2 License|BSD (3-Clause) License | |||
[server] | |||
HTTP_ADDR = |
@@ -0,0 +1,18 @@ | |||
# Object files | |||
*.o | |||
*.ko | |||
# Libraries | |||
*.lib | |||
*.a | |||
# Shared objects (inc. Windows DLLs) | |||
*.dll | |||
*.so | |||
*.so.* | |||
*.dylib | |||
# Executables | |||
*.exe | |||
*.out | |||
*.app |
@@ -0,0 +1,27 @@ | |||
Copyright (c) 2014 | |||
All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright notice, this | |||
list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright notice, | |||
this list of conditions and the following disclaimer in the documentation | |||
and/or other materials provided with the distribution. | |||
* Neither the name of the {organization} nor the names of its | |||
contributors may be used to endorse or promote products derived from | |||
this software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@@ -20,7 +20,7 @@ import ( | |||
// Test that go1.1 tag above is included in builds. main.go refers to this definition. | |||
const go11tag = true | |||
const APP_VER = "0.0.6.0313" | |||
const APP_VER = "0.0.7.0314" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -9,6 +9,7 @@ import ( | |||
"fmt" | |||
"io/ioutil" | |||
"os" | |||
"path" | |||
"path/filepath" | |||
"strings" | |||
"time" | |||
@@ -270,6 +271,7 @@ type RepoFile struct { | |||
Id *git.Oid | |||
Type int | |||
Name string | |||
Path string | |||
Message string | |||
Created time.Time | |||
} | |||
@@ -282,7 +284,7 @@ func (f *RepoFile) IsDir() bool { | |||
return f.Type == git.FilemodeTree | |||
} | |||
func GetReposFiles(userName, reposName, treeName, rpath string) ([]*RepoFile, error) { | |||
func GetReposFiles(userName, reposName, branchName, rpath string) ([]*RepoFile, error) { | |||
f := RepoPath(userName, reposName) | |||
repo, err := git.OpenRepository(f) | |||
if err != nil { | |||
@@ -299,8 +301,28 @@ func GetReposFiles(userName, reposName, treeName, rpath string) ([]*RepoFile, er | |||
if err != nil { | |||
return nil, err | |||
} | |||
var i uint64 = 0 | |||
for ; i < tree.EntryCount(); i++ { | |||
//var i uint64 = 0 | |||
if rpath != "" { | |||
rpath = rpath + "/" | |||
} | |||
fmt.Println("...", rpath, "...") | |||
tree.Walk(func(dirname string, entry *git.TreeEntry) int { | |||
if dirname == rpath { | |||
fmt.Println("====", dirname, "==", entry.Name) | |||
repofiles = append(repofiles, &RepoFile{ | |||
entry.Id, | |||
entry.Filemode, | |||
entry.Name, | |||
path.Join(dirname, entry.Name), | |||
lastCommit.Message(), | |||
lastCommit.Committer().When, | |||
}) | |||
} | |||
return 0 | |||
}) | |||
/*for ; i < tree.EntryCount(); i++ { | |||
entry := tree.EntryByIndex(i) | |||
repofiles = append(repofiles, &RepoFile{ | |||
@@ -310,7 +332,7 @@ func GetReposFiles(userName, reposName, treeName, rpath string) ([]*RepoFile, er | |||
lastCommit.Message(), | |||
lastCommit.Committer().When, | |||
}) | |||
} | |||
}*/ | |||
return repofiles, nil | |||
} | |||
@@ -354,6 +376,10 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) { | |||
session.Rollback() | |||
return err | |||
} | |||
if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil { | |||
session.Rollback() | |||
return err | |||
} | |||
if _, err = session.Exec("update user set num_repos = num_repos - 1 where id = ?", userId); err != nil { | |||
session.Rollback() | |||
return err |
@@ -48,7 +48,10 @@ type User struct { | |||
NumFollowings int | |||
NumStars int | |||
NumRepos int | |||
Avatar string `xorm:"varchar(2048) not null"` | |||
Avatar string `xorm:"varchar(2048) not null"` | |||
AvatarEmail string `xorm:"not null"` | |||
Location string | |||
Website string | |||
Created time.Time `xorm:"created"` | |||
Updated time.Time `xorm:"updated"` | |||
} | |||
@@ -104,6 +107,7 @@ func RegisterUser(user *User) (err error) { | |||
user.LowerName = strings.ToLower(user.Name) | |||
user.Avatar = base.EncodeMd5(user.Email) | |||
user.AvatarEmail = user.Email | |||
if err = user.EncodePasswd(); err != nil { | |||
return err | |||
} |
@@ -23,7 +23,7 @@ type Form interface { | |||
} | |||
type RegisterForm struct { | |||
UserName string `form:"username" binding:"Required;AlphaDash;MinSize(5);MaxSize(30)"` | |||
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"` | |||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` | |||
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` | |||
RetypePasswd string `form:"retypepasswd"` | |||
@@ -59,7 +59,7 @@ func (f *RegisterForm) Validate(errors *binding.Errors, req *http.Request, conte | |||
} | |||
type LogInForm struct { | |||
UserName string `form:"username" binding:"Required;AlphaDash;MinSize(5);MaxSize(30)"` | |||
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"` | |||
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` | |||
} | |||
@@ -90,11 +90,6 @@ func (f *LogInForm) Validate(errors *binding.Errors, req *http.Request, context | |||
validate(errors, data, f) | |||
} | |||
type FeedsForm struct { | |||
UserId int64 `form:"userid" binding:"Required"` | |||
Offset int64 `form:"offset"` | |||
} | |||
func getMinMaxSize(field reflect.StructField) string { | |||
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { | |||
if strings.HasPrefix(rule, "MinSize(") || strings.HasPrefix(rule, "MaxSize(") { |
@@ -5,10 +5,15 @@ | |||
package auth | |||
import ( | |||
"net/http" | |||
"reflect" | |||
"github.com/codegangsta/martini" | |||
"github.com/martini-contrib/render" | |||
"github.com/martini-contrib/sessions" | |||
"github.com/gogits/binding" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/base" | |||
"github.com/gogits/gogs/modules/log" | |||
@@ -83,3 +88,76 @@ func SignOutRequire() martini.Handler { | |||
} | |||
} | |||
} | |||
type FeedsForm struct { | |||
UserId int64 `form:"userid" binding:"Required"` | |||
Offset int64 `form:"offset"` | |||
} | |||
type UpdateProfileForm struct { | |||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` | |||
Website string `form:"website" binding:"MaxSize(50)"` | |||
Location string `form:"location" binding:"MaxSize(50)"` | |||
Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"` | |||
} | |||
func (f *UpdateProfileForm) Name(field string) string { | |||
names := map[string]string{ | |||
"Email": "Email address", | |||
"Website": "Website", | |||
"Location": "Location", | |||
"Avatar": "Gravatar Email", | |||
} | |||
return names[field] | |||
} | |||
func (f *UpdateProfileForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
return | |||
} | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
data["HasError"] = true | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("UpdateProfileForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
} | |||
type UpdatePasswdForm struct { | |||
OldPasswd string `form:"oldpasswd" binding:"Required;MinSize(6);MaxSize(30)"` | |||
NewPasswd string `form:"newpasswd" binding:"Required;MinSize(6);MaxSize(30)"` | |||
RetypePasswd string `form:"retypepasswd"` | |||
} | |||
func (f *UpdatePasswdForm) Name(field string) string { | |||
names := map[string]string{ | |||
"OldPasswd": "Old password", | |||
"NewPasswd": "New password", | |||
"RetypePasswd": "Re-type password", | |||
} | |||
return names[field] | |||
} | |||
func (f *UpdatePasswdForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { | |||
if req.Method == "GET" || errors.Count() == 0 { | |||
return | |||
} | |||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | |||
data["HasError"] = true | |||
if len(errors.Overall) > 0 { | |||
for _, err := range errors.Overall { | |||
log.Error("UpdatePasswdForm.Validate: %v", err) | |||
} | |||
return | |||
} | |||
validate(errors, data, f) | |||
} |
@@ -7,6 +7,8 @@ package base | |||
import ( | |||
"crypto/md5" | |||
"encoding/hex" | |||
"fmt" | |||
"time" | |||
) | |||
// Encode string to md5 hex value | |||
@@ -15,3 +17,64 @@ func EncodeMd5(str string) string { | |||
m.Write([]byte(str)) | |||
return hex.EncodeToString(m.Sum(nil)) | |||
} | |||
// Seconds-based time units | |||
const ( | |||
Minute = 60 | |||
Hour = 60 * Minute | |||
Day = 24 * Hour | |||
Week = 7 * Day | |||
Month = 30 * Day | |||
Year = 12 * Month | |||
) | |||
// TimeSince calculates the time interval and generate user-friendly string. | |||
func TimeSince(then time.Time) string { | |||
now := time.Now() | |||
lbl := "ago" | |||
diff := now.Unix() - then.Unix() | |||
if then.After(now) { | |||
lbl = "from now" | |||
diff = then.Unix() - now.Unix() | |||
} | |||
switch { | |||
case diff <= 0: | |||
return "now" | |||
case diff <= 2: | |||
return fmt.Sprintf("1 second %s", lbl) | |||
case diff < 1*Minute: | |||
return fmt.Sprintf("%d seconds %s", diff, lbl) | |||
case diff < 2*Minute: | |||
return fmt.Sprintf("1 minute %s", lbl) | |||
case diff < 1*Hour: | |||
return fmt.Sprintf("%d minutes %s", diff/Minute, lbl) | |||
case diff < 2*Hour: | |||
return fmt.Sprintf("1 hour %s", lbl) | |||
case diff < 1*Day: | |||
return fmt.Sprintf("%d hours %s", diff/Hour, lbl) | |||
case diff < 2*Day: | |||
return fmt.Sprintf("1 day %s", lbl) | |||
case diff < 1*Week: | |||
return fmt.Sprintf("%d days %s", diff/Day, lbl) | |||
case diff < 2*Week: | |||
return fmt.Sprintf("1 week %s", lbl) | |||
case diff < 1*Month: | |||
return fmt.Sprintf("%d weeks %s", diff/Week, lbl) | |||
case diff < 2*Month: | |||
return fmt.Sprintf("1 month %s", lbl) | |||
case diff < 1*Year: | |||
return fmt.Sprintf("%d months %s", diff/Month, lbl) | |||
case diff < 18*Month: | |||
return fmt.Sprintf("1 year %s", lbl) | |||
} | |||
return then.String() | |||
} |
@@ -6,7 +6,13 @@ | |||
package log | |||
import ( | |||
"fmt" | |||
"github.com/martini-contrib/render" | |||
"github.com/gogits/logs" | |||
"github.com/gogits/gogs/modules/base" | |||
) | |||
var logger *logs.BeeLogger | |||
@@ -35,3 +41,9 @@ func Warn(format string, v ...interface{}) { | |||
func Critical(format string, v ...interface{}) { | |||
logger.Critical(format, v...) | |||
} | |||
func Handle(status int, title string, data base.TmplData, r render.Render, err error) { | |||
data["ErrorMsg"] = err | |||
Error("%s: %v", title, err) | |||
r.HTML(status, fmt.Sprintf("status/%d", status), data) | |||
} |
@@ -137,6 +137,11 @@ body { | |||
margin-top: 50px; | |||
} | |||
#gogs-body .btn-default { | |||
background-color: #FFF; | |||
background-image: linear-gradient(to bottom, #FFF 0, #FAFAFA 100%); | |||
} | |||
#gogs-body-nav { | |||
margin-top: 52px; | |||
margin-bottom: -50px; | |||
@@ -269,7 +274,8 @@ body { | |||
/* gogits user setting */ | |||
#gogs-user-setting-nav > h4, #gogs-user-setting-container > h4, #gogs-ssh-keys > h4, #gogs-user-delete > h4 ,#gogs-repo-setting-container .tab-pane > h4{ | |||
#gogs-user-setting-nav > h4, #gogs-user-setting-container > h4, #gogs-user-setting-container > div > h4, | |||
#gogs-ssh-keys > h4, #gogs-user-delete > h4, #gogs-repo-setting-container .tab-pane > h4 { | |||
padding-bottom: 18px; | |||
margin-bottom: 18px; | |||
border-bottom: 1px solid #CCC; | |||
@@ -380,6 +386,7 @@ body { | |||
} | |||
#gogs-feed-right .repo-panel .list-group-item:hover { | |||
background-color: #eafffd; | |||
background-color: rgba(65, 131, 196, 0.1); | |||
} | |||
@@ -391,6 +398,12 @@ body { | |||
/* gogits repo single page */ | |||
#gogs-body-nav.gogs-repo-nav { | |||
padding-top: 16px; | |||
padding-bottom: 30px; | |||
height: auto; | |||
} | |||
.gogs-repo-nav h3 .fa { | |||
color: #BBB; | |||
} | |||
@@ -429,32 +442,82 @@ body { | |||
margin-bottom: 4px; | |||
} | |||
#gogs-repo-toolbar{ | |||
#gogs-repo-toolbar { | |||
margin-top: 51px; | |||
margin-bottom: -50px; | |||
border-bottom: 1px solid #BBB; | |||
background-color: #FFF; | |||
height: 40px; | |||
font-size: 14px; | |||
} | |||
#gogs-repo-toolbar .navbar-default{ | |||
#gogs-repo-toolbar .navbar-default { | |||
border: none; | |||
height: 39px; | |||
} | |||
#gogs-repo-toolbar .nav > li > a{ | |||
#gogs-repo-toolbar .nav > li > a { | |||
height: 39px; | |||
} | |||
#gogs-repo-toolbar .navbar-toolbar.navbar-default .navbar-nav>.active>a:after{ | |||
#gogs-repo-toolbar .navbar-toolbar.navbar-default .navbar-nav > .active > a:after { | |||
border-bottom-color: #999; | |||
} | |||
#gogs-repo-toolbar .navbar.nav-toolbar{ | |||
#gogs-repo-toolbar .navbar.nav-toolbar { | |||
margin-bottom: 0; | |||
} | |||
#gogs-repo-toolbar .navbar-collapse{ | |||
#gogs-repo-toolbar .navbar-collapse { | |||
padding: 0; | |||
} | |||
/* #gogs-source */ | |||
#gogs-source-toolbar:after { | |||
clear: both; | |||
} | |||
#gogs-source-toolbar .branch-switch { | |||
display: inline-block; | |||
} | |||
#gogs-source-toolbar .breadcrumb { | |||
margin: 0 .5em; | |||
font-size: 16px; | |||
vertical-align: middle; | |||
display: inline-block; | |||
background-color: transparent; | |||
} | |||
#gogs-source-table { | |||
margin-top: 1.5em; | |||
font-size: 14px; | |||
} | |||
#gogs-source-table .fa{ | |||
font-size: 15px; | |||
width: 16px; | |||
text-align: center; | |||
color: #666; | |||
} | |||
#gogs-source-table .name{ | |||
width: 160px; | |||
} | |||
#gogs-source-table .size{ | |||
width: 80px; | |||
} | |||
#gogs-source-table .date{ | |||
width: 120px; | |||
} | |||
#gogs-source-table .is-dir .name { | |||
font-weight: bold; | |||
} | |||
#gogs-source-table.table-hover > tbody > tr:hover > td { | |||
background-color: #FEFEFE; | |||
} |
@@ -78,7 +78,6 @@ function initRegister() { | |||
rules: { | |||
"username": { | |||
required: true, | |||
minlength: 5, | |||
maxlength: 30 | |||
}, | |||
"email": { |
@@ -5,9 +5,10 @@ | |||
package repo | |||
import ( | |||
"net/http" | |||
"github.com/martini-contrib/render" | |||
"github.com/martini-contrib/sessions" | |||
"net/http" | |||
"github.com/gogits/gogs/models" | |||
"github.com/gogits/gogs/modules/auth" | |||
@@ -46,7 +47,7 @@ func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data b | |||
if err == nil { | |||
if _, err = models.CreateRepository(user, | |||
form.RepoName, form.Description, form.Language, form.License, | |||
form.Visibility == "private", form.InitReadme == "true"); err == nil { | |||
form.Visibility == "private", form.InitReadme == "on"); err == nil { | |||
if err == nil { | |||
data["RepoName"] = user.Name + "/" + form.RepoName | |||
r.HTML(200, "repo/created", data) | |||
@@ -63,9 +64,7 @@ func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data b | |||
return | |||
} | |||
data["ErrorMsg"] = err | |||
log.Error("repo.Create: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "repo.Create", data, r, err) | |||
} | |||
func Delete(form auth.DeleteRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session) { | |||
@@ -77,13 +76,11 @@ func Delete(form auth.DeleteRepoForm, req *http.Request, r render.Render, data b | |||
} | |||
if err := models.DeleteRepository(form.UserId, form.RepoId, form.UserName); err != nil { | |||
data["ErrorMsg"] = err | |||
log.Error("repo.Delete: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "repo.Delete", data, r, err) | |||
return | |||
} | |||
r.Redirect("/", 200) | |||
r.Redirect("/", 302) | |||
} | |||
func List(req *http.Request, r render.Render, data base.TmplData, session sessions.Session) { | |||
@@ -96,9 +93,7 @@ func List(req *http.Request, r render.Render, data base.TmplData, session sessio | |||
data["Title"] = "Repositories" | |||
repos, err := models.GetRepositories(u) | |||
if err != nil { | |||
data["ErrorMsg"] = err | |||
log.Error("repo.List: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "repo.List", data, r, err) | |||
return | |||
} | |||
@@ -1,6 +1,7 @@ | |||
package repo | |||
import ( | |||
"strings" | |||
"github.com/codegangsta/martini" | |||
"github.com/martini-contrib/render" | |||
@@ -13,15 +14,27 @@ func Single(params martini.Params, r render.Render, data base.TmplData) { | |||
if !data["IsRepositoryValid"].(bool) { | |||
return | |||
} | |||
files, err := models.GetReposFiles(params["username"], params["reponame"], "HEAD", "/") | |||
if params["branchname"] == "" { | |||
params["branchname"] = "master" | |||
} | |||
treename := params["_1"] | |||
files, err := models.GetReposFiles(params["username"], params["reponame"], | |||
params["branchname"], treename) | |||
if err != nil { | |||
data["ErrorMsg"] = err | |||
log.Error("repo.List: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "repo.Single", data, r, err) | |||
return | |||
} | |||
data["Username"] = params["username"] | |||
data["Reponame"] = params["reponame"] | |||
data["Branchname"] = params["branchname"] | |||
treenames := strings.Split(treename, "/") | |||
Paths := make([]string, 0) | |||
for i, _ := range treenames { | |||
Paths = append(Paths, strings.Join(treenames[0:i+1], "/")) | |||
} | |||
data["Paths"] = Paths | |||
data["Treenames"] = treenames | |||
data["IsRepoToolbarSource"] = true | |||
data["Files"] = files | |||
@@ -17,12 +17,72 @@ import ( | |||
"github.com/gogits/gogs/modules/log" | |||
) | |||
func Setting(r render.Render, data base.TmplData, session sessions.Session) { | |||
func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) { | |||
data["Title"] = "Setting" | |||
data["PageIsUserSetting"] = true | |||
user := auth.SignedInUser(session) | |||
data["Owner"] = user | |||
if req.Method == "GET" { | |||
r.HTML(200, "user/setting", data) | |||
return | |||
} | |||
if hasErr, ok := data["HasError"]; ok && hasErr.(bool) { | |||
r.HTML(200, "user/setting", data) | |||
return | |||
} | |||
user.Email = form.Email | |||
user.Website = form.Website | |||
user.Location = form.Location | |||
user.Avatar = base.EncodeMd5(form.Avatar) | |||
user.AvatarEmail = form.Avatar | |||
if err := models.UpdateUser(user); err != nil { | |||
log.Handle(200, "setting.Setting", data, r, err) | |||
return | |||
} | |||
data["IsSuccess"] = true | |||
r.HTML(200, "user/setting", data) | |||
} | |||
func SettingPassword(form auth.UpdatePasswdForm, r render.Render, data base.TmplData, session sessions.Session, req *http.Request) { | |||
data["Title"] = "Password" | |||
data["PageIsUserSetting"] = true | |||
if req.Method == "GET" { | |||
r.HTML(200, "user/password", data) | |||
return | |||
} | |||
user := auth.SignedInUser(session) | |||
newUser := &models.User{Passwd: form.NewPasswd} | |||
if err := newUser.EncodePasswd(); err != nil { | |||
log.Handle(200, "setting.SettingPassword", data, r, err) | |||
return | |||
} | |||
if user.Passwd != newUser.Passwd { | |||
data["HasError"] = true | |||
data["ErrorMsg"] = "Old password is not correct" | |||
} else if form.NewPasswd != form.RetypePasswd { | |||
data["HasError"] = true | |||
data["ErrorMsg"] = "New password and re-type password are not same" | |||
} else { | |||
user.Passwd = newUser.Passwd | |||
if err := models.UpdateUser(user); err != nil { | |||
log.Handle(200, "setting.SettingPassword", data, r, err) | |||
return | |||
} | |||
data["IsSuccess"] = true | |||
} | |||
data["Owner"] = user | |||
r.HTML(200, "user/password", data) | |||
} | |||
func SettingSSHKeys(form auth.AddSSHKeyForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) { | |||
data["Title"] = "SSH Keys" | |||
@@ -94,3 +154,17 @@ func SettingSSHKeys(form auth.AddSSHKeyForm, r render.Render, data base.TmplData | |||
data["Keys"] = keys | |||
r.HTML(200, "user/publickey", data) | |||
} | |||
func SettingNotification(r render.Render, data base.TmplData) { | |||
// todo user setting notification | |||
data["Title"] = "Notification" | |||
data["PageIsUserSetting"] = true | |||
r.HTML(200, "user/notification", data) | |||
} | |||
func SettingSecurity(r render.Render, data base.TmplData) { | |||
// todo user setting security | |||
data["Title"] = "Security" | |||
data["PageIsUserSetting"] = true | |||
r.HTML(200, "user/security", data) | |||
} |
@@ -22,9 +22,7 @@ func Dashboard(r render.Render, data base.TmplData, session sessions.Session) { | |||
data["PageIsUserDashboard"] = true | |||
repos, err := models.GetRepositories(&models.User{Id: auth.SignedInId(session)}) | |||
if err != nil { | |||
data["ErrorMsg"] = err | |||
log.Error("dashboard: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "user.Dashboard", data, r, err) | |||
return | |||
} | |||
data["MyRepos"] = repos | |||
@@ -37,14 +35,11 @@ func Profile(params martini.Params, r render.Render, data base.TmplData, session | |||
// TODO: Need to check view self or others. | |||
user, err := models.GetUserByName(params["username"]) | |||
if err != nil { | |||
data["ErrorMsg"] = err | |||
log.Error("user.Profile: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "user.Profile", data, r, err) | |||
return | |||
} | |||
data["Avatar"] = user.Avatar | |||
data["Username"] = user.Name | |||
data["Owner"] = user | |||
r.HTML(200, "user/profile", data) | |||
} | |||
@@ -71,9 +66,7 @@ func SignIn(form auth.LogInForm, data base.TmplData, req *http.Request, r render | |||
return | |||
} | |||
data["ErrorMsg"] = err | |||
log.Error("user.SignIn: %v", err) | |||
r.HTML(200, "base/error", data) | |||
log.Handle(200, "user.SignIn", data, r, err) | |||
return | |||
} | |||
@@ -130,9 +123,7 @@ func SignUp(form auth.RegisterForm, data base.TmplData, req *http.Request, r ren | |||
data["ErrorMsg"] = "E-mail address has been already used" | |||
r.HTML(200, "user/signup", data) | |||
default: | |||
data["ErrorMsg"] = err | |||
log.Error("user.SignUp: %v", data) | |||
r.HTML(200, "base/error", nil) | |||
log.Handle(200, "user.SignUp", data, r, err) | |||
} | |||
return | |||
} | |||
@@ -156,9 +147,7 @@ func Delete(data base.TmplData, req *http.Request, session sessions.Session, r r | |||
case models.ErrUserOwnRepos.Error(): | |||
data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first." | |||
default: | |||
data["ErrorMsg"] = err | |||
log.Error("user.Delete: %v", data) | |||
r.HTML(200, "base/error", nil) | |||
log.Handle(200, "user.Delete", data, r, err) | |||
return | |||
} | |||
} |
@@ -1,6 +1,17 @@ | |||
<div id="gogs-body-nav" class="gogs-repo-nav"> | |||
<div class="container"> | |||
<div class="gogs-repo-btns pull-right"> | |||
<div class="btn-group" id="gogs-repo-clone"> | |||
<button type="button" class="btn btn-default"><i class="fa fa-download"></i>Clone</button> | |||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | |||
<span class="caret"></span> | |||
<span class="sr-only">Toggle Dropdown</span> | |||
</button> | |||
<div class="dropdown-menu" role="menu"> | |||
<div data-val="down-http">http link</div> | |||
<div data-val="down-git">git link</div> | |||
</div> | |||
</div> | |||
<div class="btn-group" id="gogs-repo-watching"> | |||
<button type="button" class="btn btn-default"><i class="fa fa-eye"></i>Watch {x}</button> | |||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> |
@@ -3,11 +3,58 @@ | |||
{{template "repo/nav" .}} | |||
{{template "repo/toolbar" .}} | |||
<div id="gogs-body" class="container"> | |||
<h4>Source Files:</h4> | |||
<ul> | |||
{{range .Files}} | |||
<li>{{.Name}} - {{.Id}} - {{.Message}} - {{.Created}} - {{.IsFile}} - {{.IsDir}}</li> | |||
{{end}} | |||
</ul> | |||
<div id="gogs-source"> | |||
<div id="gogs-source-toolbar"> | |||
<button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button> | |||
<div class="dropdown branch-switch"> | |||
<a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>master | |||
<b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a class="current" href="/{{.RepositoryLink}}/branch/master">master</a></li> | |||
<li><a href="//{{.RepositoryLink}}/branch/develop">develop</a></li> | |||
</ul> | |||
</div> | |||
<ol class="breadcrumb"> | |||
<li class="root dir">{{.Repository.Name}}</li> | |||
{{$paths := .Paths}} | |||
{{ $username := .Username}} | |||
{{ $reponame := .Reponame}} | |||
{{ $branchname := .Branchname}} | |||
{{ $treenames := .Treenames}} | |||
{{ $n := len $treenames}} | |||
{{ $l := Subtract $n 1}} | |||
{{range $i, $v := $treenames}} | |||
<li class="dir"> | |||
{{if eq $i $l}}{{$v}} | |||
{{else}} | |||
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{index $paths $i}}">{{$v}}</a> | |||
{{end}}</li> | |||
{{end}} | |||
</ol> | |||
</div> | |||
<table id="gogs-source-table" class="table table-hover"> | |||
<thead class="hidden"> | |||
<tr> | |||
<th class="name">Filename</th> | |||
<th class="date">Date modified</th> | |||
<th class="text">Message</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{{range .Files}} | |||
<tr {{if .IsDir}}class="is-dir"{{end}}> | |||
<td class="name"><i class="fa {{if .IsDir}}fa-folder{{else}}fa-file{{end}}"></i> | |||
{{if .IsDir}} | |||
<a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{.Path}}">{{.Name}}</a> | |||
{{else}} | |||
<a href="#">{{.Name}}</a> | |||
{{end}}</td> | |||
<td class="date"><time datetime="{{.Created}}" data-title="true" title="{{.Created}}">{{TimeSince .Created}}</time></td> | |||
<td class="text">{{.Message}}</td> | |||
</tr> | |||
{{end}} | |||
</tbody> | |||
</table> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,40 +1,32 @@ | |||
<div id="gogs-repo-toolbar"> | |||
<div class="container"> | |||
<nav class="navbar navbar-toolbar navbar-default" role="navigation"> | |||
<div class="container-fluid"> | |||
<div class="collapse navbar-collapse"> | |||
<ul class="nav navbar-nav"> | |||
<li class="dropdown"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Branches <b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a href="#">master</a></li> | |||
<li><a href="#">develop</a></li> | |||
</ul> | |||
</li> | |||
<li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="/{{.RepositoryLink}}">Source</a></li> | |||
<li><a href="#">Commits</a></li> | |||
<li><a href="#">Issues <span class="badge">42</span></a></li> | |||
<li><a href="#">Pull Requests</a></li> | |||
<li class="dropdown"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a href="#">Release</a></li> | |||
<li><a href="#">Wiki</a></li> | |||
</ul> | |||
</li> | |||
</ul> | |||
<ul class="nav navbar-nav navbar-right"> | |||
<li class="dropdown"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Statistic <b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a href="#">Graphic</a></li> | |||
<li><a href="#">Pulse</a></li> | |||
<li><a href="#">Network</a></li> | |||
</ul> | |||
</li>{{if .IsRepositoryOwner}} | |||
<li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="/{{.RepositoryLink}}/settings">Settings</a></li>{{end}} | |||
</ul> | |||
</div> | |||
<div class="collapse navbar-collapse"> | |||
<ul class="nav navbar-nav"> | |||
<li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="/{{.RepositoryLink}}">Source</a></li> | |||
<li><a href="/{{.RepositoryLink}}/commits">Commits</a></li> | |||
<li><a href="/{{.RepositoryLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li> | |||
<li><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li> | |||
<li class="dropdown"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a href="/{{.RepositoryLink}}/release">Release</a></li> | |||
<li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li> | |||
</ul> | |||
</li> | |||
</ul> | |||
<ul class="nav navbar-nav navbar-right"> | |||
<li class="dropdown"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Statistic <b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a href="#">Graphic</a></li> | |||
<li><a href="#">Pulse</a></li> | |||
<li><a href="#">Network</a></li> | |||
</ul> | |||
</li>{{if .IsRepositoryOwner}} | |||
<li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="/{{.RepositoryLink}}/settings">Settings</a> | |||
</li>{{end}} | |||
</ul> | |||
</div> | |||
</nav> | |||
</div> |
@@ -5,10 +5,10 @@ | |||
<h4>Account Setting</h4> | |||
<ul class="list-group"> | |||
<li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | |||
<li class="list-group-item"><a href="#">Emails and Password</a></li> | |||
<li class="list-group-item"><a href="#">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/password">Password</a></li> | |||
<li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | |||
<li class="list-group-item"><a href="#">Security</a></li> | |||
<li class="list-group-item"><a href="/user/setting/security">Security</a></li> | |||
<li class="list-group-item list-group-item-success"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> |
@@ -0,0 +1,19 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="gogs-body" class="container"> | |||
<div id="gogs-user-setting-nav" class="col-md-3"> | |||
<h4>Account Setting</h4> | |||
<ul class="list-group"> | |||
<li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | |||
<li class="list-group-item"><a href="/user/setting/password">Password</a></li> | |||
<li class="list-group-item list-group-item-success"><a href="/user/setting/notification">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | |||
<li class="list-group-item"><a href="/user/setting/security">Security</a></li> | |||
<li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> | |||
<div id="gogs-user-setting-container" class="col-md-9"> | |||
<h4>Notification</h4> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,51 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="gogs-body" class="container"> | |||
<div id="gogs-user-setting-nav" class="col-md-3"> | |||
<h4>Account Setting</h4> | |||
<ul class="list-group"> | |||
<li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | |||
<li class="list-group-item list-group-item-success"><a href="/user/setting/password">Password</a></li> | |||
<li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | |||
<li class="list-group-item"><a href="/user/setting/security">Security</a></li> | |||
<li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> | |||
<div id="gogs-user-setting-container" class="col-md-9"> | |||
<div id="gogs-setting-pwd"> | |||
<h4>Password</h4> | |||
<form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting/password">{{if .IsSuccess}} | |||
<p class="alert alert-success">Password is changed successfully. You can now sign in via new password.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}} | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Old Password<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input type="password" name="oldpasswd" class="form-control" placeholder="Type your current password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">New Password<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input type="password" name="newpasswd" class="form-control" placeholder="Type your new password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Re-Type<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input type="password" name="retypepasswd" class="form-control" placeholder="Re-type your new password" required="required"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-8"> | |||
<button type="submit" class="btn btn-primary">Change Password</button> | |||
<a href="/forget-password/">Forgot your password?</a> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -4,16 +4,16 @@ | |||
<div id="gogs-user-profile" class="col-md-3"> | |||
<div class="profile-avatar text-center"> | |||
<a href="#" class="center-block" data-toggle="tooltip" data-placement="bottom" title="Change Avatar"> | |||
<img id="gogs-user-avatar" src="http://1.gravatar.com/avatar/{{.Avatar}}?s=200" alt="user-avatar" title="username"/> | |||
<img id="gogs-user-avatar" src="http://1.gravatar.com/avatar/{{.Owner.Avatar}}?s=200" alt="user-avatar" title="username"/> | |||
</a> | |||
<span id="gogs-user-name" class="center-block" href="#">{{.Username}}</span> | |||
<span id="gogs-user-name" class="center-block" href="#">{{.Owner.Name}}</span> | |||
</div> | |||
<div class="profile-info"> | |||
<ul class="list-group"> | |||
<li class="list-group-item"><i class="fa fa-thumb-tack"></i>City, County, State, Nation</li> | |||
<li class="list-group-item"><i class="fa fa-envelope"></i><a href="#">Email@EmailAddress.com</a></li> | |||
<li class="list-group-item"><i class="fa fa-link"></i><a href="#">http://yousite/</a></li> | |||
<li class="list-group-item"><i class="fa fa-clock-o"></i>Joined At 03.02, 2014</li> | |||
<li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li> | |||
<li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}">{{.Owner.Email}}</a></li> | |||
<li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li> | |||
<li class="list-group-item"><i class="fa fa-clock-o"></i>{{.Owner.Created}}</li> | |||
</ul> | |||
</div> | |||
</div> |
@@ -5,10 +5,10 @@ | |||
<h4>Account Setting</h4> | |||
<ul class="list-group"> | |||
<li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | |||
<li class="list-group-item"><a href="#">Emails and Password</a></li> | |||
<li class="list-group-item"><a href="#">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/Password">Password</a></li> | |||
<li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | |||
<li class="list-group-item list-group-item-success"><a href="/user/setting/ssh/">SSH Keys</a></li> | |||
<li class="list-group-item"><a href="#">Security</a></li> | |||
<li class="list-group-item"><a href="/user/setting/security">Security</a></li> | |||
<li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> |
@@ -1,26 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div class="container" id="gogs-body"> | |||
<form action="/user/publickey/add" method="post" class="form-horizontal"> | |||
<div class="form-group"> | |||
<label class="col-md-4 control-label">Name of this public key: </label> | |||
<div class="col-md-3"> | |||
<input name="keyname" class="form-control" placeholder="Type your preferred name" value="{{.KeyName}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-4 control-label">Paste your key here: </label> | |||
<div class="col-md-3"> | |||
<textarea name="key_content" cols="30" rows="10" class="form-control">{{.KeyContent}}</textarea> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-4 col-md-3"> | |||
<button type="submit" class="btn btn-info">Add public key</button> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,8 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div class="container"> | |||
<div class="form-group"> | |||
publickey added | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,12 +0,0 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div class="container" id="gogs-body"> | |||
<div><a href="/user/publickey/add">Add publick key</a></div> | |||
<ul> | |||
{{range .Keys}} | |||
<li>{{.Name}}</li> | |||
<li>{{.Content}}</li> | |||
{{end}} | |||
</ul> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,19 @@ | |||
{{template "base/head" .}} | |||
{{template "base/navbar" .}} | |||
<div id="gogs-body" class="container"> | |||
<div id="gogs-user-setting-nav" class="col-md-3"> | |||
<h4>Account Setting</h4> | |||
<ul class="list-group"> | |||
<li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | |||
<li class="list-group-item"><a href="/user/setting/password">Password</a></li> | |||
<li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | |||
<li class="list-group-item list-group-item-success"><a href="/user/setting/security">Security</a></li> | |||
<li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> | |||
<div id="gogs-user-setting-container" class="col-md-9"> | |||
<h4>Security</h4> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -5,15 +5,54 @@ | |||
<h4>Account Setting</h4> | |||
<ul class="list-group"> | |||
<li class="list-group-item list-group-item-success"><a href="/user/setting">Account Profile</a></li> | |||
<li class="list-group-item"><a href="#">Emails and Password</a></li> | |||
<li class="list-group-item"><a href="#">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/ssh">SSH Keys</a></li> | |||
<li class="list-group-item"><a href="#">Security</a></li> | |||
<li class="list-group-item"><a href="/user/setting/password">Password</a></li> | |||
<li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | |||
<li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | |||
<li class="list-group-item"><a href="/user/setting/security">Security</a></li> | |||
<li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | |||
</ul> | |||
</div> | |||
<div id="gogs-user-setting-container" class="col-md-9"> | |||
setting container | |||
<div id="gogs-setting-pwd"> | |||
<h4>Account Profile</h4> | |||
<form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting">{{if .IsSuccess}} | |||
<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}} | |||
<p>Your Email will be public and used for Account related notifications and any web based operations made via the web.</p> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Email</label> | |||
<div class="col-md-8"> | |||
<input type="text" name="email" class="form-control" placeholder="Type your e-mail address" value="{{.Owner.Email}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Website</label> | |||
<div class="col-md-8"> | |||
<input type="text" name="website" class="form-control" placeholder="Type your website URL" value="{{.Owner.Website}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Location</label> | |||
<div class="col-md-8"> | |||
<input type="text" name="location" class="form-control" placeholder="Type your current location" value="{{.Owner.Location}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<label class="col-md-2 control-label">Gravatar Email<strong class="text-danger">*</strong></label> | |||
<div class="col-md-8"> | |||
<input type="text" name="avatar" class="form-control" placeholder="Type your Gravatar e-mail address" required="required" value="{{.Owner.AvatarEmail}}"> | |||
</div> | |||
</div> | |||
<div class="form-group"> | |||
<div class="col-md-offset-2 col-md-8"> | |||
<button type="submit" class="btn btn-primary">Update Profile</button> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -7,7 +7,7 @@ | |||
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | |||
<label class="col-md-4 control-label">Username: </label> | |||
<div class="col-md-6"> | |||
<input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required" title="Username must contain at least 5 characters"> | |||
<input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required"> | |||
</div> | |||
</div> | |||
@@ -33,6 +33,55 @@ gogs web`, | |||
Flags: []cli.Flag{}, | |||
} | |||
func Subtract(left interface{}, right interface{}) interface{} { | |||
var rleft, rright int64 | |||
var fleft, fright float64 | |||
var isInt bool = true | |||
switch left.(type) { | |||
case int: | |||
rleft = int64(left.(int)) | |||
case int8: | |||
rleft = int64(left.(int8)) | |||
case int16: | |||
rleft = int64(left.(int16)) | |||
case int32: | |||
rleft = int64(left.(int32)) | |||
case int64: | |||
rleft = left.(int64) | |||
case float32: | |||
fleft = float64(left.(float32)) | |||
isInt = false | |||
case float64: | |||
fleft = left.(float64) | |||
isInt = false | |||
} | |||
switch right.(type) { | |||
case int: | |||
rright = int64(right.(int)) | |||
case int8: | |||
rright = int64(right.(int8)) | |||
case int16: | |||
rright = int64(right.(int16)) | |||
case int32: | |||
rright = int64(right.(int32)) | |||
case int64: | |||
rright = right.(int64) | |||
case float32: | |||
fright = float64(left.(float32)) | |||
isInt = false | |||
case float64: | |||
fleft = left.(float64) | |||
isInt = false | |||
} | |||
if isInt { | |||
return rleft - rright | |||
} else { | |||
return fleft + float64(rleft) - (fright + float64(rright)) | |||
} | |||
} | |||
var AppHelpers template.FuncMap = map[string]interface{}{ | |||
"AppName": func() string { | |||
return base.Cfg.MustValue("", "APP_NAME") | |||
@@ -40,6 +89,8 @@ var AppHelpers template.FuncMap = map[string]interface{}{ | |||
"AppVer": func() string { | |||
return APP_VER | |||
}, | |||
"TimeSince": base.TimeSince, | |||
"Subtract": Subtract, | |||
} | |||
func runWeb(*cli.Context) { | |||
@@ -63,8 +114,11 @@ func runWeb(*cli.Context) { | |||
m.Any("/user/delete", auth.SignInRequire(true), user.Delete) | |||
m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) | |||
m.Any("/user/setting", auth.SignInRequire(true), user.Setting) | |||
m.Any("/user/setting", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting) | |||
m.Any("/user/setting/password", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword) | |||
m.Any("/user/setting/ssh", auth.SignInRequire(true), binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys) | |||
m.Any("/user/setting/notification", auth.SignInRequire(true), user.SettingNotification) | |||
m.Any("/user/setting/security", auth.SignInRequire(true), user.SettingSecurity) | |||
m.Get("/user/:username", auth.SignInRequire(false), user.Profile) | |||
@@ -73,6 +127,10 @@ func runWeb(*cli.Context) { | |||
m.Any("/repo/list", auth.SignInRequire(false), repo.List) | |||
m.Get("/:username/:reponame/settings", auth.SignInRequire(false), auth.RepoAssignment(true), repo.Setting) | |||
m.Get("/:username/:reponame/tree/:branchname/**", | |||
auth.SignInRequire(false), auth.RepoAssignment(true), repo.Single) | |||
m.Get("/:username/:reponame/tree/:branchname", | |||
auth.SignInRequire(false), auth.RepoAssignment(true), repo.Single) | |||
m.Get("/:username/:reponame", auth.SignInRequire(false), auth.RepoAssignment(true), repo.Single) | |||
//m.Get("/:username/:reponame", repo.Repo) |