add tree view

This commit is contained in:
Lunny Xiao 2014-03-14 23:54:16 +08:00
commit b27e8e87f8
34 changed files with 716 additions and 166 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@ gogs
*.db *.db
*.log *.log
custom/ custom/
.vendor/

View file

@ -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. 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 ## 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. 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. - SSH protocal support.
- Register/delete account. - Register/delete account.
- Create public repository. - Create/delete public repository.
- User/repository home page.
- Git repository manipulation. - Git repository manipulation.
## Installation ## Installation

View file

@ -3,8 +3,8 @@ RUN_USER = lunny
[repository] [repository]
ROOT = /Users/lunny/git/gogs-repositories ROOT = /Users/lunny/git/gogs-repositories
LANG_IGNS=Google Go LANG_IGNS=Google Go|C
LICENSES=Apache v2 License LICENSES=Apache v2 License|BSD (3-Clause) License
[server] [server]
HTTP_ADDR = HTTP_ADDR =

18
conf/gitignore/C Normal file
View file

@ -0,0 +1,18 @@
# Object files
*.o
*.ko
# Libraries
*.lib
*.a
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app

View file

@ -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.

View file

@ -20,7 +20,7 @@ import (
// Test that go1.1 tag above is included in builds. main.go refers to this definition. // Test that go1.1 tag above is included in builds. main.go refers to this definition.
const go11tag = true const go11tag = true
const APP_VER = "0.0.6.0313" const APP_VER = "0.0.7.0314"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
@ -270,6 +271,7 @@ type RepoFile struct {
Id *git.Oid Id *git.Oid
Type int Type int
Name string Name string
Path string
Message string Message string
Created time.Time Created time.Time
} }
@ -282,7 +284,7 @@ func (f *RepoFile) IsDir() bool {
return f.Type == git.FilemodeTree 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) f := RepoPath(userName, reposName)
repo, err := git.OpenRepository(f) repo, err := git.OpenRepository(f)
if err != nil { if err != nil {
@ -299,8 +301,28 @@ func GetReposFiles(userName, reposName, treeName, rpath string) ([]*RepoFile, er
if err != nil { if err != nil {
return nil, err return nil, err
} }
var i uint64 = 0 //var i uint64 = 0
for ; i < tree.EntryCount(); i++ { 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) entry := tree.EntryByIndex(i)
repofiles = append(repofiles, &RepoFile{ repofiles = append(repofiles, &RepoFile{
@ -310,7 +332,7 @@ func GetReposFiles(userName, reposName, treeName, rpath string) ([]*RepoFile, er
lastCommit.Message(), lastCommit.Message(),
lastCommit.Committer().When, lastCommit.Committer().When,
}) })
} }*/
return repofiles, nil return repofiles, nil
} }
@ -354,6 +376,10 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) {
session.Rollback() session.Rollback()
return err 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 { if _, err = session.Exec("update user set num_repos = num_repos - 1 where id = ?", userId); err != nil {
session.Rollback() session.Rollback()
return err return err

View file

@ -49,6 +49,9 @@ type User struct {
NumStars int NumStars int
NumRepos 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"` Created time.Time `xorm:"created"`
Updated time.Time `xorm:"updated"` Updated time.Time `xorm:"updated"`
} }
@ -104,6 +107,7 @@ func RegisterUser(user *User) (err error) {
user.LowerName = strings.ToLower(user.Name) user.LowerName = strings.ToLower(user.Name)
user.Avatar = base.EncodeMd5(user.Email) user.Avatar = base.EncodeMd5(user.Email)
user.AvatarEmail = user.Email
if err = user.EncodePasswd(); err != nil { if err = user.EncodePasswd(); err != nil {
return err return err
} }

View file

@ -23,7 +23,7 @@ type Form interface {
} }
type RegisterForm struct { 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)"` Email string `form:"email" binding:"Required;Email;MaxSize(50)"`
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
RetypePasswd string `form:"retypepasswd"` RetypePasswd string `form:"retypepasswd"`
@ -59,7 +59,7 @@ func (f *RegisterForm) Validate(errors *binding.Errors, req *http.Request, conte
} }
type LogInForm struct { 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)"` 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) validate(errors, data, f)
} }
type FeedsForm struct {
UserId int64 `form:"userid" binding:"Required"`
Offset int64 `form:"offset"`
}
func getMinMaxSize(field reflect.StructField) string { func getMinMaxSize(field reflect.StructField) string {
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
if strings.HasPrefix(rule, "MinSize(") || strings.HasPrefix(rule, "MaxSize(") { if strings.HasPrefix(rule, "MinSize(") || strings.HasPrefix(rule, "MaxSize(") {

View file

@ -5,10 +5,15 @@
package auth package auth
import ( import (
"net/http"
"reflect"
"github.com/codegangsta/martini" "github.com/codegangsta/martini"
"github.com/martini-contrib/render" "github.com/martini-contrib/render"
"github.com/martini-contrib/sessions" "github.com/martini-contrib/sessions"
"github.com/gogits/binding"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log" "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)
}

View file

@ -7,6 +7,8 @@ package base
import ( import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"fmt"
"time"
) )
// Encode string to md5 hex value // Encode string to md5 hex value
@ -15,3 +17,64 @@ func EncodeMd5(str string) string {
m.Write([]byte(str)) m.Write([]byte(str))
return hex.EncodeToString(m.Sum(nil)) 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()
}

View file

@ -6,7 +6,13 @@
package log package log
import ( import (
"fmt"
"github.com/martini-contrib/render"
"github.com/gogits/logs" "github.com/gogits/logs"
"github.com/gogits/gogs/modules/base"
) )
var logger *logs.BeeLogger var logger *logs.BeeLogger
@ -35,3 +41,9 @@ func Warn(format string, v ...interface{}) {
func Critical(format string, v ...interface{}) { func Critical(format string, v ...interface{}) {
logger.Critical(format, v...) 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)
}

View file

@ -137,6 +137,11 @@ body {
margin-top: 50px; margin-top: 50px;
} }
#gogs-body .btn-default {
background-color: #FFF;
background-image: linear-gradient(to bottom, #FFF 0, #FAFAFA 100%);
}
#gogs-body-nav { #gogs-body-nav {
margin-top: 52px; margin-top: 52px;
margin-bottom: -50px; margin-bottom: -50px;
@ -269,7 +274,8 @@ body {
/* gogits user setting */ /* 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; padding-bottom: 18px;
margin-bottom: 18px; margin-bottom: 18px;
border-bottom: 1px solid #CCC; border-bottom: 1px solid #CCC;
@ -380,6 +386,7 @@ body {
} }
#gogs-feed-right .repo-panel .list-group-item:hover { #gogs-feed-right .repo-panel .list-group-item:hover {
background-color: #eafffd;
background-color: rgba(65, 131, 196, 0.1); background-color: rgba(65, 131, 196, 0.1);
} }
@ -391,6 +398,12 @@ body {
/* gogits repo single page */ /* gogits repo single page */
#gogs-body-nav.gogs-repo-nav {
padding-top: 16px;
padding-bottom: 30px;
height: auto;
}
.gogs-repo-nav h3 .fa { .gogs-repo-nav h3 .fa {
color: #BBB; color: #BBB;
} }
@ -429,13 +442,13 @@ body {
margin-bottom: 4px; margin-bottom: 4px;
} }
#gogs-repo-toolbar { #gogs-repo-toolbar {
margin-top: 51px; margin-top: 51px;
margin-bottom: -50px; margin-bottom: -50px;
border-bottom: 1px solid #BBB; border-bottom: 1px solid #BBB;
background-color: #FFF; background-color: #FFF;
height: 40px; height: 40px;
font-size: 14px;
} }
#gogs-repo-toolbar .navbar-default { #gogs-repo-toolbar .navbar-default {
@ -458,3 +471,53 @@ body {
#gogs-repo-toolbar .navbar-collapse { #gogs-repo-toolbar .navbar-collapse {
padding: 0; 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;
}

