From 7b34f6f1dac2c0b09b98e937226e43e0a6d09cf1 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 13 Mar 2014 02:55:14 -0400
Subject: [PATCH 01/15] Update README

---
 README.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index abb0b8ce20..05056e20a6 100644
--- a/README.md
+++ b/README.md
@@ -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.6 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,7 @@ 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.
 - Git repository manipulation.
 
 ## Installation

From 57bc2d1ca0bfc3ba90e6d85309dba39415c6db73 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 13 Mar 2014 03:39:18 -0400
Subject: [PATCH 02/15] Add update user profile back end, add new gitignore and
 license, add template data to public profile page

---
 conf/app.ini                        |  4 +--
 conf/gitignore/C                    | 18 ++++++++++++
 conf/license/BSD (3-Clause) License | 27 +++++++++++++++++
 gogs.go                             |  2 +-
 models/repo.go                      |  4 +++
 models/user.go                      |  4 ++-
 modules/auth/auth.go                |  5 ----
 modules/auth/user.go                | 45 +++++++++++++++++++++++++++++
 routers/repo/repo.go                |  4 +--
 routers/user/setting.go             | 24 ++++++++++++++-
 routers/user/user.go                |  3 +-
 templates/user/profile.tmpl         | 12 ++++----
 web.go                              |  2 +-
 13 files changed, 133 insertions(+), 21 deletions(-)
 create mode 100644 conf/gitignore/C
 create mode 100644 conf/license/BSD (3-Clause) License

diff --git a/conf/app.ini b/conf/app.ini
index fcfbe9bc2d..aa42129cce 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -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 = 
diff --git a/conf/gitignore/C b/conf/gitignore/C
new file mode 100644
index 0000000000..e7a909e4c6
--- /dev/null
+++ b/conf/gitignore/C
@@ -0,0 +1,18 @@
+# Object files
+*.o
+*.ko
+
+# Libraries
+*.lib
+*.a
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
\ No newline at end of file
diff --git a/conf/license/BSD (3-Clause) License b/conf/license/BSD (3-Clause) License
new file mode 100644
index 0000000000..3af16b0724
--- /dev/null
+++ b/conf/license/BSD (3-Clause) License	
@@ -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.
\ No newline at end of file
diff --git a/gogs.go b/gogs.go
index f1a702ed22..96c0f84f2b 100644
--- a/gogs.go
+++ b/gogs.go
@@ -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.0313"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/models/repo.go b/models/repo.go
index 6e45367c09..b7b5ac42b0 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -352,6 +352,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
diff --git a/models/user.go b/models/user.go
index c59e4ae152..06db7d8ba2 100644
--- a/models/user.go
+++ b/models/user.go
@@ -48,7 +48,9 @@ type User struct {
 	NumFollowings int
 	NumStars      int
 	NumRepos      int
-	Avatar        string    `xorm:"varchar(2048) not null"`
+	Avatar        string `xorm:"varchar(2048) not null"`
+	Location      string
+	Website       string
 	Created       time.Time `xorm:"created"`
 	Updated       time.Time `xorm:"updated"`
 }
diff --git a/modules/auth/auth.go b/modules/auth/auth.go
index e4748650c2..b085527554 100644
--- a/modules/auth/auth.go
+++ b/modules/auth/auth.go
@@ -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(") {
diff --git a/modules/auth/user.go b/modules/auth/user.go
index 4059edfdd3..e868fac23d 100644
--- a/modules/auth/user.go
+++ b/modules/auth/user.go
@@ -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,43 @@ 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:"AlphaDash;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)
+}
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index a12b45d7b9..e1809b4b7e 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -46,7 +46,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)
@@ -83,7 +83,7 @@ func Delete(form auth.DeleteRepoForm, req *http.Request, r render.Render, data b
 		return
 	}
 
-	r.Redirect("/", 200)
+	r.Redirect("/", 302)
 }
 
 func List(req *http.Request, r render.Render, data base.TmplData, session sessions.Session) {
diff --git a/routers/user/setting.go b/routers/user/setting.go
index 0669784be0..63e4d8cb7d 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -17,9 +17,31 @@ 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)
+	if req.Method == "GET" {
+		data["Owner"] = user
+	}
+
+	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)
+	if err := models.UpdateUser(user); err != nil {
+		data["ErrorMsg"] = err
+		log.Error("setting.Setting: %v", err)
+		r.HTML(200, "base/error", data)
+		return
+	}
+
 	r.HTML(200, "user/setting", data)
 }
 
diff --git a/routers/user/user.go b/routers/user/user.go
index 59177a47b9..2ce158b641 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -43,8 +43,7 @@ func Profile(params martini.Params, r render.Render, data base.TmplData, session
 		return
 	}
 
-	data["Avatar"] = user.Avatar
-	data["Username"] = user.Name
+	data["Owner"] = user
 	r.HTML(200, "user/profile", data)
 }
 
diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl
index 79e6062bcb..94ec33b696 100644
--- a/templates/user/profile.tmpl
+++ b/templates/user/profile.tmpl
@@ -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="#">{{.Owner.Email}}</a></li>
+                <li class="list-group-item"><i class="fa fa-link"></i><a href="#">{{.Owner.Website}}</a></li>
+                <li class="list-group-item"><i class="fa fa-clock-o"></i>{{.Owner.Created}}</li>
             </ul>
         </div>
     </div>
diff --git a/web.go b/web.go
index 475b662b39..856d0f106d 100644
--- a/web.go
+++ b/web.go
@@ -63,7 +63,7 @@ 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/ssh", auth.SignInRequire(true), binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
 
 	m.Get("/user/:username", auth.SignInRequire(false), user.Profile)