View file

@ -78,7 +78,6 @@ function initRegister() {
rules: { rules: {
"username": { "username": {
required: true, required: true,
minlength: 5,
maxlength: 30 maxlength: 30
}, },
"email": { "email": {

View file

@ -5,9 +5,10 @@
package repo package repo
import ( import (
"net/http"
"github.com/martini-contrib/render" "github.com/martini-contrib/render"
"github.com/martini-contrib/sessions" "github.com/martini-contrib/sessions"
"net/http"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth" "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 == nil {
if _, err = models.CreateRepository(user, if _, err = models.CreateRepository(user,
form.RepoName, form.Description, form.Language, form.License, 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 { if err == nil {
data["RepoName"] = user.Name + "/" + form.RepoName data["RepoName"] = user.Name + "/" + form.RepoName
r.HTML(200, "repo/created", data) r.HTML(200, "repo/created", data)
@ -63,9 +64,7 @@ func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data b
return return
} }
data["ErrorMsg"] = err log.Handle(200, "repo.Create", data, r, err)
log.Error("repo.Create: %v", err)
r.HTML(200, "base/error", data)
} }
func Delete(form auth.DeleteRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session) { 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 { if err := models.DeleteRepository(form.UserId, form.RepoId, form.UserName); err != nil {
data["ErrorMsg"] = err log.Handle(200, "repo.Delete", data, r, err)
log.Error("repo.Delete: %v", err)
r.HTML(200, "base/error", data)
return return
} }
r.Redirect("/", 200) r.Redirect("/", 302)
} }
func List(req *http.Request, r render.Render, data base.TmplData, session sessions.Session) { 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" data["Title"] = "Repositories"
repos, err := models.GetRepositories(u) repos, err := models.GetRepositories(u)
if err != nil { if err != nil {
data["ErrorMsg"] = err log.Handle(200, "repo.List", data, r, err)
log.Error("repo.List: %v", err)
r.HTML(200, "base/error", data)
return return
} }

View file

@ -1,6 +1,7 @@
package repo package repo
import ( import (
"strings"
"github.com/codegangsta/martini" "github.com/codegangsta/martini"
"github.com/martini-contrib/render" "github.com/martini-contrib/render"
@ -13,15 +14,27 @@ func Single(params martini.Params, r render.Render, data base.TmplData) {
if !data["IsRepositoryValid"].(bool) { if !data["IsRepositoryValid"].(bool) {
return return
} }
if params["branchname"] == "" {
files, err := models.GetReposFiles(params["username"], params["reponame"], "HEAD", "/") params["branchname"] = "master"
}
treename := params["_1"]
files, err := models.GetReposFiles(params["username"], params["reponame"],
params["branchname"], treename)
if err != nil { if err != nil {
data["ErrorMsg"] = err log.Handle(200, "repo.Single", data, r, err)
log.Error("repo.List: %v", err)
r.HTML(200, "base/error", data)
return 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["IsRepoToolbarSource"] = true
data["Files"] = files data["Files"] = files

View file

@ -17,10 +17,70 @@ import (
"github.com/gogits/gogs/modules/log" "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["Title"] = "Setting"
data["PageIsUserSetting"] = true data["PageIsUserSetting"] = true
user := auth.SignedInUser(session)
data["Owner"] = user
if req.Method == "GET" {
r.HTML(200, "user/setting", data) 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) { func SettingSSHKeys(form auth.AddSSHKeyForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) {
@ -94,3 +154,17 @@ func SettingSSHKeys(form auth.AddSSHKeyForm, r render.Render, data base.TmplData
data["Keys"] = keys data["Keys"] = keys
r.HTML(200, "user/publickey", data) 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)
}

View file

@ -22,9 +22,7 @@ func Dashboard(r render.Render, data base.TmplData, session sessions.Session) {
data["PageIsUserDashboard"] = true data["PageIsUserDashboard"] = true
repos, err := models.GetRepositories(&models.User{Id: auth.SignedInId(session)}) repos, err := models.GetRepositories(&models.User{Id: auth.SignedInId(session)})
if err != nil { if err != nil {
data["ErrorMsg"] = err log.Handle(200, "user.Dashboard", data, r, err)
log.Error("dashboard: %v", err)
r.HTML(200, "base/error", data)
return return
} }
data["MyRepos"] = repos 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. // TODO: Need to check view self or others.
user, err := models.GetUserByName(params["username"]) user, err := models.GetUserByName(params["username"])
if err != nil { if err != nil {
data["ErrorMsg"] = err log.Handle(200, "user.Profile", data, r, err)
log.Error("user.Profile: %v", err)
r.HTML(200, "base/error", data)
return return
} }
data["Avatar"] = user.Avatar data["Owner"] = user
data["Username"] = user.Name
r.HTML(200, "user/profile", data) r.HTML(200, "user/profile", data)
} }
@ -71,9 +66,7 @@ func SignIn(form auth.LogInForm, data base.TmplData, req *http.Request, r render
return return
} }
data["ErrorMsg"] = err log.Handle(200, "user.SignIn", data, r, err)
log.Error("user.SignIn: %v", err)
r.HTML(200, "base/error", data)
return 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" data["ErrorMsg"] = "E-mail address has been already used"
r.HTML(200, "user/signup", data) r.HTML(200, "user/signup", data)
default: default:
data["ErrorMsg"] = err log.Handle(200, "user.SignUp", data, r, err)
log.Error("user.SignUp: %v", data)
r.HTML(200, "base/error", nil)
} }
return return
} }
@ -156,9 +147,7 @@ func Delete(data base.TmplData, req *http.Request, session sessions.Session, r r
case models.ErrUserOwnRepos.Error(): case models.ErrUserOwnRepos.Error():
data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first." data["ErrorMsg"] = "Your account still have ownership of repository, you have to delete or transfer them first."
default: default:
data["ErrorMsg"] = err log.Handle(200, "user.Delete", data, r, err)
log.Error("user.Delete: %v", data)
r.HTML(200, "base/error", nil)
return return
} }
} }

View file

@ -1,6 +1,17 @@
<div id="gogs-body-nav" class="gogs-repo-nav"> <div id="gogs-body-nav" class="gogs-repo-nav">
<div class="container"> <div class="container">
<div class="gogs-repo-btns pull-right"> <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"> <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"><i class="fa fa-eye"></i>Watch {x}</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">

View file

@ -3,11 +3,58 @@
{{template "repo/nav" .}} {{template "repo/nav" .}}
{{template "repo/toolbar" .}} {{template "repo/toolbar" .}}
<div id="gogs-body" class="container"> <div id="gogs-body" class="container">
<h4>Source Files:</h4> <div id="gogs-source">
<ul> <div id="gogs-source-toolbar">
{{range .Files}} <button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button>
<li>{{.Name}} - {{.Id}} - {{.Message}} - {{.Created}} - {{.IsFile}} - {{.IsDir}}</li> <div class="dropdown branch-switch">
{{end}} <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>master&nbsp;&nbsp;
<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> </ul>
</div> </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>&nbsp;
{{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" .}} {{template "base/footer" .}}

View file

@ -1,25 +1,17 @@
<div id="gogs-repo-toolbar"> <div id="gogs-repo-toolbar">
<div class="container"> <div class="container">
<nav class="navbar navbar-toolbar navbar-default" role="navigation"> <nav class="navbar navbar-toolbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="collapse navbar-collapse"> <div class="collapse navbar-collapse">
<ul class="nav navbar-nav"> <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 class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="/{{.RepositoryLink}}">Source</a></li>
<li><a href="#">Commits</a></li> <li><a href="/{{.RepositoryLink}}/commits">Commits</a></li>
<li><a href="#">Issues <span class="badge">42</span></a></li> <li><a href="/{{.RepositoryLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li>
<li><a href="#">Pull Requests</a></li> <li><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li>
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#">Release</a></li> <li><a href="/{{.RepositoryLink}}/release">Release</a></li>
<li><a href="#">Wiki</a></li> <li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -32,10 +24,10 @@
<li><a href="#">Network</a></li> <li><a href="#">Network</a></li>
</ul> </ul>
</li>{{if .IsRepositoryOwner}} </li>{{if .IsRepositoryOwner}}
<li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="/{{.RepositoryLink}}/settings">Settings</a></li>{{end}} <li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="/{{.RepositoryLink}}/settings">Settings</a>
</li>{{end}}
</ul> </ul>
</div> </div>
</div>
</nav> </nav>
</div> </div>
</div> </div>

View file

@ -5,10 +5,10 @@
<h4>Account Setting</h4> <h4>Account Setting</h4>
<ul class="list-group"> <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">Account Profile</a></li>
<li class="list-group-item"><a href="#">Emails and Password</a></li> <li class="list-group-item"><a href="/user/setting/password">Password</a></li>
<li class="list-group-item"><a href="#">Notifications</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/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> <li class="list-group-item list-group-item-success"><a href="/user/delete">Delete Account</a></li>
</ul> </ul>
</div> </div>

View file

@ -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" .}}

View file

@ -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>&nbsp;&nbsp;
<a href="/forget-password/">Forgot your password?</a>
</div>
</div>
</form>
</div>
</div>
</div>
{{template "base/footer" .}}

View file

@ -4,16 +4,16 @@
<div id="gogs-user-profile" class="col-md-3"> <div id="gogs-user-profile" class="col-md-3">
<div class="profile-avatar text-center"> <div class="profile-avatar text-center">
<a href="#" class="center-block" data-toggle="tooltip" data-placement="bottom" title="Change Avatar"> <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> </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>
<div class="profile-info"> <div class="profile-info">
<ul class="list-group"> <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-thumb-tack"></i>{{.Owner.Location}}</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-envelope"></i><a href="mailto:{{.Owner.Email}}">{{.Owner.Email}}</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-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</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-clock-o"></i>{{.Owner.Created}}</li>
</ul> </ul>
</div> </div>
</div> </div>

View file

@ -5,10 +5,10 @@
<h4>Account Setting</h4> <h4>Account Setting</h4>
<ul class="list-group"> <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">Account Profile</a></li>
<li class="list-group-item"><a href="#">Emails and Password</a></li> <li class="list-group-item"><a href="/user/setting/Password">Password</a></li>
<li class="list-group-item"><a href="#">Notifications</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 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> <li class="list-group-item"><a href="/user/delete">Delete Account</a></li>
</ul> </ul>
</div> </div>

View file

@ -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" .}}

View file

@ -1,8 +0,0 @@
{{template "base/head" .}}
{{template "base/navbar" .}}
<div class="container">
<div class="form-group">
publickey added
</div>
</div>
{{template "base/footer" .}}

View file

@ -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" .}}

View file

@ -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" .}}

View file

@ -5,15 +5,54 @@
<h4>Account Setting</h4> <h4>Account Setting</h4>
<ul class="list-group"> <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 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="/user/setting/password">Password</a></li>
<li class="list-group-item"><a href="#">Notifications</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/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> <li class="list-group-item"><a href="/user/delete">Delete Account</a></li>
</ul> </ul>
</div> </div>
<div id="gogs-user-setting-container" class="col-md-9"> <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>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View file

@ -7,7 +7,7 @@
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> <div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
<label class="col-md-4 control-label">Username: </label> <label class="col-md-4 control-label">Username: </label>
<div class="col-md-6"> <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>
</div> </div>

60
web.go
View file

@ -33,6 +33,55 @@ gogs web`,
Flags: []cli.Flag{}, 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{}{ var AppHelpers template.FuncMap = map[string]interface{}{
"AppName": func() string { "AppName": func() string {
return base.Cfg.MustValue("", "APP_NAME") return base.Cfg.MustValue("", "APP_NAME")
@ -40,6 +89,8 @@ var AppHelpers template.FuncMap = map[string]interface{}{
"AppVer": func() string { "AppVer": func() string {
return APP_VER return APP_VER
}, },
"TimeSince": base.TimeSince,
"Subtract": Subtract,
} }
func runWeb(*cli.Context) { func runWeb(*cli.Context) {
@ -63,8 +114,11 @@ func runWeb(*cli.Context) {
m.Any("/user/delete", auth.SignInRequire(true), user.Delete) m.Any("/user/delete", auth.SignInRequire(true), user.Delete)
m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) 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/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) 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.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/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", auth.SignInRequire(false), auth.RepoAssignment(true), repo.Single)
//m.Get("/:username/:reponame", repo.Repo) //m.Get("/:username/:reponame", repo.Repo)