From 76dae5bf680cd701b1ae9876ecc21486a8721f92 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 13 Mar 2014 03:44:56 -0400
Subject: [PATCH 03/15] Bug fix

---
 routers/user/setting.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/routers/user/setting.go b/routers/user/setting.go
index 63e4d8cb7d..5ec4c455ef 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -24,6 +24,8 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 	user := auth.SignedInUser(session)
 	if req.Method == "GET" {
 		data["Owner"] = user
+		r.HTML(200, "user/setting", data)
+		return
 	}
 
 	if hasErr, ok := data["HasError"]; ok && hasErr.(bool) {

From c01f593daa994dddc208f853c1c116c56d2ea397 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 13 Mar 2014 04:06:35 -0400
Subject: [PATCH 04/15] Add updatePasswd

---
 README.md               |  3 ++-
 modules/auth/user.go    | 33 +++++++++++++++++++++++++++++++++
 routers/user/setting.go | 33 +++++++++++++++++++++++++++++++++
 web.go                  |  1 +
 4 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 05056e20a6..0e354a9d47 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ 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.6 Alpha
+##### Current version: 0.0.7 Alpha
 
 ## Purpose
 
@@ -18,6 +18,7 @@ Please see [Wiki](https://github.com/gogits/gogs/wiki) for project design, devel
 - SSH protocal support.
 - Register/delete account.
 - Create/delete public repository.
+- User/repository home page.
 - Git repository manipulation.
 
 ## Installation
diff --git a/modules/auth/user.go b/modules/auth/user.go
index e868fac23d..6bc7130626 100644
--- a/modules/auth/user.go
+++ b/modules/auth/user.go
@@ -128,3 +128,36 @@ func (f *UpdateProfileForm) Validate(errors *binding.Errors, req *http.Request,
 
 	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)
+}
diff --git a/routers/user/setting.go b/routers/user/setting.go
index 5ec4c455ef..02a214b2c1 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -47,6 +47,39 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 	r.HTML(200, "user/setting", data)
 }
 
+func UpdatePasswd(form auth.UpdatePasswdForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) {
+	data["Title"] = "Setting"
+	data["PageIsUserSetting"] = true
+
+	user := auth.SignedInUser(session)
+	newUser := &models.User{Passwd: form.OldPasswd}
+	if err := newUser.EncodePasswd(); err != nil {
+		data["ErrorMsg"] = err
+		log.Error("setting.UpdatePasswd: %v", err)
+		r.HTML(200, "base/error", data)
+		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 {
+			data["ErrorMsg"] = err
+			log.Error("setting.Setting: %v", err)
+			r.HTML(200, "base/error", data)
+			return
+		}
+	}
+
+	data["Owner"] = user
+	r.HTML(200, "user/setting", data)
+}
+
 func SettingSSHKeys(form auth.AddSSHKeyForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) {
 	data["Title"] = "SSH Keys"
 
diff --git a/web.go b/web.go
index 856d0f106d..a80c4924b9 100644
--- a/web.go
+++ b/web.go
@@ -64,6 +64,7 @@ func runWeb(*cli.Context) {
 	m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
 
 	m.Any("/user/setting", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
+	m.Post("/user/setting/update_passwd", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdatePasswdForm{}), user.UpdatePasswd)
 	m.Any("/user/setting/ssh", auth.SignInRequire(true), binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
 
 	m.Get("/user/:username", auth.SignInRequire(false), user.Profile)

From 52de63e7bbd500a90a1a8cb62cdb490b0ba623c7 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Thu, 13 Mar 2014 16:21:16 -0400
Subject: [PATCH 05/15] Allow 1 letter usernames

---
 modules/auth/auth.go       | 4 ++--
 public/js/app.js           | 1 -
 templates/user/signup.tmpl | 2 +-
 3 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/modules/auth/auth.go b/modules/auth/auth.go
index b085527554..0e87168891 100644
--- a/modules/auth/auth.go
+++ b/modules/auth/auth.go
@@ -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)"`
 }
 
diff --git a/public/js/app.js b/public/js/app.js
index 69d21020e8..0f0ecc43ea 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -78,7 +78,6 @@ function initRegister() {
             rules: {
                 "username": {
                     required: true,
-                    minlength: 5,
                     maxlength: 30
                 },
                 "email": {
diff --git a/templates/user/signup.tmpl b/templates/user/signup.tmpl
index ba41b0c9bb..2f1e82c730 100644
--- a/templates/user/signup.tmpl
+++ b/templates/user/signup.tmpl
@@ -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>
 

From 9c0672e0dd8381558dbae42bb4c49000dc4807c5 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 14 Mar 2014 11:24:08 +0800
Subject: [PATCH 06/15] user update-password page ui

---
 public/css/gogs.css                 | 16 ++++-----
 routers/user/setting.go             |  8 +++++
 templates/user/delete.tmpl          |  6 ++--
 templates/user/email_password.tmpl  | 53 +++++++++++++++++++++++++++++
 templates/user/publickey.tmpl       |  6 ++--
 templates/user/publickey_add.tmpl   | 26 --------------
 templates/user/publickey_added.tmpl |  8 -----
 templates/user/publickey_list.tmpl  | 12 -------
 templates/user/setting.tmpl         |  8 ++---
 web.go                              |  1 +
 10 files changed, 80 insertions(+), 64 deletions(-)
 create mode 100644 templates/user/email_password.tmpl
 delete mode 100644 templates/user/publickey_add.tmpl
 delete mode 100644 templates/user/publickey_added.tmpl
 delete mode 100644 templates/user/publickey_list.tmpl

diff --git a/public/css/gogs.css b/public/css/gogs.css
index a44d4a9380..7a05b9abe4 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -269,7 +269,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;
@@ -429,8 +430,7 @@ body {
     margin-bottom: 4px;
 }
 
-
-#gogs-repo-toolbar{
+#gogs-repo-toolbar {
     margin-top: 51px;
     margin-bottom: -50px;
     border-bottom: 1px solid #BBB;
@@ -438,23 +438,23 @@ body {
     height: 40px;
 }
 
-#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;
 }
\ No newline at end of file
diff --git a/routers/user/setting.go b/routers/user/setting.go
index 02a214b2c1..cf11095bea 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -47,6 +47,14 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 	r.HTML(200, "user/setting", data)
 }
 
+func SettingEmailPassword(r render.Render, data base.TmplData, session sessions.Session, req *http.Request) {
+	data["Title"] = "Email & Password"
+	data["PageIsUserSetting"] = true
+	data["IsPwdSuccess"] = (req.FormValue("password") == "true")
+
+	r.HTML(200, "user/email_password", data)
+}
+
 func UpdatePasswd(form auth.UpdatePasswdForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) {
 	data["Title"] = "Setting"
 	data["PageIsUserSetting"] = true
diff --git a/templates/user/delete.tmpl b/templates/user/delete.tmpl
index af0e1fbc06..37259f61e5 100644
--- a/templates/user/delete.tmpl
+++ b/templates/user/delete.tmpl
@@ -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/email_password">Emails and 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>
diff --git a/templates/user/email_password.tmpl b/templates/user/email_password.tmpl
new file mode 100644
index 0000000000..364bcf398e
--- /dev/null
+++ b/templates/user/email_password.tmpl
@@ -0,0 +1,53 @@
+{{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/email_password">Emails and 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-email">
+            <h4>Email</h4>
+            <p><strong>Your Primary Email</strong> will be used for Account related notifications as well as any web based operations, such as edits and merges made via the web.</p>
+            <p>// TODO</p><br/>
+        </div>
+        <div id="gogs-setting-pwd">
+            <h4>Password</h4>
+            <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting/update_passwd">{{if .IsPwdSuccess}}
+                <p class="alert alert-success">Password is changed successfully. You can sign in via new password.</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="re-type" 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/">Forget Password ?</a>
+                    </div>
+                </div>
+            </form>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/user/publickey.tmpl b/templates/user/publickey.tmpl
index 0bd76593e7..195af75887 100644
--- a/templates/user/publickey.tmpl
+++ b/templates/user/publickey.tmpl
@@ -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/email_password">Emails and 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>
diff --git a/templates/user/publickey_add.tmpl b/templates/user/publickey_add.tmpl
deleted file mode 100644
index 634b859ddd..0000000000
--- a/templates/user/publickey_add.tmpl
+++ /dev/null
@@ -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" .}}
\ No newline at end of file
diff --git a/templates/user/publickey_added.tmpl b/templates/user/publickey_added.tmpl
deleted file mode 100644
index f67da9ed85..0000000000
--- a/templates/user/publickey_added.tmpl
+++ /dev/null
@@ -1,8 +0,0 @@
-{{template "base/head" .}}
-{{template "base/navbar" .}}
-<div class="container">
-		<div class="form-group">
-			publickey added
-		</div>
-</div>
-{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/user/publickey_list.tmpl b/templates/user/publickey_list.tmpl
deleted file mode 100644
index fbd640b4bf..0000000000
--- a/templates/user/publickey_list.tmpl
+++ /dev/null
@@ -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" .}}
\ No newline at end of file
diff --git a/templates/user/setting.tmpl b/templates/user/setting.tmpl
index 79de58fe75..380ac88a62 100644
--- a/templates/user/setting.tmpl
+++ b/templates/user/setting.tmpl
@@ -5,10 +5,10 @@
         <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/email_password">Emails and 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>
diff --git a/web.go b/web.go
index a80c4924b9..4712861763 100644
--- a/web.go
+++ b/web.go
@@ -64,6 +64,7 @@ func runWeb(*cli.Context) {
 	m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
 
 	m.Any("/user/setting", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
+	m.Get("/user/setting/email_password",auth.SignInRequire(true),user.SettingEmailPassword)
 	m.Post("/user/setting/update_passwd", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdatePasswdForm{}), user.UpdatePasswd)
 	m.Any("/user/setting/ssh", auth.SignInRequire(true), binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
 

From bd4ee75fc3cb5f53e267d4340c67ff50206c2f72 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 00:19:07 -0400
Subject: [PATCH 07/15] Update

---
 .gitignore | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 0323c29726..6559d61a06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ gogs
 .DS_Store
 *.db
 *.log
-custom/
\ No newline at end of file
+custom/
+.vendor/

From 47edf7f4f9d359765764207cbcb6dd82dba36de8 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 01:12:07 -0400
Subject: [PATCH 08/15] Finish update password and profile

---
 gogs.go                                       |  2 +-
 models/user.go                                |  2 +
 modules/auth/user.go                          |  2 +-
 routers/user/setting.go                       | 27 ++++++------
 templates/user/delete.tmpl                    |  2 +-
 .../{email_password.tmpl => password.tmpl}    | 18 ++++----
 templates/user/profile.tmpl                   |  4 +-
 templates/user/publickey.tmpl                 |  2 +-
 templates/user/setting.tmpl                   | 43 ++++++++++++++++++-
 web.go                                        |  3 +-
 10 files changed, 72 insertions(+), 33 deletions(-)
 rename templates/user/{email_password.tmpl => password.tmpl} (76%)

diff --git a/gogs.go b/gogs.go
index 96c0f84f2b..b276490280 100644
--- a/gogs.go
+++ b/gogs.go
@@ -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.7.0313"
+const APP_VER = "0.0.7.0314"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/models/user.go b/models/user.go
index 06db7d8ba2..8f7a37cba9 100644
--- a/models/user.go
+++ b/models/user.go
@@ -49,6 +49,7 @@ type User struct {
 	NumStars      int
 	NumRepos      int
 	Avatar        string `xorm:"varchar(2048) not null"`
+	AvatarEmail   string `xorm:"not null"`
 	Location      string
 	Website       string
 	Created       time.Time `xorm:"created"`
@@ -106,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
 	}
diff --git a/modules/auth/user.go b/modules/auth/user.go
index 6bc7130626..ef595c6000 100644
--- a/modules/auth/user.go
+++ b/modules/auth/user.go
@@ -96,7 +96,7 @@ type FeedsForm struct {
 
 type UpdateProfileForm struct {
 	Email    string `form:"email" binding:"Required;Email;MaxSize(50)"`
-	Website  string `form:"website" binding:"AlphaDash;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)"`
 }
diff --git a/routers/user/setting.go b/routers/user/setting.go
index cf11095bea..08879ae4a7 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -22,8 +22,9 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 	data["PageIsUserSetting"] = true
 
 	user := auth.SignedInUser(session)
+	data["Owner"] = user
+
 	if req.Method == "GET" {
-		data["Owner"] = user
 		r.HTML(200, "user/setting", data)
 		return
 	}
@@ -37,6 +38,7 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 	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 {
 		data["ErrorMsg"] = err
 		log.Error("setting.Setting: %v", err)
@@ -44,23 +46,21 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 		return
 	}
 
+	data["IsSuccess"] = true
 	r.HTML(200, "user/setting", data)
 }
 
-func SettingEmailPassword(r render.Render, data base.TmplData, session sessions.Session, req *http.Request) {
-	data["Title"] = "Email & Password"
+func SettingPassword(form auth.UpdatePasswdForm, r render.Render, data base.TmplData, session sessions.Session, req *http.Request) {
+	data["Title"] = "Password"
 	data["PageIsUserSetting"] = true
-	data["IsPwdSuccess"] = (req.FormValue("password") == "true")
 
-	r.HTML(200, "user/email_password", data)
-}
-
-func UpdatePasswd(form auth.UpdatePasswdForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) {
-	data["Title"] = "Setting"
-	data["PageIsUserSetting"] = true
+	if req.Method == "GET" {
+		r.HTML(200, "user/password", data)
+		return
+	}
 
 	user := auth.SignedInUser(session)
-	newUser := &models.User{Passwd: form.OldPasswd}
+	newUser := &models.User{Passwd: form.NewPasswd}
 	if err := newUser.EncodePasswd(); err != nil {
 		data["ErrorMsg"] = err
 		log.Error("setting.UpdatePasswd: %v", err)
@@ -78,14 +78,15 @@ func UpdatePasswd(form auth.UpdatePasswdForm, r render.Render, data base.TmplDat
 		user.Passwd = newUser.Passwd
 		if err := models.UpdateUser(user); err != nil {
 			data["ErrorMsg"] = err
-			log.Error("setting.Setting: %v", err)
+			log.Error("setting.UpdatePasswd: %v", err)
 			r.HTML(200, "base/error", data)
 			return
 		}
+		data["IsSuccess"] = true
 	}
 
 	data["Owner"] = user
-	r.HTML(200, "user/setting", data)
+	r.HTML(200, "user/password", data)
 }
 
 func SettingSSHKeys(form auth.AddSSHKeyForm, r render.Render, data base.TmplData, req *http.Request, session sessions.Session) {
diff --git a/templates/user/delete.tmpl b/templates/user/delete.tmpl
index 37259f61e5..904201772e 100644
--- a/templates/user/delete.tmpl
+++ b/templates/user/delete.tmpl
@@ -5,7 +5,7 @@
         <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/email_password">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="/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>
diff --git a/templates/user/email_password.tmpl b/templates/user/password.tmpl
similarity index 76%
rename from templates/user/email_password.tmpl
rename to templates/user/password.tmpl
index 364bcf398e..a8b1e21e04 100644
--- a/templates/user/email_password.tmpl
+++ b/templates/user/password.tmpl
@@ -5,7 +5,7 @@
         <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/email_password">Emails and Password</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>
@@ -13,37 +13,35 @@
         </ul>
     </div>
     <div id="gogs-user-setting-container" class="col-md-9">
-        <div id="gogs-setting-email">
-            <h4>Email</h4>
-            <p><strong>Your Primary Email</strong> will be used for Account related notifications as well as any web based operations, such as edits and merges made via the web.</p>
-            <p>// TODO</p><br/>
-        </div>
         <div id="gogs-setting-pwd">
             <h4>Password</h4>
-            <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting/update_passwd">{{if .IsPwdSuccess}}
-                <p class="alert alert-success">Password is changed successfully. You can sign in via new password.</p>{{end}}
+            <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="re-type" class="form-control" placeholder="Re-type your new password" required="required">
+                        <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/">Forget Password ?</a>
+                        <a href="/forget-password/">Forgot your password?</a>
                     </div>
                 </div>
             </form>
diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl
index 94ec33b696..c10bfcb0f3 100644
--- a/templates/user/profile.tmpl
+++ b/templates/user/profile.tmpl
@@ -11,8 +11,8 @@
         <div class="profile-info">
             <ul class="list-group">
                 <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="#">{{.Owner.Email}}</a></li>
-                <li class="list-group-item"><i class="fa fa-link"></i><a href="#">{{.Owner.Website}}</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 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>
diff --git a/templates/user/publickey.tmpl b/templates/user/publickey.tmpl
index 195af75887..60d2c2464a 100644
--- a/templates/user/publickey.tmpl
+++ b/templates/user/publickey.tmpl
@@ -5,7 +5,7 @@
         <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/email_password">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="/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="/user/setting/security">Security</a></li>
diff --git a/templates/user/setting.tmpl b/templates/user/setting.tmpl
index 380ac88a62..edbeeb22a9 100644
--- a/templates/user/setting.tmpl
+++ b/templates/user/setting.tmpl
@@ -5,7 +5,7 @@
         <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="/user/setting/email_password">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="/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>
@@ -13,7 +13,46 @@
         </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" .}}
\ No newline at end of file
diff --git a/web.go b/web.go
index 4712861763..1fa19afc17 100644
--- a/web.go
+++ b/web.go
@@ -64,8 +64,7 @@ func runWeb(*cli.Context) {
 	m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
 
 	m.Any("/user/setting", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
-	m.Get("/user/setting/email_password",auth.SignInRequire(true),user.SettingEmailPassword)
-	m.Post("/user/setting/update_passwd", auth.SignInRequire(true), binding.BindIgnErr(auth.UpdatePasswdForm{}), user.UpdatePasswd)
+	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.Get("/user/:username", auth.SignInRequire(false), user.Profile)

From 56cf05be771977abd9ae2e68dd446092c595981c Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 01:40:34 -0400
Subject: [PATCH 09/15] Add errHandler mid ware

---
 modules/log/error.go | 32 ++++++++++++++++++++++++++++++++
 routers/repo/repo.go |  9 ++++-----
 web.go               |  1 +
 3 files changed, 37 insertions(+), 5 deletions(-)
 create mode 100644 modules/log/error.go

diff --git a/modules/log/error.go b/modules/log/error.go
new file mode 100644
index 0000000000..cb94ec2473
--- /dev/null
+++ b/modules/log/error.go
@@ -0,0 +1,32 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package log
+
+import (
+	"github.com/codegangsta/martini"
+	"github.com/martini-contrib/render"
+)
+
+// ErrHandler is an interface for custom error handler.
+type ErrHandler interface {
+	Handle(string, render.Render, error)
+}
+
+// ErrHandle is a Middleware that maps a ErrHandler service into the Martini handler chain.
+func ErrHandle() martini.Handler {
+	return func(context martini.Context) {
+		context.MapTo(&errHandler{}, (*ErrHandler)(nil))
+	}
+}
+
+type errHandler struct {
+}
+
+func (eh *errHandler) Handle(title string, r render.Render, err error) {
+	Error("%s: %v", title, err)
+	r.HTML(200, "base/error", map[string]interface{}{
+		"ErrorMsg": err,
+	})
+}
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index e1809b4b7e..1c9bb0500c 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -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"
@@ -15,7 +16,7 @@ import (
 	"github.com/gogits/gogs/modules/log"
 )
 
-func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session) {
+func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session, eh log.ErrHandler) {
 	data["Title"] = "Create repository"
 
 	if req.Method == "GET" {
@@ -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)
+	eh.Handle("repo.Create", r, err)
 }
 
 func Delete(form auth.DeleteRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session) {
diff --git a/web.go b/web.go
index 1fa19afc17..30e881bba1 100644
--- a/web.go
+++ b/web.go
@@ -50,6 +50,7 @@ func runWeb(*cli.Context) {
 	// Middlewares.
 	m.Use(render.Renderer(render.Options{Funcs: []template.FuncMap{AppHelpers}}))
 	m.Use(base.InitContext())
+	m.Use(log.ErrHandle())
 
 	// TODO: should use other store because cookie store is not secure.
 	store := sessions.NewCookieStore([]byte("secret123"))

From 15f8bc417e2b5683e2cd578c9c50f51acfd3daba Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 01:51:12 -0400
Subject: [PATCH 10/15] Add log.handle

---
 modules/log/error.go | 32 --------------------------------
 modules/log/log.go   | 10 ++++++++++
 routers/repo/repo.go |  4 ++--
 web.go               |  1 -
 4 files changed, 12 insertions(+), 35 deletions(-)
 delete mode 100644 modules/log/error.go

diff --git a/modules/log/error.go b/modules/log/error.go
deleted file mode 100644
index cb94ec2473..0000000000
--- a/modules/log/error.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Gogs Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package log
-
-import (
-	"github.com/codegangsta/martini"
-	"github.com/martini-contrib/render"
-)
-
-// ErrHandler is an interface for custom error handler.
-type ErrHandler interface {
-	Handle(string, render.Render, error)
-}
-
-// ErrHandle is a Middleware that maps a ErrHandler service into the Martini handler chain.
-func ErrHandle() martini.Handler {
-	return func(context martini.Context) {
-		context.MapTo(&errHandler{}, (*ErrHandler)(nil))
-	}
-}
-
-type errHandler struct {
-}
-
-func (eh *errHandler) Handle(title string, r render.Render, err error) {
-	Error("%s: %v", title, err)
-	r.HTML(200, "base/error", map[string]interface{}{
-		"ErrorMsg": err,
-	})
-}
diff --git a/modules/log/log.go b/modules/log/log.go
index 0634bde655..f71be7c133 100644
--- a/modules/log/log.go
+++ b/modules/log/log.go
@@ -6,7 +6,11 @@
 package log
 
 import (
+	"github.com/martini-contrib/render"
+
 	"github.com/gogits/logs"
+
+	"github.com/gogits/gogs/modules/base"
 )
 
 var logger *logs.BeeLogger
@@ -35,3 +39,9 @@ func Warn(format string, v ...interface{}) {
 func Critical(format string, v ...interface{}) {
 	logger.Critical(format, v...)
 }
+
+func Handle(status int, title, tmpl string, data base.TmplData, r render.Render, err error) {
+	data["ErrorMsg"] = err
+	Error("%s: %v", title, err)
+	r.HTML(status, tmpl, data)
+}
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index 1c9bb0500c..706b4f937d 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -16,7 +16,7 @@ import (
 	"github.com/gogits/gogs/modules/log"
 )
 
-func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session, eh log.ErrHandler) {
+func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session) {
 	data["Title"] = "Create repository"
 
 	if req.Method == "GET" {
@@ -64,7 +64,7 @@ func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data b
 		return
 	}
 
-	eh.Handle("repo.Create", r, err)
+	log.Handle(200, "repo.Create", "base/error", data, r, err)
 }
 
 func Delete(form auth.DeleteRepoForm, req *http.Request, r render.Render, data base.TmplData, session sessions.Session) {
diff --git a/web.go b/web.go
index 30e881bba1..1fa19afc17 100644
--- a/web.go
+++ b/web.go
@@ -50,7 +50,6 @@ func runWeb(*cli.Context) {
 	// Middlewares.
 	m.Use(render.Renderer(render.Options{Funcs: []template.FuncMap{AppHelpers}}))
 	m.Use(base.InitContext())
-	m.Use(log.ErrHandle())
 
 	// TODO: should use other store because cookie store is not secure.
 	store := sessions.NewCookieStore([]byte("secret123"))

From 1ce17cce764b5c10feeba5a92586be9a45173e26 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 01:59:07 -0400
Subject: [PATCH 11/15] Add log.handle

---
 modules/log/log.go                            |  6 ++++--
 routers/repo/repo.go                          | 10 +++-------
 routers/repo/single.go                        |  4 +---
 routers/user/setting.go                       | 12 +++--------
 routers/user/user.go                          | 20 +++++--------------
 .../{base/error.tmpl => status/200.tmpl}      |  0
 6 files changed, 16 insertions(+), 36 deletions(-)
 rename templates/{base/error.tmpl => status/200.tmpl} (100%)

diff --git a/modules/log/log.go b/modules/log/log.go
index f71be7c133..b3a3e0a63c 100644
--- a/modules/log/log.go
+++ b/modules/log/log.go
@@ -6,6 +6,8 @@
 package log
 
 import (
+	"fmt"
+
 	"github.com/martini-contrib/render"
 
 	"github.com/gogits/logs"
@@ -40,8 +42,8 @@ func Critical(format string, v ...interface{}) {
 	logger.Critical(format, v...)
 }
 
-func Handle(status int, title, tmpl string, data base.TmplData, r render.Render, err error) {
+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, tmpl, data)
+	r.HTML(status, fmt.Sprintf("status/%d", status), data)
 }
diff --git a/routers/repo/repo.go b/routers/repo/repo.go
index 706b4f937d..b25ce1899c 100644
--- a/routers/repo/repo.go
+++ b/routers/repo/repo.go
@@ -64,7 +64,7 @@ func Create(form auth.CreateRepoForm, req *http.Request, r render.Render, data b
 		return
 	}
 
-	log.Handle(200, "repo.Create", "base/error", data, r, err)
+	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) {
@@ -76,9 +76,7 @@ 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
 	}
 
@@ -95,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
 	}
 
diff --git a/routers/repo/single.go b/routers/repo/single.go
index 1d5e601aa3..489666f406 100644
--- a/routers/repo/single.go
+++ b/routers/repo/single.go
@@ -16,9 +16,7 @@ func Single(params martini.Params, r render.Render, data base.TmplData) {
 
 	files, err := models.GetReposFiles(params["username"], params["reponame"], "HEAD", "/")
 	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
 	}
 
diff --git a/routers/user/setting.go b/routers/user/setting.go
index 08879ae4a7..b01d27d845 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -40,9 +40,7 @@ func Setting(form auth.UpdateProfileForm, r render.Render, data base.TmplData, r
 	user.Avatar = base.EncodeMd5(form.Avatar)
 	user.AvatarEmail = form.Avatar
 	if err := models.UpdateUser(user); err != nil {
-		data["ErrorMsg"] = err
-		log.Error("setting.Setting: %v", err)
-		r.HTML(200, "base/error", data)
+		log.Handle(200, "setting.Setting", data, r, err)
 		return
 	}
 
@@ -62,9 +60,7 @@ func SettingPassword(form auth.UpdatePasswdForm, r render.Render, data base.Tmpl
 	user := auth.SignedInUser(session)
 	newUser := &models.User{Passwd: form.NewPasswd}
 	if err := newUser.EncodePasswd(); err != nil {
-		data["ErrorMsg"] = err
-		log.Error("setting.UpdatePasswd: %v", err)
-		r.HTML(200, "base/error", data)
+		log.Handle(200, "setting.SettingPassword", data, r, err)
 		return
 	}
 
@@ -77,9 +73,7 @@ func SettingPassword(form auth.UpdatePasswdForm, r render.Render, data base.Tmpl
 	} else {
 		user.Passwd = newUser.Passwd
 		if err := models.UpdateUser(user); err != nil {
-			data["ErrorMsg"] = err
-			log.Error("setting.UpdatePasswd: %v", err)
-			r.HTML(200, "base/error", data)
+			log.Handle(200, "setting.SettingPassword", data, r, err)
 			return
 		}
 		data["IsSuccess"] = true
diff --git a/routers/user/user.go b/routers/user/user.go
index 2ce158b641..6095b53808 100644
--- a/routers/user/user.go
+++ b/routers/user/user.go
@@ -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,9 +35,7 @@ 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
 	}
 
@@ -70,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
 	}
 
@@ -129,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
 	}
@@ -155,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
 		}
 	}
diff --git a/templates/base/error.tmpl b/templates/status/200.tmpl
similarity index 100%
rename from templates/base/error.tmpl
rename to templates/status/200.tmpl

From 8d1fcdaf2cb647edd1bbc031b601afa99a1f8989 Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 14 Mar 2014 14:17:29 +0800
Subject: [PATCH 12/15] repo page ui

---
 public/css/gogs.css         | 63 +++++++++++++++++++++++++++++++++++++
 templates/repo/nav.tmpl     | 11 +++++++
 templates/repo/single.tmpl  | 59 ++++++++++++++++++++++++++++++++++
 templates/repo/toolbar.tmpl | 60 +++++++++++++++--------------------
 4 files changed, 159 insertions(+), 34 deletions(-)

diff --git a/public/css/gogs.css b/public/css/gogs.css
index 7a05b9abe4..160f561ca2 100755
--- a/public/css/gogs.css
+++ b/public/css/gogs.css
@@ -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;
@@ -381,6 +386,7 @@ body {
 }
 
 #gogs-feed-right .repo-panel .list-group-item:hover {
+    background-color: #eafffd;
     background-color: rgba(65, 131, 196, 0.1);
 }
 
@@ -392,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;
 }
@@ -436,6 +448,7 @@ body {
     border-bottom: 1px solid #BBB;
     background-color: #FFF;
     height: 40px;
+    font-size: 14px;
 }
 
 #gogs-repo-toolbar .navbar-default {
@@ -457,4 +470,54 @@ body {
 
 #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;
 }
\ No newline at end of file
diff --git a/templates/repo/nav.tmpl b/templates/repo/nav.tmpl
index 5d60d46107..1a9434e860 100644
--- a/templates/repo/nav.tmpl
+++ b/templates/repo/nav.tmpl
@@ -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">
diff --git a/templates/repo/single.tmpl b/templates/repo/single.tmpl
index 42e09b9a2f..54d06aed40 100644
--- a/templates/repo/single.tmpl
+++ b/templates/repo/single.tmpl
@@ -3,6 +3,65 @@
 {{template "repo/nav" .}}
 {{template "repo/toolbar" .}}
 <div id="gogs-body" class="container">
+    <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&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>
+            </div>
+            <ol class="breadcrumb">
+                <li class="root dir">{{.Repository.Name}}</li>
+                <li class="dir">Dir</li>
+            </ol>
+        </div>
+        <table id="gogs-source-table" class="table table-hover">
+            <thead class="hidden">
+            <tr>
+                <th class="name">Filename</th>
+                <th class="size">Size</th>
+                <th class="date">Date modified</th>
+                <th class="text">Message</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr class="is-dir">
+                <td class="name" colspan="3"><i class="fa fa-folder"></i><a href="#">dir-1</a></td>
+                <td class="message">commit message</td>
+            </tr>
+            <tr class="is-dir">
+                <td class="name" colspan="3"><i class="fa fa-folder"></i><a href="#">dir-2</a></td>
+                <td class="message"> commit message</td>
+            </tr>
+            <tr class="is-dir">
+                <td class="name" colspan="3"><i class="fa fa-folder"></i><a href="#">dir-3</a></td>
+                <td class="message">commit message</td>
+            </tr>
+            <tr>
+                <td class="name"><i class="fa fa-file"></i><a href="#">file-1.txt</a></td>
+                <td class="size">177 B</td>
+                <td class="date"><time datetime="2011-10-20T06:51:01+08:00" data-title="true" title="20 October 2011 06:51">3 years ago</time></td>
+                <td class="text">commit message</td>
+            </tr>
+            <tr>
+                <td class="name"><i class="fa fa-file"></i><a href="#">file-2.txt</a></td>
+                <td class="size">177 B</td>
+                <td class="date"><time datetime="2011-10-20T06:51:01+08:00" data-title="true" title="20 October 2011 06:51">3 years ago</time></td>
+                <td class="text">commit message</td>
+            </tr><tr>
+                <td class="name"><i class="fa fa-file"></i><a href="#">file-3.txt</a></td>
+                <td class="size">177 B</td>
+                <td class="date"><time datetime="2011-10-20T06:51:01+08:00" data-title="true" title="20 October 2011 06:51">3 years ago</time></td>
+                <td class="text">commit message</td>
+            </tr>
+
+            </tbody>
+        </table>
+    </div>
     <h4>Source Files:</h4>
     <ul>
     {{range .Files}}
diff --git a/templates/repo/toolbar.tmpl b/templates/repo/toolbar.tmpl
index a409fcbea7..4a0b60adad 100644
--- a/templates/repo/toolbar.tmpl
+++ b/templates/repo/toolbar.tmpl
@@ -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>

From bd6542c2f1a3b1ebdf09a59ab2187510e6b36bde Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 02:32:11 -0400
Subject: [PATCH 13/15] Add TimeSince

---
 modules/base/tool.go | 63 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/modules/base/tool.go b/modules/base/tool.go
index eef473f965..445833cebc 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -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()
+}

From 398809b135742ad8a7441f65fa7d0ccec318bd91 Mon Sep 17 00:00:00 2001
From: Unknown <joe2010xtmf@163.com>
Date: Fri, 14 Mar 2014 02:40:07 -0400
Subject: [PATCH 14/15] Combine UI and data in repo home page

---
 templates/repo/single.tmpl | 54 +++++++++-----------------------------
 web.go                     |  1 +
 2 files changed, 13 insertions(+), 42 deletions(-)

diff --git a/templates/repo/single.tmpl b/templates/repo/single.tmpl
index 54d06aed40..4a71ad3465 100644
--- a/templates/repo/single.tmpl
+++ b/templates/repo/single.tmpl
@@ -21,52 +21,22 @@
         </div>
         <table id="gogs-source-table" class="table table-hover">
             <thead class="hidden">
-            <tr>
-                <th class="name">Filename</th>
-                <th class="size">Size</th>
-                <th class="date">Date modified</th>
-                <th class="text">Message</th>
-            </tr>
+	            <tr>
+	                <th class="name">Filename</th>
+	                <th class="date">Date modified</th>
+	                <th class="text">Message</th>
+	            </tr>
             </thead>
             <tbody>
-            <tr class="is-dir">
-                <td class="name" colspan="3"><i class="fa fa-folder"></i><a href="#">dir-1</a></td>
-                <td class="message">commit message</td>
-            </tr>
-            <tr class="is-dir">
-                <td class="name" colspan="3"><i class="fa fa-folder"></i><a href="#">dir-2</a></td>
-                <td class="message"> commit message</td>
-            </tr>
-            <tr class="is-dir">
-                <td class="name" colspan="3"><i class="fa fa-folder"></i><a href="#">dir-3</a></td>
-                <td class="message">commit message</td>
-            </tr>
-            <tr>
-                <td class="name"><i class="fa fa-file"></i><a href="#">file-1.txt</a></td>
-                <td class="size">177 B</td>
-                <td class="date"><time datetime="2011-10-20T06:51:01+08:00" data-title="true" title="20 October 2011 06:51">3 years ago</time></td>
-                <td class="text">commit message</td>
-            </tr>
-            <tr>
-                <td class="name"><i class="fa fa-file"></i><a href="#">file-2.txt</a></td>
-                <td class="size">177 B</td>
-                <td class="date"><time datetime="2011-10-20T06:51:01+08:00" data-title="true" title="20 October 2011 06:51">3 years ago</time></td>
-                <td class="text">commit message</td>
-            </tr><tr>
-                <td class="name"><i class="fa fa-file"></i><a href="#">file-3.txt</a></td>
-                <td class="size">177 B</td>
-                <td class="date"><time datetime="2011-10-20T06:51:01+08:00" data-title="true" title="20 October 2011 06:51">3 years ago</time></td>
-                <td class="text">commit message</td>
-            </tr>
-
+    			{{range .Files}}
+				<tr {{if .IsDir}}class="is-dir"{{end}}>
+	                <td class="name"><i class="fa fa-file"></i><a href="#">{{.Name}}</a></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>
-    <h4>Source Files:</h4>
-    <ul>
-    {{range .Files}}
-        <li>{{.Name}} - {{.Message}} - {{.Created}} - {{.IsFile}} - {{.IsDir}}</li>
-    {{end}}
-    </ul>
 </div>
 {{template "base/footer" .}}
\ No newline at end of file
diff --git a/web.go b/web.go
index 1fa19afc17..f416d96e86 100644
--- a/web.go
+++ b/web.go
@@ -40,6 +40,7 @@ var AppHelpers template.FuncMap = map[string]interface{}{
 	"AppVer": func() string {
 		return APP_VER
 	},
+	"TimeSince": base.TimeSince,
 }
 
 func runWeb(*cli.Context) {

From d18237850c6a4ae855b3f8592994c91462fcdb0a Mon Sep 17 00:00:00 2001
From: FuXiaoHei <fuxiaohei@hexiaz.com>
Date: Fri, 14 Mar 2014 17:12:28 +0800
Subject: [PATCH 15/15] add draft page for empty link

---
 routers/user/setting.go          | 14 ++++++++++++++
 templates/repo/single.tmpl       |  2 +-
 templates/user/notification.tmpl | 19 +++++++++++++++++++
 templates/user/security.tmpl     | 19 +++++++++++++++++++
 web.go                           |  2 ++
 5 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 templates/user/notification.tmpl
 create mode 100644 templates/user/security.tmpl

diff --git a/routers/user/setting.go b/routers/user/setting.go
index b01d27d845..8b5a2d18df 100644
--- a/routers/user/setting.go
+++ b/routers/user/setting.go
@@ -154,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)
+}
diff --git a/templates/repo/single.tmpl b/templates/repo/single.tmpl
index 4a71ad3465..fbd05c4ba7 100644
--- a/templates/repo/single.tmpl
+++ b/templates/repo/single.tmpl
@@ -30,7 +30,7 @@
             <tbody>
     			{{range .Files}}
 				<tr {{if .IsDir}}class="is-dir"{{end}}>
-	                <td class="name"><i class="fa fa-file"></i><a href="#">{{.Name}}</a></td>
+	                <td class="name"><i class="fa {{if .IsDir}}fa-folder{{else}}fa-file{{end}}"></i><a href="#">{{.Name}}</a></td>
 	                <td class="date"><time datetime="{{.Created}}" data-title="true" title="{{.Created}}">{{TimeSince .Created}}</time></td>
 	                <td class="text">{{.Message}}</td>
 				</tr>
diff --git a/templates/user/notification.tmpl b/templates/user/notification.tmpl
new file mode 100644
index 0000000000..c1abc46fb0
--- /dev/null
+++ b/templates/user/notification.tmpl
@@ -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" .}}
\ No newline at end of file
diff --git a/templates/user/security.tmpl b/templates/user/security.tmpl
new file mode 100644
index 0000000000..37cd5872aa
--- /dev/null
+++ b/templates/user/security.tmpl
@@ -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" .}}
\ No newline at end of file
diff --git a/web.go b/web.go
index f416d96e86..8f698e39d7 100644
--- a/web.go
+++ b/web.go
@@ -67,6 +67,8 @@ func runWeb(*cli.Context) {
 	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)