Browse Source

Merge branch 'master' of github.com:gogits/gogs

Conflicts:
	models/update.go
	routers/repo/http.go
Lunny Xiao 10 years ago
parent
commit
86e2627175
75 changed files with 2032 additions and 659 deletions
  1. 0 3
      README.md
  2. 0 3
      README_ZH.md
  3. 10 10
      cmd/serve.go
  4. 3 1
      cmd/update.go
  5. 13 2
      cmd/web.go
  6. 2 2
      conf/app.ini
  7. 1 1
      gogs.go
  8. 9 8
      models/access.go
  9. 6 5
      models/action.go
  10. 2 2
      models/issue.go
  11. 2 2
      models/login.go
  12. 1 1
      models/models.go
  13. 192 0
      models/org.go
  14. 80 49
      models/repo.go
  15. 14 13
      models/update.go
  16. 107 54
      models/user.go
  17. 57 0
      modules/auth/org.go
  18. 5 3
      modules/auth/repo.go
  19. 16 14
      modules/auth/user.go
  20. 1 0
      modules/base/base.go
  21. 235 236
      modules/bin/conf.go
  22. 14 5
      modules/mailer/mail.go
  23. 4 4
      modules/middleware/context.go
  24. 2 2
      modules/middleware/repo.go
  25. 7 7
      modules/setting/setting.go
  26. 114 3
      public/css/gogs.css
  27. 24 0
      public/js/app.js
  28. 19 10
      routers/admin/admin.go
  29. 14 9
      routers/admin/auth.go
  30. 29 21
      routers/admin/user.go
  31. 6 1
      routers/dashboard.go
  32. 2 1
      routers/dev/template.go
  33. 17 11
      routers/install.go
  34. 152 1
      routers/org/org.go
  35. 21 0
      routers/org/teams.go
  36. 8 3
      routers/repo/branch.go
  37. 48 44
      routers/repo/commit.go
  38. 4 4
      routers/repo/http.go
  39. 27 7
      routers/repo/issue.go
  40. 6 1
      routers/repo/pull.go
  41. 15 4
      routers/repo/release.go
  42. 84 22
      routers/repo/repo.go
  43. 43 28
      routers/repo/setting.go
  44. 30 11
      routers/user/home.go
  45. 18 9
      routers/user/setting.go
  46. 36 26
      routers/user/user.go
  47. 1 1
      templates/VERSION
  48. 0 0
      templates/admin/auth/edit.tmpl
  49. 0 0
      templates/admin/auth/new.tmpl
  50. 2 2
      templates/admin/config.tmpl
  51. 0 0
      templates/admin/user/edit.tmpl
  52. 0 0
      templates/admin/user/new.tmpl
  53. 0 0
      templates/mail/auth/active.tmpl
  54. 75 0
      templates/org/edit_team.tmpl
  55. 56 0
      templates/org/members.tmpl
  56. 32 0
      templates/org/new.tmpl
  57. 74 0
      templates/org/new_team.tmpl
  58. 130 0
      templates/org/settings.tmpl
  59. 71 0
      templates/org/teams.tmpl
  60. 0 0
      templates/repo/branch.tmpl
  61. 30 2
      templates/repo/create.tmpl
  62. 0 0
      templates/repo/hook_add.tmpl
  63. 0 0
      templates/repo/hook_edit.tmpl
  64. 0 0
      templates/repo/issue/create.tmpl
  65. 0 0
      templates/repo/issue/list.tmpl
  66. 0 0
      templates/repo/issue/milestone.tmpl
  67. 0 0
      templates/repo/issue/milestone_edit.tmpl
  68. 0 0
      templates/repo/issue/milestone_new.tmpl
  69. 0 0
      templates/repo/issue/view.tmpl
  70. 30 2
      templates/repo/migrate.tmpl
  71. 0 0
      templates/repo/release/edit.tmpl
  72. 0 0
      templates/repo/release/list.tmpl
  73. 0 0
      templates/repo/release/new.tmpl
  74. 29 8
      templates/user/dashboard.tmpl
  75. 2 1
      templates/user/issues.tmpl

+ 0 - 3
README.md

@@ -75,9 +75,6 @@ There are 5 ways to install Gogs:
 
 
 The [core team](http://gogs.io/team) of this project. See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for full list of contributors.
 The [core team](http://gogs.io/team) of this project. See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for full list of contributors.
 
 
-[![Clone in Koding](http://learn.koding.com/btn/clone_d.png)][koding]
-[koding]: https://koding.com/Teamwork?import=https://github.com/gogits/gogs/archive/master.zip&c=git1
-
 ## License
 ## License
 
 
 This project is under the MIT License. See the [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) file for the full license text.
 This project is under the MIT License. See the [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) file for the full license text.

+ 0 - 3
README_ZH.md

@@ -66,9 +66,6 @@ Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依
 
 
 本项目的 [开发团队](http://gogs.io/team)。您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
 本项目的 [开发团队](http://gogs.io/team)。您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
 
 
-[![Clone in Koding](http://learn.koding.com/btn/clone_d.png)][koding]
-[koding]: https://koding.com/Teamwork?import=https://github.com/gogits/gogs/archive/master.zip&c=git1
-
 ## 授权许可
 ## 授权许可
 
 
 本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) 文件中。
 本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) 文件中。

+ 10 - 10
cmd/serve.go

@@ -56,19 +56,19 @@ func parseCmd(cmd string) (string, string) {
 }
 }
 
 
 var (
 var (
-	COMMANDS_READONLY = map[string]int{
-		"git-upload-pack":    models.AU_WRITABLE,
-		"git upload-pack":    models.AU_WRITABLE,
-		"git-upload-archive": models.AU_WRITABLE,
+	COMMANDS_READONLY = map[string]models.AccessType{
+		"git-upload-pack":    models.WRITABLE,
+		"git upload-pack":    models.WRITABLE,
+		"git-upload-archive": models.WRITABLE,
 	}
 	}
 
 
-	COMMANDS_WRITE = map[string]int{
-		"git-receive-pack": models.AU_READABLE,
-		"git receive-pack": models.AU_READABLE,
+	COMMANDS_WRITE = map[string]models.AccessType{
+		"git-receive-pack": models.READABLE,
+		"git receive-pack": models.READABLE,
 	}
 	}
 )
 )
 
 
-func In(b string, sl map[string]int) bool {
+func In(b string, sl map[string]models.AccessType) bool {
 	_, e := sl[b]
 	_, e := sl[b]
 	return e
 	return e
 }
 }
@@ -129,7 +129,7 @@ func runServ(k *cli.Context) {
 	// Access check.
 	// Access check.
 	switch {
 	switch {
 	case isWrite:
 	case isWrite:
-		has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_WRITABLE)
+		has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.WRITABLE)
 		if err != nil {
 		if err != nil {
 			println("Gogs: internal error:", err)
 			println("Gogs: internal error:", err)
 			log.GitLogger.Fatal("Fail to check write access:", err)
 			log.GitLogger.Fatal("Fail to check write access:", err)
@@ -152,7 +152,7 @@ func runServ(k *cli.Context) {
 			break
 			break
 		}
 		}
 
 
-		has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_READABLE)
+		has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.READABLE)
 		if err != nil {
 		if err != nil {
 			println("Gogs: internal error:", err)
 			println("Gogs: internal error:", err)
 			log.GitLogger.Fatal("Fail to check read access:", err)
 			log.GitLogger.Fatal("Fail to check read access:", err)

+ 3 - 1
cmd/update.go

@@ -42,5 +42,7 @@ func runUpdate(c *cli.Context) {
 	repoUserName := os.Getenv("repoUserName")
 	repoUserName := os.Getenv("repoUserName")
 	repoName := os.Getenv("repoName")
 	repoName := os.Getenv("repoName")
 
 
-	models.Update(args[0], args[1], args[2], userName, repoUserName, repoName, userId)
+	if err := models.Update(args[0], args[1], args[2], userName, repoUserName, repoName, userId); err != nil {
+		log.GitLogger.Fatal(err.Error())
+	}
 }
 }

+ 13 - 2
cmd/web.go

@@ -188,9 +188,20 @@ func runWeb(*cli.Context) {
 
 
 	reqOwner := middleware.RequireOwner()
 	reqOwner := middleware.RequireOwner()
 
 
-	m.Group("/o", func(r martini.Router) {
+	m.Group("/org", func(r martini.Router) {
+		r.Get("/create", org.New)
+		r.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.NewPost)
 		r.Get("/:org", org.Organization)
 		r.Get("/:org", org.Organization)
-	})
+		r.Get("/:org/dashboard", org.Dashboard)
+		r.Get("/:org/members", org.Members)
+		// organization teams
+		r.Get("/:org/teams/:team/edit", org.EditTeam)
+		r.Get("/:org/teams/new", org.NewTeam)
+		r.Get("/:org/teams", org.Teams)
+
+		r.Get("/:org/settings", org.Settings)
+		r.Post("/:org/settings", bindIgnErr(auth.OrgSettingForm{}), org.SettingsPost)
+	}, reqSignIn)
 
 
 	m.Group("/:username/:reponame", func(r martini.Router) {
 	m.Group("/:username/:reponame", func(r martini.Router) {
 		r.Get("/settings", repo.Setting)
 		r.Get("/settings", repo.Setting)

+ 2 - 2
conf/app.ini

@@ -51,8 +51,8 @@ SECRET_KEY = !#@FDEWREWR&*(
 LOGIN_REMEMBER_DAYS = 7
 LOGIN_REMEMBER_DAYS = 7
 COOKIE_USERNAME = gogs_awesome
 COOKIE_USERNAME = gogs_awesome
 COOKIE_REMEMBER_NAME = gogs_incredible
 COOKIE_REMEMBER_NAME = gogs_incredible
-; Reverse proxy authentication header name of user ID
-REVERSE_PROXY_AUTHENTICATION_UID = X-WEBAUTH-UID
+; Reverse proxy authentication header name of user name
+REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
 
 
 [service]
 [service]
 ACTIVE_CODE_LIVE_MINUTES = 180
 ACTIVE_CODE_LIVE_MINUTES = 180

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
-const APP_VER = "0.4.5.0621 Alpha"
+const APP_VER = "0.4.5.0627 Alpha"
 
 
 func init() {
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
 	runtime.GOMAXPROCS(runtime.NumCPU())

+ 9 - 8
models/access.go

@@ -11,19 +11,20 @@ import (
 	"github.com/go-xorm/xorm"
 	"github.com/go-xorm/xorm"
 )
 )
 
 
-// Access types.
+type AccessType int
+
 const (
 const (
-	AU_READABLE = iota + 1
-	AU_WRITABLE
+	READABLE AccessType = iota + 1
+	WRITABLE
 )
 )
 
 
 // Access represents the accessibility of user to repository.
 // Access represents the accessibility of user to repository.
 type Access struct {
 type Access struct {
 	Id       int64
 	Id       int64
-	UserName string    `xorm:"unique(s)"`
-	RepoName string    `xorm:"unique(s)"` // <user name>/<repo name>
-	Mode     int       `xorm:"unique(s)"`
-	Created  time.Time `xorm:"created"`
+	UserName string     `xorm:"unique(s)"`
+	RepoName string     `xorm:"unique(s)"` // <user name>/<repo name>
+	Mode     AccessType `xorm:"unique(s)"`
+	Created  time.Time  `xorm:"created"`
 }
 }
 
 
 // AddAccess adds new access record.
 // AddAccess adds new access record.
@@ -59,7 +60,7 @@ func UpdateAccessWithSession(sess *xorm.Session, access *Access) error {
 
 
 // HasAccess returns true if someone can read or write to given repository.
 // HasAccess returns true if someone can read or write to given repository.
 // The repoName should be in format <username>/<reponame>.
 // The repoName should be in format <username>/<reponame>.
-func HasAccess(uname, repoName string, mode int) (bool, error) {
+func HasAccess(uname, repoName string, mode AccessType) (bool, error) {
 	if len(repoName) == 0 {
 	if len(repoName) == 0 {
 		return false, nil
 		return false, nil
 	}
 	}

+ 6 - 5
models/action.go

@@ -182,14 +182,15 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
 }
 }
 
 
 // NewRepoAction adds new action for creating repository.
 // NewRepoAction adds new action for creating repository.
-func NewRepoAction(user *User, repo *Repository) (err error) {
-	if err = NotifyWatchers(&Action{ActUserId: user.Id, ActUserName: user.Name, ActEmail: user.Email,
-		OpType: OP_CREATE_REPO, RepoId: repo.Id, RepoName: repo.Name, IsPrivate: repo.IsPrivate}); err != nil {
-		log.Error("action.NewRepoAction(notify watchers): %d/%s", user.Id, repo.Name)
+func NewRepoAction(u *User, repo *Repository) (err error) {
+	if err = NotifyWatchers(&Action{ActUserId: u.Id, ActUserName: u.Name, ActEmail: u.Email,
+		OpType: OP_CREATE_REPO, RepoId: repo.Id, RepoUserName: repo.Owner.Name, RepoName: repo.Name,
+		IsPrivate: repo.IsPrivate}); err != nil {
+		log.Error("action.NewRepoAction(notify watchers): %d/%s", u.Id, repo.Name)
 		return err
 		return err
 	}
 	}
 
 
-	log.Trace("action.NewRepoAction: %s/%s", user.LowerName, repo.LowerName)
+	log.Trace("action.NewRepoAction: %s/%s", u.LowerName, repo.LowerName)
 	return err
 	return err
 }
 }
 
 

+ 2 - 2
models/issue.go

@@ -213,9 +213,9 @@ func GetIssueCountByPoster(uid, rid int64, isClosed bool) int64 {
 // IssueUser represents an issue-user relation.
 // IssueUser represents an issue-user relation.
 type IssueUser struct {
 type IssueUser struct {
 	Id          int64
 	Id          int64
-	Uid         int64 // User ID.
+	Uid         int64 `xorm:"INDEX"` // User ID.
 	IssueId     int64
 	IssueId     int64
-	RepoId      int64
+	RepoId      int64 `xorm:"INDEX"`
 	MilestoneId int64
 	MilestoneId int64
 	IsRead      bool
 	IsRead      bool
 	IsAssigned  bool
 	IsAssigned  bool

+ 2 - 2
models/login.go

@@ -255,7 +255,7 @@ func LoginUserLdapSource(user *User, name, passwd string, sourceId int64, cfg *L
 		Email:       mail,
 		Email:       mail,
 	}
 	}
 
 
-	return RegisterUser(user)
+	return CreateUser(user)
 }
 }
 
 
 type loginAuth struct {
 type loginAuth struct {
@@ -359,5 +359,5 @@ func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *S
 		Passwd:      passwd,
 		Passwd:      passwd,
 		Email:       name,
 		Email:       name,
 	}
 	}
-	return RegisterUser(user)
+	return CreateUser(user)
 }
 }

+ 1 - 1
models/models.go

@@ -35,7 +35,7 @@ func init() {
 	tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch),
 	tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch),
 		new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow),
 		new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow),
 		new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser),
 		new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser),
-		new(Milestone), new(Label), new(HookTask))
+		new(Milestone), new(Label), new(HookTask), new(Team), new(OrgUser), new(TeamUser))
 }
 }
 
 
 func LoadModelsConfig() {
 func LoadModelsConfig() {

+ 192 - 0
models/org.go

@@ -0,0 +1,192 @@
+// 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 models
+
+import (
+	"strings"
+
+	"github.com/gogits/gogs/modules/base"
+)
+
+// CreateOrganization creates record of a new organization.
+func CreateOrganization(org, owner *User) (*User, error) {
+	if !IsLegalName(org.Name) {
+		return nil, ErrUserNameIllegal
+	}
+
+	isExist, err := IsUserExist(org.Name)
+	if err != nil {
+		return nil, err
+	} else if isExist {
+		return nil, ErrUserAlreadyExist
+	}
+
+	isExist, err = IsEmailUsed(org.Email)
+	if err != nil {
+		return nil, err
+	} else if isExist {
+		return nil, ErrEmailAlreadyUsed
+	}
+
+	org.LowerName = strings.ToLower(org.Name)
+	org.FullName = org.Name
+	org.Avatar = base.EncodeMd5(org.Email)
+	org.AvatarEmail = org.Email
+	// No password for organization.
+	org.NumTeams = 1
+	org.NumMembers = 1
+
+	sess := x.NewSession()
+	defer sess.Close()
+	if err = sess.Begin(); err != nil {
+		return nil, err
+	}
+
+	if _, err = sess.Insert(org); err != nil {
+		sess.Rollback()
+		return nil, err
+	}
+
+	// Create default owner team.
+	t := &Team{
+		OrgId:      org.Id,
+		Name:       OWNER_TEAM,
+		Authorize:  ORG_ADMIN,
+		NumMembers: 1,
+	}
+	if _, err = sess.Insert(t); err != nil {
+		sess.Rollback()
+		return nil, err
+	}
+
+	// Add initial creator to organization and owner team.
+	ou := &OrgUser{
+		Uid:     owner.Id,
+		OrgId:   org.Id,
+		IsOwner: true,
+		NumTeam: 1,
+	}
+	if _, err = sess.Insert(ou); err != nil {
+		sess.Rollback()
+		return nil, err
+	}
+
+	tu := &TeamUser{
+		Uid:    owner.Id,
+		OrgId:  org.Id,
+		TeamId: t.Id,
+	}
+	if _, err = sess.Insert(tu); err != nil {
+		sess.Rollback()
+		return nil, err
+	}
+
+	return org, sess.Commit()
+}
+
+type AuthorizeType int
+
+const (
+	ORG_READABLE AuthorizeType = iota + 1
+	ORG_WRITABLE
+	ORG_ADMIN
+)
+
+const OWNER_TEAM = "Owner"
+
+// Team represents a organization team.
+type Team struct {
+	Id          int64
+	OrgId       int64 `xorm:"INDEX"`
+	Name        string
+	Description string
+	Authorize   AuthorizeType
+	RepoIds     string `xorm:"TEXT"`
+	NumMembers  int
+	NumRepos    int
+}
+
+// NewTeam creates a record of new team.
+func NewTeam(t *Team) error {
+	_, err := x.Insert(t)
+	return err
+}
+
+func UpdateTeam(t *Team) error {
+	if len(t.Description) > 255 {
+		t.Description = t.Description[:255]
+	}
+
+	_, err := x.Id(t.Id).AllCols().Update(t)
+	return err
+}
+
+// ________                ____ ___
+// \_____  \_______  ____ |    |   \______ ___________
+//  /   |   \_  __ \/ ___\|    |   /  ___// __ \_  __ \
+// /    |    \  | \/ /_/  >    |  /\___ \\  ___/|  | \/
+// \_______  /__|  \___  /|______//____  >\___  >__|
+//         \/     /_____/              \/     \/
+
+// OrgUser represents an organization-user relation.
+type OrgUser struct {
+	Id       int64
+	Uid      int64 `xorm:"INDEX"`
+	OrgId    int64 `xorm:"INDEX"`
+	IsPublic bool
+	IsOwner  bool
+	NumTeam  int
+}
+
+// GetOrgUsersByUserId returns all organization-user relations by user ID.
+func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
+	ous := make([]*OrgUser, 0, 10)
+	err := x.Where("uid=?", uid).Find(&ous)
+	return ous, err
+}
+
+// GetOrgUsersByOrgId returns all organization-user relations by organization ID.
+func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
+	ous := make([]*OrgUser, 0, 10)
+	err := x.Where("org_id=?", orgId).Find(&ous)
+	return ous, err
+}
+
+func GetOrganizationCount(u *User) (int64, error) {
+	return x.Where("uid=?", u.Id).Count(new(OrgUser))
+}
+
+// ___________                    ____ ___
+// \__    ___/___ _____    _____ |    |   \______ ___________
+//   |    |_/ __ \\__  \  /     \|    |   /  ___// __ \_  __ \
+//   |    |\  ___/ / __ \|  Y Y  \    |  /\___ \\  ___/|  | \/
+//   |____| \___  >____  /__|_|  /______//____  >\___  >__|
+//              \/     \/      \/             \/     \/
+
+// TeamUser represents an team-user relation.
+type TeamUser struct {
+	Id     int64
+	Uid    int64
+	OrgId  int64 `xorm:"INDEX"`
+	TeamId int64
+}
+
+// GetTeamMembers returns all members in given team of organization.
+func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
+	tus := make([]*TeamUser, 0, 10)
+	err := x.Where("org_id=?", orgId).And("team_id=?", teamId).Find(&tus)
+	if err != nil {
+		return nil, err
+	}
+
+	us := make([]*User, len(tus))
+	for i, tu := range tus {
+		us[i], err = GetUserById(tu.Uid)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return us, nil
+}

+ 80 - 49
models/repo.go

@@ -158,7 +158,7 @@ func IsRepositoryExist(u *User, repoName string) (bool, error) {
 }
 }
 
 
 var (
 var (
-	illegalEquals  = []string{"raw", "install", "api", "avatar", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
+	illegalEquals  = []string{"raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
 	illegalSuffixs = []string{".git"}
 	illegalSuffixs = []string{".git"}
 )
 )
 
 
@@ -240,7 +240,7 @@ func MirrorUpdate() {
 			"git", "remote", "update"); err != nil {
 			"git", "remote", "update"); err != nil {
 			return errors.New("git remote update: " + stderr)
 			return errors.New("git remote update: " + stderr)
 		} else if err = git.UnpackRefs(repoPath); err != nil {
 		} else if err = git.UnpackRefs(repoPath); err != nil {
-			return err
+			return errors.New("UnpackRefs: " + err.Error())
 		}
 		}
 
 
 		m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
 		m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
@@ -251,8 +251,8 @@ func MirrorUpdate() {
 }
 }
 
 
 // MigrateRepository migrates a existing repository from other project hosting.
 // MigrateRepository migrates a existing repository from other project hosting.
-func MigrateRepository(user *User, name, desc string, private, mirror bool, url string) (*Repository, error) {
-	repo, err := CreateRepository(user, name, desc, "", "", private, mirror, false)
+func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) {
+	repo, err := CreateRepository(u, name, desc, "", "", private, mirror, false)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -261,11 +261,11 @@ func MigrateRepository(user *User, name, desc string, private, mirror bool, url
 	tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()))
 	tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()))
 	os.MkdirAll(tmpDir, os.ModePerm)
 	os.MkdirAll(tmpDir, os.ModePerm)
 
 
-	repoPath := RepoPath(user.Name, name)
+	repoPath := RepoPath(u.Name, name)
 
 
 	repo.IsBare = false
 	repo.IsBare = false
 	if mirror {
 	if mirror {
-		if err = MirrorRepository(repo.Id, user.Name, repo.Name, repoPath, url); err != nil {
+		if err = MirrorRepository(repo.Id, u.Name, repo.Name, repoPath, url); err != nil {
 			return repo, err
 			return repo, err
 		}
 		}
 		repo.IsMirror = true
 		repo.IsMirror = true
@@ -454,21 +454,28 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
 	return initRepoCommit(tmpDir, user.NewGitSig())
 	return initRepoCommit(tmpDir, user.NewGitSig())
 }
 }
 
 
-// CreateRepository creates a repository for given user or orgnaziation.
-func CreateRepository(user *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) {
+// CreateRepository creates a repository for given user or organization.
+func CreateRepository(u *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) {
 	if !IsLegalName(name) {
 	if !IsLegalName(name) {
 		return nil, ErrRepoNameIllegal
 		return nil, ErrRepoNameIllegal
 	}
 	}
 
 
-	isExist, err := IsRepositoryExist(user, name)
+	isExist, err := IsRepositoryExist(u, name)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	} else if isExist {
 	} else if isExist {
 		return nil, ErrRepoAlreadyExist
 		return nil, ErrRepoAlreadyExist
 	}
 	}
 
 
+	sess := x.NewSession()
+	defer sess.Close()
+	if err = sess.Begin(); err != nil {
+		return nil, err
+	}
+
 	repo := &Repository{
 	repo := &Repository{
-		OwnerId:     user.Id,
+		OwnerId:     u.Id,
+		Owner:       u,
 		Name:        name,
 		Name:        name,
 		LowerName:   strings.ToLower(name),
 		LowerName:   strings.ToLower(name),
 		Description: desc,
 		Description: desc,
@@ -479,67 +486,85 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir
 		repo.DefaultBranch = "master"
 		repo.DefaultBranch = "master"
 	}
 	}
 
 
-	repoPath := RepoPath(user.Name, repo.Name)
-
-	sess := x.NewSession()
-	defer sess.Close()
-	sess.Begin()
-
 	if _, err = sess.Insert(repo); err != nil {
 	if _, err = sess.Insert(repo); err != nil {
-		if err2 := os.RemoveAll(repoPath); err2 != nil {
-			log.Error("repo.CreateRepository(repo): %v", err)
-			return nil, errors.New(fmt.Sprintf(
-				"delete repo directory %s/%s failed(1): %v", user.Name, repo.Name, err2))
-		}
 		sess.Rollback()
 		sess.Rollback()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	mode := AU_WRITABLE
+	var t *Team // Owner team.
+
+	mode := WRITABLE
 	if mirror {
 	if mirror {
-		mode = AU_READABLE
+		mode = READABLE
 	}
 	}
-	access := Access{
-		UserName: user.LowerName,
-		RepoName: strings.ToLower(path.Join(user.Name, repo.Name)),
+	access := &Access{
+		UserName: u.LowerName,
+		RepoName: strings.ToLower(path.Join(u.Name, repo.Name)),
 		Mode:     mode,
 		Mode:     mode,
 	}
 	}
-	if _, err = sess.Insert(&access); err != nil {
-		sess.Rollback()
-		if err2 := os.RemoveAll(repoPath); err2 != nil {
-			log.Error("repo.CreateRepository(access): %v", err)
-			return nil, errors.New(fmt.Sprintf(
-				"delete repo directory %s/%s failed(2): %v", user.Name, repo.Name, err2))
+	// Give access to all members in owner team.
+	if u.IsOrganization() {
+		t, err = u.GetOwnerTeam()
+		if err != nil {
+			sess.Rollback()
+			return nil, err
+		}
+		us, err := GetTeamMembers(u.Id, t.Id)
+		if err != nil {
+			sess.Rollback()
+			return nil, err
+		}
+		for _, u := range us {
+			access.UserName = u.LowerName
+			if _, err = sess.Insert(access); err != nil {
+				sess.Rollback()
+				return nil, err
+			}
+		}
+	} else {
+		if _, err = sess.Insert(access); err != nil {
+			sess.Rollback()
+			return nil, err
 		}
 		}
-		return nil, err
 	}
 	}
 
 
 	rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?"
 	rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?"
-	if _, err = sess.Exec(rawSql, user.Id); err != nil {
+	if _, err = sess.Exec(rawSql, u.Id); err != nil {
 		sess.Rollback()
 		sess.Rollback()
-		if err2 := os.RemoveAll(repoPath); err2 != nil {
-			log.Error("repo.CreateRepository(repo count): %v", err)
-			return nil, errors.New(fmt.Sprintf(
-				"delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2))
-		}
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err = sess.Commit(); err != nil {
-		sess.Rollback()
-		if err2 := os.RemoveAll(repoPath); err2 != nil {
-			log.Error("repo.CreateRepository(commit): %v", err)
-			return nil, errors.New(fmt.Sprintf(
-				"delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2))
+	// Update owner team info and count.
+	if u.IsOrganization() {
+		t.RepoIds += "$" + base.ToStr(repo.Id) + "|"
+		t.NumRepos++
+		if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
+			sess.Rollback()
+			return nil, err
 		}
 		}
+	}
+
+	if err = sess.Commit(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err = WatchRepo(user.Id, repo.Id, true); err != nil {
-		log.Error("repo.CreateRepository(WatchRepo): %v", err)
+	if u.IsOrganization() {
+		ous, err := GetOrgUsersByOrgId(u.Id)
+		if err != nil {
+			log.Error("repo.CreateRepository(GetOrgUsersByOrgId): %v", err)
+		} else {
+			for _, ou := range ous {
+				if err = WatchRepo(ou.Uid, repo.Id, true); err != nil {
+					log.Error("repo.CreateRepository(WatchRepo): %v", err)
+				}
+			}
+		}
+	}
+	if err = WatchRepo(u.Id, repo.Id, true); err != nil {
+		log.Error("repo.CreateRepository(WatchRepo2): %v", err)
 	}
 	}
 
 
-	if err = NewRepoAction(user, repo); err != nil {
+	if err = NewRepoAction(u, repo); err != nil {
 		log.Error("repo.CreateRepository(NewRepoAction): %v", err)
 		log.Error("repo.CreateRepository(NewRepoAction): %v", err)
 	}
 	}
 
 
@@ -548,7 +573,13 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir
 		return repo, nil
 		return repo, nil
 	}
 	}
 
 
-	if err = initRepository(repoPath, user, repo, initReadme, lang, license); err != nil {
+	repoPath := RepoPath(u.Name, repo.Name)
+	if err = initRepository(repoPath, u, repo, initReadme, lang, license); err != nil {
+		if err2 := os.RemoveAll(repoPath); err2 != nil {
+			log.Error("repo.CreateRepository(initRepository): %v", err)
+			return nil, errors.New(fmt.Sprintf(
+				"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2))
+		}
 		return nil, err
 		return nil, err
 	}
 	}
 
 

+ 14 - 13
models/update.go

@@ -6,6 +6,7 @@ package models
 
 
 import (
 import (
 	"container/list"
 	"container/list"
+	"fmt"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 
 
@@ -15,13 +16,13 @@ import (
 	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/log"
 )
 )
 
 
-func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) {
+func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) error {
 	//fmt.Println(refName, oldCommitId, newCommitId)
 	//fmt.Println(refName, oldCommitId, newCommitId)
 	//fmt.Println(userName, repoUserName, repoName)
 	//fmt.Println(userName, repoUserName, repoName)
 	isNew := strings.HasPrefix(oldCommitId, "0000000")
 	isNew := strings.HasPrefix(oldCommitId, "0000000")
 	if isNew &&
 	if isNew &&
 		strings.HasPrefix(newCommitId, "0000000") {
 		strings.HasPrefix(newCommitId, "0000000") {
-		log.GitLogger.Fatal("old rev and new rev both 000000")
+		return fmt.Errorf("old rev and new rev both 000000")
 	}
 	}
 
 
 	f := RepoPath(repoUserName, repoName)
 	f := RepoPath(repoUserName, repoName)
@@ -33,18 +34,17 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 	isDel := strings.HasPrefix(newCommitId, "0000000")
 	isDel := strings.HasPrefix(newCommitId, "0000000")
 	if isDel {
 	if isDel {
 		log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userId)
 		log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userId)
-		return
+		return nil
 	}
 	}
 
 
 	repo, err := git.OpenRepository(f)
 	repo, err := git.OpenRepository(f)
 	if err != nil {
 	if err != nil {
-		log.GitLogger.Fatal("runUpdate.Open repoId: %v", err)
+		return fmt.Errorf("runUpdate.Open repoId: %v", err)
 	}
 	}
 
 
 	newCommit, err := repo.GetCommit(newCommitId)
 	newCommit, err := repo.GetCommit(newCommitId)
 	if err != nil {
 	if err != nil {
-		log.GitLogger.Fatal("runUpdate GetCommit of newCommitId: %v", err)
-		return
+		return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err)
 	}
 	}
 
 
 	var l *list.List
 	var l *list.List
@@ -52,28 +52,27 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 	if isNew {
 	if isNew {
 		l, err = newCommit.CommitsBefore()
 		l, err = newCommit.CommitsBefore()
 		if err != nil {
 		if err != nil {
-			log.GitLogger.Fatal("Find CommitsBefore erro: %v", err)
+			return fmt.Errorf("Find CommitsBefore erro: %v", err)
 		}
 		}
 	} else {
 	} else {
 		l, err = newCommit.CommitsBeforeUntil(oldCommitId)
 		l, err = newCommit.CommitsBeforeUntil(oldCommitId)
 		if err != nil {
 		if err != nil {
-			log.GitLogger.Fatal("Find CommitsBeforeUntil erro: %v", err)
-			return
+			return fmt.Errorf("Find CommitsBeforeUntil erro: %v", err)
 		}
 		}
 	}
 	}
 
 
 	if err != nil {
 	if err != nil {
-		log.GitLogger.Fatal("runUpdate.Commit repoId: %v", err)
+		return fmt.Errorf("runUpdate.Commit repoId: %v", err)
 	}
 	}
 
 
 	ru, err := GetUserByName(repoUserName)
 	ru, err := GetUserByName(repoUserName)
 	if err != nil {
 	if err != nil {
-		log.GitLogger.Fatal("runUpdate.GetUserByName: %v", err)
+		return fmt.Errorf("runUpdate.GetUserByName: %v", err)
 	}
 	}
 
 
 	repos, err := GetRepositoryByName(ru.Id, repoName)
 	repos, err := GetRepositoryByName(ru.Id, repoName)
 	if err != nil {
 	if err != nil {
-		log.GitLogger.Fatal("runUpdate.GetRepositoryByName userId: %v", err)
+		return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err)
 	}
 	}
 
 
 	// if tags push
 	// if tags push
@@ -104,6 +103,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		return
 		return
 	}
 	}
 
 
+	// if commits push
 	commits := make([]*base.PushCommit, 0)
 	commits := make([]*base.PushCommit, 0)
 	var maxCommits = 3
 	var maxCommits = 3
 	var actEmail string
 	var actEmail string
@@ -126,6 +126,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 	//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
 	//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
 	if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
 	if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
 		repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}); err != nil {
 		repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}); err != nil {
-		log.GitLogger.Fatal("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
+		return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
 	}
 	}
+	return nil
 }
 }

+ 107 - 54
models/user.go

@@ -21,14 +21,16 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
-// User types.
+type UserType int
+
 const (
 const (
-	UT_INDIVIDUAL = iota + 1
-	UT_ORGANIZATION
+	INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
+	ORGANIZATION
 )
 )
 
 
 var (
 var (
 	ErrUserOwnRepos          = errors.New("User still have ownership of repositories")
 	ErrUserOwnRepos          = errors.New("User still have ownership of repositories")
+	ErrUserHasOrgs           = errors.New("User still have membership of organization")
 	ErrUserAlreadyExist      = errors.New("User already exist")
 	ErrUserAlreadyExist      = errors.New("User already exist")
 	ErrUserNotExist          = errors.New("User does not exist")
 	ErrUserNotExist          = errors.New("User does not exist")
 	ErrUserNotKeyOwner       = errors.New("User does not the owner of public key")
 	ErrUserNotKeyOwner       = errors.New("User does not the owner of public key")
@@ -50,7 +52,8 @@ type User struct {
 	LoginType     LoginType
 	LoginType     LoginType
 	LoginSource   int64 `xorm:"not null default 0"`
 	LoginSource   int64 `xorm:"not null default 0"`
 	LoginName     string
 	LoginName     string
-	Type          int
+	Type          UserType
+	Orgs          []*User `xorm:"-"`
 	NumFollowers  int
 	NumFollowers  int
 	NumFollowings int
 	NumFollowings int
 	NumStars      int
 	NumStars      int
@@ -65,43 +68,71 @@ type User struct {
 	Salt          string    `xorm:"VARCHAR(10)"`
 	Salt          string    `xorm:"VARCHAR(10)"`
 	Created       time.Time `xorm:"created"`
 	Created       time.Time `xorm:"created"`
 	Updated       time.Time `xorm:"updated"`
 	Updated       time.Time `xorm:"updated"`
+
+	// For organization.
+	Description string
+	NumTeams    int
+	NumMembers  int
 }
 }
 
 
 // HomeLink returns the user home page link.
 // HomeLink returns the user home page link.
-func (user *User) HomeLink() string {
-	return "/user/" + user.Name
+func (u *User) HomeLink() string {
+	return "/user/" + u.Name
 }
 }
 
 
 // AvatarLink returns user gravatar link.
 // AvatarLink returns user gravatar link.
-func (user *User) AvatarLink() string {
+func (u *User) AvatarLink() string {
 	if setting.DisableGravatar {
 	if setting.DisableGravatar {
 		return "/img/avatar_default.jpg"
 		return "/img/avatar_default.jpg"
 	} else if setting.Service.EnableCacheAvatar {
 	} else if setting.Service.EnableCacheAvatar {
-		return "/avatar/" + user.Avatar
+		return "/avatar/" + u.Avatar
 	}
 	}
-	return "//1.gravatar.com/avatar/" + user.Avatar
+	return "//1.gravatar.com/avatar/" + u.Avatar
 }
 }
 
 
 // NewGitSig generates and returns the signature of given user.
 // NewGitSig generates and returns the signature of given user.
-func (user *User) NewGitSig() *git.Signature {
+func (u *User) NewGitSig() *git.Signature {
 	return &git.Signature{
 	return &git.Signature{
-		Name:  user.Name,
-		Email: user.Email,
+		Name:  u.Name,
+		Email: u.Email,
 		When:  time.Now(),
 		When:  time.Now(),
 	}
 	}
 }
 }
 
 
 // EncodePasswd encodes password to safe format.
 // EncodePasswd encodes password to safe format.
-func (user *User) EncodePasswd() {
-	newPasswd := base.PBKDF2([]byte(user.Passwd), []byte(user.Salt), 10000, 50, sha256.New)
-	user.Passwd = fmt.Sprintf("%x", newPasswd)
+func (u *User) EncodePasswd() {
+	newPasswd := base.PBKDF2([]byte(u.Passwd), []byte(u.Salt), 10000, 50, sha256.New)
+	u.Passwd = fmt.Sprintf("%x", newPasswd)
 }
 }
 
 
-// Member represents user is member of organization.
-type Member struct {
-	Id     int64
-	OrgId  int64 `xorm:"unique(member) index"`
-	UserId int64 `xorm:"unique(member)"`
+func (u *User) IsOrganization() bool {
+	return u.Type == ORGANIZATION
+}
+
+func (u *User) GetOrganizations() error {
+	ous, err := GetOrgUsersByUserId(u.Id)
+	if err != nil {
+		return err
+	}
+
+	u.Orgs = make([]*User, len(ous))
+	for i, ou := range ous {
+		u.Orgs[i], err = GetUserById(ou.OrgId)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// GetOwnerTeam returns owner team of organization.
+func (org *User) GetOwnerTeam() (*Team, error) {
+	t := &Team{
+		OrgId: org.Id,
+		Name:  OWNER_TEAM,
+	}
+	_, err := x.Get(t)
+	return t, err
 }
 }
 
 
 // IsUserExist checks if given user name exist,
 // IsUserExist checks if given user name exist,
@@ -126,49 +157,60 @@ func GetUserSalt() string {
 	return base.GetRandomString(10)
 	return base.GetRandomString(10)
 }
 }
 
 
-// RegisterUser creates record of a new user.
-func RegisterUser(user *User) (*User, error) {
-
-	if !IsLegalName(user.Name) {
+// CreateUser creates record of a new user.
+func CreateUser(u *User) (*User, error) {
+	if !IsLegalName(u.Name) {
 		return nil, ErrUserNameIllegal
 		return nil, ErrUserNameIllegal
 	}
 	}
 
 
-	isExist, err := IsUserExist(user.Name)
+	isExist, err := IsUserExist(u.Name)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	} else if isExist {
 	} else if isExist {
 		return nil, ErrUserAlreadyExist
 		return nil, ErrUserAlreadyExist
 	}
 	}
 
 
-	isExist, err = IsEmailUsed(user.Email)
+	isExist, err = IsEmailUsed(u.Email)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	} else if isExist {
 	} else if isExist {
 		return nil, ErrEmailAlreadyUsed
 		return nil, ErrEmailAlreadyUsed
 	}
 	}
 
 
-	user.LowerName = strings.ToLower(user.Name)
-	user.Avatar = base.EncodeMd5(user.Email)
-	user.AvatarEmail = user.Email
-	user.Rands = GetUserSalt()
-	user.Salt = GetUserSalt()
-	user.EncodePasswd()
-	if _, err = x.Insert(user); err != nil {
+	u.LowerName = strings.ToLower(u.Name)
+	u.Avatar = base.EncodeMd5(u.Email)
+	u.AvatarEmail = u.Email
+	u.Rands = GetUserSalt()
+	u.Salt = GetUserSalt()
+	u.EncodePasswd()
+
+	sess := x.NewSession()
+	defer sess.Close()
+	if err = sess.Begin(); err != nil {
+		return nil, err
+	}
+
+	if _, err = sess.Insert(u); err != nil {
+		sess.Rollback()
 		return nil, err
 		return nil, err
-	} else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil {
-		if _, err := x.Id(user.Id).Delete(&User{}); err != nil {
-			return nil, errors.New(fmt.Sprintf(
-				"both create userpath %s and delete table record faild: %v", user.Name, err))
-		}
+	}
+
+	if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil {
+		sess.Rollback()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if user.Id == 1 {
-		user.IsAdmin = true
-		user.IsActive = true
-		_, err = x.Id(user.Id).UseBool().Update(user)
+	if err = sess.Commit(); err != nil {
+		return nil, err
 	}
 	}
-	return user, err
+
+	// Auto-set admin for user whose ID is 1.
+	if u.Id == 1 {
+		u.IsAdmin = true
+		u.IsActive = true
+		_, err = x.Id(u.Id).UseBool().Update(u)
+	}
+	return u, err
 }
 }
 
 
 // GetUsers returns given number of user objects with offset.
 // GetUsers returns given number of user objects with offset.
@@ -277,51 +319,62 @@ func UpdateUser(u *User) (err error) {
 	if len(u.Website) > 255 {
 	if len(u.Website) > 255 {
 		u.Website = u.Website[:255]
 		u.Website = u.Website[:255]
 	}
 	}
+	if len(u.Description) > 255 {
+		u.Description = u.Description[:255]
+	}
 
 
 	_, err = x.Id(u.Id).AllCols().Update(u)
 	_, err = x.Id(u.Id).AllCols().Update(u)
 	return err
 	return err
 }
 }
 
 
 // DeleteUser completely deletes everything of the user.
 // DeleteUser completely deletes everything of the user.
-func DeleteUser(user *User) error {
+func DeleteUser(u *User) error {
 	// Check ownership of repository.
 	// Check ownership of repository.
-	count, err := GetRepositoryCount(user)
+	count, err := GetRepositoryCount(u)
 	if err != nil {
 	if err != nil {
-		return errors.New("modesl.GetRepositories: " + err.Error())
+		return errors.New("modesl.GetRepositories(GetRepositoryCount): " + err.Error())
 	} else if count > 0 {
 	} else if count > 0 {
 		return ErrUserOwnRepos
 		return ErrUserOwnRepos
 	}
 	}
 
 
+	// Check membership of organization.
+	count, err = GetOrganizationCount(u)
+	if err != nil {
+		return errors.New("modesl.GetRepositories(GetOrganizationCount): " + err.Error())
+	} else if count > 0 {
+		return ErrUserHasOrgs
+	}
+
 	// TODO: check issues, other repos' commits
 	// TODO: check issues, other repos' commits
 
 
 	// Delete all followers.
 	// Delete all followers.
-	if _, err = x.Delete(&Follow{FollowId: user.Id}); err != nil {
+	if _, err = x.Delete(&Follow{FollowId: u.Id}); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Delete oauth2.
 	// Delete oauth2.
-	if _, err = x.Delete(&Oauth2{Uid: user.Id}); err != nil {
+	if _, err = x.Delete(&Oauth2{Uid: u.Id}); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Delete all feeds.
 	// Delete all feeds.
-	if _, err = x.Delete(&Action{UserId: user.Id}); err != nil {
+	if _, err = x.Delete(&Action{UserId: u.Id}); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Delete all watches.
 	// Delete all watches.
-	if _, err = x.Delete(&Watch{UserId: user.Id}); err != nil {
+	if _, err = x.Delete(&Watch{UserId: u.Id}); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Delete all accesses.
 	// Delete all accesses.
-	if _, err = x.Delete(&Access{UserName: user.LowerName}); err != nil {
+	if _, err = x.Delete(&Access{UserName: u.LowerName}); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Delete all SSH keys.
 	// Delete all SSH keys.
 	keys := make([]*PublicKey, 0, 10)
 	keys := make([]*PublicKey, 0, 10)
-	if err = x.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil {
+	if err = x.Find(&keys, &PublicKey{OwnerId: u.Id}); err != nil {
 		return err
 		return err
 	}
 	}
 	for _, key := range keys {
 	for _, key := range keys {
@@ -331,11 +384,11 @@ func DeleteUser(user *User) error {
 	}
 	}
 
 
 	// Delete user directory.
 	// Delete user directory.
-	if err = os.RemoveAll(UserPath(user.Name)); err != nil {
+	if err = os.RemoveAll(UserPath(u.Name)); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	_, err = x.Delete(user)
+	_, err = x.Delete(u)
 	return err
 	return err
 }
 }
 
 

+ 57 - 0
modules/auth/org.go

@@ -0,0 +1,57 @@
+// 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 auth
+
+import (
+	"net/http"
+	"reflect"
+
+	"github.com/go-martini/martini"
+
+	"github.com/gogits/gogs/modules/base"
+	"github.com/gogits/gogs/modules/middleware/binding"
+)
+
+type CreateOrgForm struct {
+	OrgName string `form:"orgname" binding:"Required;AlphaDashDot;MaxSize(30)"`
+	Email   string `form:"email" binding:"Required;Email;MaxSize(50)"`
+}
+
+func (f *CreateOrgForm) Name(field string) string {
+	names := map[string]string{
+		"OrgName": "Organization name",
+		"Email":   "E-mail address",
+	}
+	return names[field]
+}
+
+func (f *CreateOrgForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) {
+	data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
+	validate(errs, data, f)
+}
+
+type OrgSettingForm struct {
+	DisplayName string `form:"display_name" binding:"Required;MaxSize(100)"`
+	Email       string `form:"email" binding:"Required;Email;MaxSize(50)"`
+	Description string `form:"desc" binding:"MaxSize(255)"`
+	Website     string `form:"site" binding:"Url;MaxSize(100)"`
+	Location    string `form:"location" binding:"MaxSize(50)"`
+}
+
+func (f *OrgSettingForm) Name(field string) string {
+	names := map[string]string{
+		"DisplayName": "Display name",
+		"Email":       "E-mail address",
+		"Description": "Description",
+		"Website":     "Website address",
+		"Location":    "Location",
+	}
+	return names[field]
+}
+
+func (f *OrgSettingForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
+	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
+	validate(errors, data, f)
+}

+ 5 - 3
modules/auth/repo.go

@@ -22,9 +22,10 @@ import (
 //         \/     \/|__|              \/                       \/
 //         \/     \/|__|              \/                       \/
 
 
 type CreateRepoForm struct {
 type CreateRepoForm struct {
+	Uid         int64  `form:"uid" binding:"Required"`
 	RepoName    string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"`
 	RepoName    string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"`
 	Private     bool   `form:"private"`
 	Private     bool   `form:"private"`
-	Description string `form:"desc" binding:"MaxSize(100)"`
+	Description string `form:"desc" binding:"MaxSize(255)"`
 	Language    string `form:"language"`
 	Language    string `form:"language"`
 	License     string `form:"license"`
 	License     string `form:"license"`
 	InitReadme  bool   `form:"initReadme"`
 	InitReadme  bool   `form:"initReadme"`
@@ -47,10 +48,11 @@ type MigrateRepoForm struct {
 	Url          string `form:"url" binding:"Url"`
 	Url          string `form:"url" binding:"Url"`
 	AuthUserName string `form:"auth_username"`
 	AuthUserName string `form:"auth_username"`
 	AuthPasswd   string `form:"auth_password"`
 	AuthPasswd   string `form:"auth_password"`
+	Uid          int64  `form:"uid" binding:"Required"`
 	RepoName     string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"`
 	RepoName     string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"`
 	Mirror       bool   `form:"mirror"`
 	Mirror       bool   `form:"mirror"`
 	Private      bool   `form:"private"`
 	Private      bool   `form:"private"`
-	Description  string `form:"desc" binding:"MaxSize(100)"`
+	Description  string `form:"desc" binding:"MaxSize(255)"`
 }
 }
 
 
 func (f *MigrateRepoForm) Name(field string) string {
 func (f *MigrateRepoForm) Name(field string) string {
@@ -69,7 +71,7 @@ func (f *MigrateRepoForm) Validate(errors *binding.Errors, req *http.Request, co
 
 
 type RepoSettingForm struct {
 type RepoSettingForm struct {
 	RepoName    string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"`
 	RepoName    string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"`
-	Description string `form:"desc" binding:"MaxSize(100)"`
+	Description string `form:"desc" binding:"MaxSize(255)"`
 	Website     string `form:"site" binding:"Url;MaxSize(100)"`
 	Website     string `form:"site" binding:"Url;MaxSize(100)"`
 	Branch      string `form:"branch"`
 	Branch      string `form:"branch"`
 	Interval    int    `form:"interval"`
 	Interval    int    `form:"interval"`

+ 16 - 14
modules/auth/user.go

@@ -25,23 +25,25 @@ func SignedInId(header http.Header, sess session.SessionStore) int64 {
 		return 0
 		return 0
 	}
 	}
 
 
-	var id int64
 	if setting.Service.EnableReverseProxyAuth {
 	if setting.Service.EnableReverseProxyAuth {
-		id, _ = base.StrTo(header.Get(setting.ReverseProxyAuthUid)).Int64()
-	}
-
-	if id <= 0 {
-		uid := sess.Get("userId")
-		if uid == nil {
-			return 0
-		}
-		var ok bool
-		if id, ok = uid.(int64); !ok {
-			return 0
+		webAuthUser := header.Get(setting.ReverseProxyAuthUser)
+		if len(webAuthUser) > 0 {
+			u, err := models.GetUserByName(webAuthUser)
+			if err != nil {
+				if err != models.ErrUserNotExist {
+					log.Error("auth.user.SignedInId(GetUserByName): %v", err)
+				}
+				return 0
+			}
+			return u.Id
 		}
 		}
 	}
 	}
 
 
-	if id > 0 {
+	uid := sess.Get("userId")
+	if uid == nil {
+		return 0
+	}
+	if id, ok := uid.(int64); ok {
 		if _, err := models.GetUserById(id); err != nil {
 		if _, err := models.GetUserById(id); err != nil {
 			if err != models.ErrUserNotExist {
 			if err != models.ErrUserNotExist {
 				log.Error("auth.user.SignedInId(GetUserById): %v", err)
 				log.Error("auth.user.SignedInId(GetUserById): %v", err)
@@ -91,7 +93,7 @@ func (f *UpdateProfileForm) Name(field string) string {
 	names := map[string]string{
 	names := map[string]string{
 		"UserName": "Username",
 		"UserName": "Username",
 		"Email":    "E-mail address",
 		"Email":    "E-mail address",
-		"Website":  "Website",
+		"Website":  "Website address",
 		"Location": "Location",
 		"Location": "Location",
 		"Avatar":   "Gravatar Email",
 		"Avatar":   "Gravatar Email",
 	}
 	}

+ 1 - 0
modules/base/base.go

@@ -7,6 +7,7 @@ package base
 type (
 type (
 	// Type TmplData represents data in the templates.
 	// Type TmplData represents data in the templates.
 	TmplData map[string]interface{}
 	TmplData map[string]interface{}
+	TplName  string
 
 
 	ApiJsonErr struct {
 	ApiJsonErr struct {
 		Message string `json:"message"`
 		Message string `json:"message"`

+ 235 - 236
modules/bin/conf.go

@@ -28,242 +28,241 @@ func bindata_read(data []byte, name string) ([]byte, error) {
 func conf_app_ini() ([]byte, error) {
 func conf_app_ini() ([]byte, error) {
 	return bindata_read([]byte{
 	return bindata_read([]byte{
 		0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0xb4, 0x59,
 		0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0xb4, 0x59,
-		0xdd, 0x72, 0xdb, 0xc8, 0xb1, 0xbe, 0xc7, 0x53, 0x8c, 0x79, 0x76, 0xcf,
-		0xda, 0xa7, 0x24, 0x92, 0x92, 0x8f, 0x65, 0xaf, 0xbc, 0xae, 0x63, 0x8a,
-		0x04, 0x25, 0x1c, 0xf3, 0x47, 0x0b, 0x40, 0xf2, 0x2a, 0x2e, 0x15, 0x0a,
-		0x02, 0x86, 0xe4, 0x44, 0x00, 0x06, 0xc2, 0x0c, 0x45, 0x31, 0x77, 0x79,
-		0x85, 0x54, 0x9e, 0x26, 0xcf, 0x93, 0x8b, 0x3c, 0x46, 0xbe, 0x1e, 0x00,
-		0x14, 0x28, 0x73, 0xb5, 0xce, 0x5f, 0x25, 0x65, 0x11, 0xf3, 0xd3, 0xd3,
-		0xdd, 0xf3, 0xf5, 0xd7, 0xdd, 0xb3, 0xef, 0x59, 0x2f, 0xcf, 0x59, 0x16,
-		0xa6, 0x9c, 0xe9, 0x45, 0xa8, 0x99, 0x5a, 0xc8, 0x95, 0x62, 0x32, 0x63,
-		0xfc, 0x9e, 0x17, 0x6b, 0x96, 0x87, 0x73, 0x4c, 0x08, 0x9d, 0x70, 0xab,
-		0x77, 0x7e, 0x1e, 0x4c, 0x7a, 0x63, 0x9b, 0x7d, 0x60, 0xa7, 0x72, 0xae,
-		0x8e, 0xf1, 0x2f, 0x3b, 0x15, 0x9a, 0x79, 0xbc, 0xb8, 0x17, 0x51, 0x39,
-		0x3f, 0x9a, 0x9e, 0x4e, 0x31, 0x2f, 0xd2, 0x79, 0x67, 0x16, 0x62, 0x54,
-		0x66, 0xed, 0x3c, 0x9b, 0x5b, 0xef, 0x59, 0x7f, 0x11, 0x66, 0x90, 0x84,
-		0xe5, 0x62, 0xc6, 0xd6, 0x72, 0xc9, 0x8a, 0x65, 0xc6, 0x12, 0x19, 0x85,
-		0x49, 0xb2, 0xb6, 0xdc, 0x8b, 0x49, 0x70, 0xe1, 0xd9, 0x2e, 0x76, 0xce,
-		0x85, 0xc6, 0x6a, 0x5b, 0xe8, 0x05, 0x2f, 0x58, 0x2b, 0xe6, 0xf7, 0xad,
-		0x3d, 0xd6, 0xca, 0x0b, 0x19, 0xb7, 0x98, 0xc4, 0x80, 0xe6, 0x4a, 0x63,
-		0x24, 0xe6, 0xb3, 0x70, 0x99, 0x40, 0x96, 0x2a, 0xd7, 0x18, 0x09, 0xe3,
-		0xe9, 0x80, 0x74, 0xc3, 0xb7, 0x65, 0x7d, 0x29, 0x78, 0x2e, 0x95, 0xd0,
-		0xb2, 0x58, 0x5f, 0x5b, 0xee, 0x74, 0xea, 0x63, 0xc2, 0xf2, 0xfa, 0xae,
-		0x73, 0xee, 0x07, 0xfe, 0xd5, 0x39, 0xad, 0xbb, 0x09, 0xd5, 0x02, 0x0b,
-		0x15, 0xb4, 0xe7, 0xc5, 0xb5, 0x75, 0xee, 0x4e, 0xfd, 0x69, 0x7f, 0x3a,
-		0xc2, 0xcc, 0x42, 0xeb, 0xdc, 0x1a, 0x4c, 0xc7, 0x3d, 0x67, 0x82, 0x2f,
-		0xa3, 0xe4, 0x42, 0x2a, 0x6d, 0xe4, 0x04, 0x17, 0x2e, 0x2d, 0xf9, 0xfe,
-		0x65, 0xbd, 0xfe, 0x95, 0x3a, 0xee, 0x74, 0xbe, 0x7f, 0x59, 0x2e, 0xc7,
-		0xc7, 0xf7, 0x2f, 0xcf, 0x7c, 0xff, 0x3c, 0x38, 0x9f, 0xba, 0xfe, 0x2b,
-		0xd5, 0xb1, 0xcc, 0x47, 0x6f, 0x30, 0x20, 0xdb, 0xac, 0xcd, 0x0c, 0x3e,
-		0x5e, 0x77, 0xbb, 0x5d, 0xcb, 0xf3, 0xce, 0xea, 0xef, 0xc3, 0x43, 0xd8,
-		0x3d, 0x10, 0x2a, 0xbc, 0x49, 0x38, 0xeb, 0x0f, 0x26, 0xe4, 0xff, 0x8c,
-		0x89, 0xac, 0xb6, 0x3e, 0x95, 0x31, 0xb7, 0xa6, 0xc3, 0xe1, 0xc8, 0x99,
-		0xd8, 0xb5, 0xa9, 0xb3, 0x30, 0x51, 0xdc, 0x1a, 0x38, 0x5e, 0xef, 0x64,
-		0x64, 0x07, 0xee, 0xf4, 0xc2, 0xb7, 0x5d, 0xba, 0x82, 0xcd, 0xd4, 0x7b,
-		0x76, 0xca, 0x33, 0x5e, 0x84, 0x9a, 0x33, 0xa5, 0x79, 0xae, 0x8e, 0x31,
-		0xf2, 0x1d, 0x8b, 0x62, 0x5c, 0xab, 0x5e, 0x74, 0xb4, 0xec, 0xcc, 0x71,
-		0x91, 0x9d, 0x68, 0xa9, 0xb4, 0x4c, 0x3b, 0x64, 0xb6, 0x32, 0x0b, 0xe6,
-		0xd2, 0x5c, 0xcf, 0x77, 0xa7, 0x53, 0x32, 0xb9, 0xa3, 0x8a, 0xa8, 0x93,
-		0xdf, 0xce, 0x3b, 0x51, 0xb1, 0xce, 0xb1, 0x47, 0x27, 0xaa, 0x33, 0xaf,
-		0xc4, 0x06, 0x11, 0x2f, 0x74, 0x1b, 0xeb, 0xf7, 0xa3, 0xf0, 0x83, 0x2e,
-		0x96, 0x9c, 0xed, 0xc7, 0x4b, 0x4c, 0x08, 0x99, 0x7d, 0x78, 0xf7, 0xf6,
-		0xa8, 0xbb, 0xe8, 0xa6, 0x5d, 0xc5, 0xf6, 0xc9, 0x7d, 0x1f, 0xd2, 0x35,
-		0xfd, 0x69, 0xf3, 0x87, 0x30, 0xcd, 0x13, 0xde, 0x8e, 0x64, 0x6a, 0xf5,
-		0x6d, 0xd7, 0x0f, 0x86, 0xce, 0x88, 0x8c, 0x69, 0x6a, 0xd1, 0x31, 0x62,
-		0x73, 0x9e, 0x5a, 0x9f, 0xec, 0xab, 0x9d, 0x0b, 0x6e, 0xf9, 0xda, 0xcc,
-		0xbf, 0x67, 0x17, 0x79, 0x0e, 0xa8, 0x24, 0x70, 0x57, 0xc2, 0xe4, 0x8c,
-		0x69, 0x0e, 0xe9, 0x64, 0x70, 0x98, 0xc5, 0x30, 0x1a, 0xaa, 0x44, 0x6c,
-		0x26, 0xe0, 0x53, 0x32, 0x19, 0xcb, 0x1b, 0xd0, 0x01, 0xc6, 0xcc, 0x28,
-		0x5b, 0x01, 0x6c, 0xdc, 0x80, 0x9a, 0x86, 0xf9, 0x03, 0x8f, 0x96, 0x9a,
-		0xc7, 0x96, 0xe7, 0xf7, 0x7c, 0xa7, 0x1f, 0x98, 0x6b, 0x3f, 0xef, 0xf9,
-		0x67, 0x74, 0x85, 0xd6, 0x97, 0x38, 0xd4, 0x21, 0xb0, 0xc3, 0xaf, 0x1b,
-		0x38, 0x4d, 0xd7, 0xea, 0x2e, 0x31, 0x48, 0x85, 0x85, 0xf3, 0x82, 0xab,
-		0x12, 0xad, 0x18, 0x14, 0x9a, 0xbf, 0xc6, 0x84, 0xd0, 0x3f, 0x28, 0x82,
-		0x7d, 0xc1, 0xa2, 0x85, 0xa4, 0x60, 0x19, 0x9c, 0xd4, 0x38, 0x34, 0x7b,
-		0xad, 0xb3, 0xa9, 0x47, 0x28, 0x38, 0x38, 0x7c, 0xdb, 0xee, 0xe2, 0x7f,
-		0x07, 0xc7, 0xaf, 0x5f, 0x77, 0x8f, 0xac, 0x2a, 0xdc, 0xe8, 0x96, 0xac,
-		0x2a, 0x40, 0x0a, 0x29, 0xb5, 0x75, 0xde, 0xf3, 0xbc, 0xcf, 0x03, 0xf6,
-		0x01, 0x2a, 0x0c, 0xe9, 0xa0, 0xc6, 0xb1, 0x59, 0xb2, 0xde, 0x63, 0xbc,
-		0x8e, 0x9f, 0x12, 0x4f, 0xa4, 0x59, 0xc1, 0xef, 0x96, 0xa2, 0xe0, 0xa5,
-		0x62, 0x40, 0xbc, 0x98, 0xad, 0xf7, 0x67, 0xcb, 0x24, 0x69, 0x01, 0x84,
-		0xa3, 0x4d, 0xec, 0x94, 0xeb, 0x6b, 0xb1, 0xb5, 0xfe, 0x46, 0xaa, 0x55,
-		0xb9, 0x80, 0xec, 0x37, 0xb8, 0x69, 0xc7, 0x37, 0x70, 0x47, 0x18, 0xa7,
-		0x22, 0xbb, 0x36, 0x81, 0x14, 0x2d, 0x0b, 0xa1, 0x11, 0x6f, 0xce, 0x04,
-		0x9e, 0x1b, 0x8d, 0x80, 0xc4, 0xfe, 0xa7, 0x06, 0x14, 0x5f, 0xbc, 0xe8,
-		0x9f, 0xf5, 0x26, 0xa7, 0x36, 0xf3, 0xcf, 0x1c, 0x8f, 0xf9, 0x53, 0xf6,
-		0xc9, 0xb6, 0xcf, 0xd9, 0xd5, 0xf4, 0xc2, 0x65, 0xc6, 0xb6, 0x41, 0xcf,
-		0xef, 0x31, 0xaf, 0x37, 0xb4, 0x5f, 0xbc, 0xb0, 0x3c, 0xbb, 0xef, 0xda,
-		0x7e, 0x80, 0xdb, 0x87, 0x80, 0x17, 0xff, 0xf5, 0x71, 0x38, 0xb0, 0x3f,
-		0xbb, 0xf8, 0xff, 0x7f, 0xff, 0xcf, 0x4b, 0x48, 0xea, 0x2d, 0xb5, 0xdc,
-		0x4f, 0xe4, 0x1c, 0xd1, 0x51, 0xf0, 0x94, 0xa7, 0x37, 0xb0, 0x35, 0x0e,
-		0xd7, 0xca, 0x02, 0xf6, 0x9d, 0x49, 0xe0, 0xda, 0x63, 0x7b, 0x7c, 0x82,
-		0x50, 0x18, 0xf4, 0xae, 0x3c, 0xec, 0x7f, 0x6b, 0xf5, 0xa7, 0xd3, 0x4f,
-		0x8e, 0x6d, 0x38, 0xa6, 0xe1, 0xd2, 0x20, 0x5c, 0x71, 0x25, 0x53, 0x5e,
-		0x4f, 0x6f, 0xf6, 0x35, 0xd7, 0x88, 0x2c, 0x2a, 0x78, 0x2c, 0x4a, 0xaf,
-		0xb8, 0x44, 0x8a, 0x0a, 0xa8, 0x29, 0xe4, 0xc3, 0x9a, 0x85, 0x4b, 0x78,
-		0x39, 0x03, 0xc0, 0x0c, 0xde, 0xd9, 0x82, 0x87, 0x31, 0x14, 0x31, 0x54,
-		0x0a, 0x20, 0x2e, 0xc1, 0x2c, 0xcc, 0x19, 0x58, 0xae, 0x7d, 0x69, 0xbb,
-		0x9e, 0x1d, 0x80, 0x30, 0x7e, 0xb9, 0x0a, 0x7a, 0x17, 0xfe, 0x99, 0x3d,
-		0x01, 0xac, 0x00, 0xad, 0x29, 0x58, 0xcf, 0xc1, 0x2d, 0xb2, 0x5f, 0xf6,
-		0x3f, 0xdb, 0x27, 0x34, 0xb3, 0x8f, 0xef, 0x8a, 0x93, 0x00, 0x92, 0x6b,
-		0xab, 0xd7, 0xf7, 0x9d, 0x4b, 0x3b, 0xe8, 0xe3, 0x76, 0x82, 0x11, 0xfd,
-		0x1a, 0x3b, 0x13, 0x04, 0x39, 0x19, 0x75, 0xf0, 0xae, 0x0b, 0xd1, 0x9e,
-		0x4d, 0xd0, 0x24, 0x30, 0xfc, 0xea, 0x22, 0x44, 0x08, 0x69, 0x92, 0x71,
-		0x1e, 0x33, 0x2d, 0x19, 0x28, 0x79, 0x26, 0x8a, 0x94, 0xf1, 0xfd, 0x34,
-		0x14, 0x09, 0x9b, 0xe1, 0x9e, 0x0b, 0x3e, 0x17, 0x4a, 0x97, 0x51, 0x0b,
-		0x99, 0xa7, 0x8e, 0x47, 0x3c, 0x62, 0x83, 0xd0, 0x46, 0x90, 0x3a, 0x19,
-		0x3a, 0xee, 0xb8, 0x71, 0x8d, 0x03, 0xc9, 0x15, 0xcb, 0xa4, 0x66, 0xa0,
-		0x6e, 0xb9, 0xaa, 0x36, 0xe3, 0x00, 0x8a, 0x37, 0x03, 0x06, 0x06, 0x87,
-		0x99, 0x00, 0x8c, 0x22, 0xb9, 0xcc, 0x74, 0x09, 0x9e, 0x0d, 0x49, 0x19,
-		0xf1, 0xae, 0xb1, 0xbe, 0x21, 0xd4, 0xa8, 0x98, 0x22, 0xc0, 0x99, 0x12,
-		0x73, 0x43, 0x7b, 0x50, 0xf5, 0x5e, 0xf0, 0x15, 0xc4, 0xae, 0xf5, 0x42,
-		0x64, 0xf3, 0x36, 0x34, 0xfb, 0xf9, 0xc2, 0x71, 0xed, 0xc0, 0x73, 0x4e,
-		0x27, 0xb8, 0xe5, 0x4b, 0xc7, 0xfe, 0xdc, 0x90, 0xd0, 0x0f, 0x23, 0x84,
-		0x73, 0x78, 0x0f, 0x74, 0x42, 0x17, 0xc5, 0x72, 0x11, 0xe9, 0x65, 0xc1,
-		0x2d, 0x7b, 0x62, 0xce, 0xed, 0xf7, 0xfa, 0x67, 0x76, 0xd0, 0xbb, 0x04,
-		0xc6, 0xdc, 0xc6, 0xae, 0x31, 0xf9, 0x00, 0xc6, 0x88, 0x59, 0x75, 0x8b,
-		0xf5, 0xfa, 0xc9, 0xd4, 0x77, 0x86, 0x57, 0x01, 0xf9, 0xa0, 0xb9, 0x5c,
-		0x82, 0x27, 0x62, 0xae, 0xb1, 0xeb, 0xd8, 0xa4, 0x09, 0x22, 0x7f, 0xa4,
-		0xac, 0xc5, 0xf2, 0x86, 0xf8, 0x8c, 0xc2, 0x42, 0x68, 0x55, 0xb2, 0xaa,
-		0x50, 0x6a, 0xc9, 0x55, 0xe7, 0xe0, 0xe8, 0x4d, 0x2d, 0xf3, 0x39, 0x24,
-		0x6c, 0x0e, 0xb1, 0xbe, 0xac, 0xf8, 0xcd, 0x42, 0xca, 0x5b, 0xe2, 0x97,
-		0x7e, 0x01, 0x5c, 0xe9, 0x50, 0xdd, 0xc2, 0x23, 0xf0, 0xf1, 0x7d, 0x98,
-		0x90, 0x6b, 0xe0, 0x63, 0xf0, 0x93, 0xb2, 0xfc, 0x9e, 0xf7, 0x29, 0x70,
-		0x26, 0xb8, 0xac, 0xcb, 0x1e, 0x69, 0x79, 0x40, 0xb7, 0xc3, 0x13, 0x01,
-		0x8c, 0x22, 0x65, 0xa7, 0x5c, 0x2e, 0x35, 0x2d, 0x47, 0x60, 0xca, 0x2c,
-		0x56, 0xd6, 0xc0, 0x26, 0x74, 0xb8, 0x81, 0xef, 0x8c, 0x6d, 0xa4, 0x0a,
-		0x6c, 0x78, 0x83, 0xd3, 0x08, 0x05, 0x94, 0xff, 0x4a, 0x1d, 0x07, 0x0d,
-		0x63, 0x4f, 0x96, 0xb3, 0x99, 0x61, 0xd6, 0x6c, 0x0e, 0x8e, 0x04, 0xa2,
-		0x23, 0xe4, 0xf0, 0x8c, 0x27, 0x7b, 0xec, 0x96, 0xf3, 0x9c, 0x52, 0x39,
-		0xdc, 0x2c, 0x0c, 0x93, 0x56, 0x39, 0x3d, 0x96, 0xd9, 0x0f, 0x9a, 0xdd,
-		0x66, 0x80, 0xc5, 0x8a, 0x6a, 0x09, 0x33, 0xd9, 0x46, 0x30, 0x4f, 0x06,
-		0xc1, 0xc9, 0xc5, 0x70, 0x48, 0xd9, 0xc9, 0x26, 0x53, 0x0f, 0x08, 0x96,
-		0x13, 0x0a, 0x14, 0x30, 0x0e, 0xe8, 0x7a, 0x0d, 0x6c, 0x92, 0x61, 0x74,
-		0x1b, 0x65, 0xb1, 0xe1, 0x5d, 0x9c, 0xfc, 0xbf, 0xdd, 0xf7, 0x4d, 0xaa,
-		0xad, 0x0b, 0x8f, 0x57, 0xaa, 0xbe, 0xb1, 0x32, 0x69, 0x53, 0x7a, 0x4b,
-		0xcd, 0x55, 0xa8, 0x54, 0xe7, 0xed, 0x39, 0xfd, 0xa6, 0x6b, 0x38, 0x7e,
-		0xf3, 0xee, 0x2d, 0xe6, 0x7e, 0xfe, 0xb9, 0x9a, 0xb8, 0xbb, 0x33, 0xa3,
-		0x87, 0x6f, 0x6a, 0x96, 0xad, 0xc5, 0xcc, 0x0a, 0x99, 0x02, 0xb3, 0x31,
-		0x98, 0x53, 0x59, 0x43, 0x77, 0x3a, 0x7e, 0x9c, 0x83, 0xe1, 0x26, 0x80,
-		0x4d, 0x34, 0x13, 0xb4, 0xf3, 0x50, 0xa9, 0x95, 0x2c, 0xe2, 0x9a, 0x87,
-		0x37, 0x1c, 0x4c, 0x39, 0x41, 0x12, 0x15, 0x7c, 0xed, 0xc3, 0x6a, 0xa2,
-		0x5d, 0x22, 0xe4, 0xeb, 0xf9, 0xfe, 0xc8, 0x01, 0x02, 0x02, 0xc3, 0x01,
-		0xf5, 0x47, 0xc9, 0x7c, 0x65, 0xb9, 0x32, 0x3d, 0x37, 0x51, 0x5c, 0x03,
-		0x2d, 0xcc, 0x45, 0xbb, 0x01, 0x36, 0xd2, 0xcf, 0x22, 0x14, 0x55, 0x35,
-		0xc9, 0x0e, 0x3c, 0x1a, 0x8e, 0xec, 0x18, 0x25, 0x3a, 0xf4, 0x8f, 0x2c,
-		0xc4, 0x1f, 0xb8, 0xe5, 0x4f, 0x3f, 0xd9, 0x93, 0x6f, 0xdc, 0x14, 0x45,
-		0xf0, 0x4d, 0xa0, 0xe5, 0x2d, 0xcf, 0x2c, 0x53, 0x4e, 0x68, 0x16, 0x25,
-		0x02, 0xac, 0xc7, 0x44, 0x5c, 0xa6, 0x58, 0x8e, 0x70, 0xd7, 0xc6, 0x95,
-		0x98, 0xaf, 0xc5, 0x01, 0x71, 0x4a, 0x22, 0xc9, 0xc7, 0x94, 0x96, 0x25,
-		0x12, 0xb4, 0x42, 0x91, 0x20, 0xe7, 0x65, 0xda, 0xef, 0x80, 0x3e, 0x7f,
-		0xcf, 0x23, 0xbd, 0x71, 0x8f, 0x99, 0xf9, 0x97, 0xdd, 0xb3, 0x5a, 0xad,
-		0x2a, 0x51, 0x70, 0x94, 0x32, 0x07, 0x19, 0x1b, 0xc8, 0x4f, 0x22, 0x9b,
-		0xc9, 0x36, 0x37, 0xf8, 0xfa, 0xe6, 0xe5, 0xd0, 0x92, 0x0a, 0x87, 0x5d,
-		0x2e, 0xae, 0xa8, 0x6d, 0xcb, 0x28, 0x59, 0xba, 0xec, 0xd0, 0x48, 0xd9,
-		0xe9, 0xe3, 0x67, 0x77, 0x55, 0x2e, 0xae, 0x5c, 0x72, 0x77, 0xf7, 0x4f,
-		0xbb, 0x03, 0xb4, 0x6c, 0xc0, 0xcf, 0xfe, 0xfa, 0x97, 0x3f, 0xfd, 0xed,
-		0x8f, 0x7f, 0xa6, 0x74, 0xb9, 0x03, 0x23, 0x45, 0x98, 0x2f, 0xaa, 0xc0,
-		0xa8, 0x34, 0x68, 0x77, 0x1b, 0x10, 0x79, 0xcf, 0x76, 0x82, 0x64, 0xe7,
-		0xae, 0x52, 0x73, 0xec, 0xe0, 0x59, 0x44, 0xc0, 0x58, 0x71, 0x71, 0x23,
-		0x77, 0x79, 0x0d, 0x38, 0xc8, 0xda, 0xba, 0xde, 0x1f, 0xcd, 0xc5, 0xfe,
-		0x4d, 0x0d, 0xb4, 0xc3, 0xdf, 0x80, 0xe7, 0xf3, 0x5b, 0xb7, 0x40, 0x5a,
-		0x79, 0x50, 0xaf, 0x84, 0xd6, 0xbb, 0x88, 0xed, 0x1f, 0x70, 0xe3, 0xae,
-		0x9b, 0x47, 0x0c, 0x56, 0xa2, 0x1f, 0xbd, 0xf0, 0x1b, 0xca, 0xff, 0xca,
-		0x9e, 0x5d, 0x5a, 0x1b, 0xdf, 0xfd, 0x27, 0x74, 0x36, 0x82, 0x1b, 0xf7,
-		0xf6, 0x0d, 0x2a, 0x7f, 0xbd, 0x65, 0x5b, 0xe3, 0x88, 0x32, 0xee, 0x56,
-		0x15, 0xcc, 0x53, 0xf4, 0x5b, 0x65, 0xb1, 0x09, 0x5e, 0xc7, 0x0f, 0x59,
-		0x8e, 0x9a, 0x95, 0x4f, 0xda, 0xb6, 0x6a, 0xb1, 0xd5, 0x1b, 0xf4, 0xce,
-		0x7d, 0xc3, 0xa8, 0xe5, 0x48, 0x5d, 0x7b, 0x56, 0xf3, 0x55, 0x41, 0x7b,
-		0xda, 0xdf, 0xca, 0x80, 0x55, 0x4a, 0xdb, 0x92, 0x78, 0xd4, 0xb5, 0x1a,
-		0xb9, 0xf0, 0xa8, 0x5b, 0x0b, 0x2a, 0x75, 0x31, 0x5c, 0xd5, 0xd4, 0x05,
-		0x02, 0x32, 0x70, 0x90, 0x29, 0xdc, 0x50, 0x3d, 0x6f, 0xd2, 0xc0, 0x7b,
-		0x66, 0x36, 0x1c, 0xb3, 0xd6, 0xf1, 0x51, 0xf7, 0xf5, 0x8f, 0x2d, 0x0c,
-		0xd4, 0xbb, 0x30, 0xf6, 0x58, 0x9f, 0x1f, 0x1c, 0x1c, 0x1e, 0x1c, 0xb4,
-		0xaa, 0x8c, 0x62, 0x6a, 0x36, 0xa5, 0x20, 0x6c, 0xb7, 0x3f, 0x88, 0x47,
-		0x1e, 0xfd, 0x52, 0xba, 0xa5, 0x6a, 0x19, 0x76, 0xf9, 0x04, 0x05, 0xc2,
-		0xa5, 0x33, 0x30, 0x4e, 0x31, 0x0c, 0xf4, 0x9e, 0x9d, 0x17, 0xf2, 0x5e,
-		0x50, 0x75, 0x69, 0xca, 0xb7, 0x39, 0x93, 0x39, 0x69, 0xae, 0x4a, 0xe5,
-		0xb0, 0xe7, 0xd8, 0x54, 0x64, 0x8b, 0xf0, 0x9e, 0x92, 0xd5, 0xba, 0x5e,
-		0xb5, 0xe6, 0xd4, 0x4c, 0x93, 0x08, 0x64, 0xc2, 0x52, 0xbf, 0xc7, 0x5e,
-		0x08, 0x5d, 0x42, 0x7b, 0xde, 0x46, 0x8f, 0x40, 0xf5, 0x7c, 0x35, 0xab,
-		0x5a, 0x8f, 0xf6, 0x57, 0x32, 0x12, 0x71, 0xcb, 0xcb, 0xa1, 0x2a, 0xeb,
-		0x1a, 0x4f, 0xed, 0xb1, 0x5c, 0xca, 0xc4, 0x03, 0x7c, 0xf6, 0x36, 0x99,
-		0xb1, 0x16, 0xf8, 0xe8, 0xa3, 0xa3, 0xd7, 0x6f, 0x7f, 0xdc, 0x3b, 0xe8,
-		0x76, 0xf7, 0x42, 0x34, 0x62, 0x0f, 0x82, 0x1b, 0x67, 0x92, 0xdd, 0xc7,
-		0xa8, 0xad, 0xf7, 0xf1, 0x77, 0x3f, 0x2e, 0xa8, 0x5a, 0xe9, 0x98, 0x41,
-		0x16, 0xab, 0xac, 0x3e, 0x15, 0xe5, 0x28, 0x6a, 0xbe, 0x5a, 0x22, 0xf5,
-		0x3c, 0xc7, 0xf5, 0x31, 0x1f, 0x6b, 0x65, 0x03, 0x6d, 0x7a, 0x9b, 0x8d,
-		0xb7, 0xca, 0x5a, 0xf5, 0xb4, 0x6e, 0x51, 0x6a, 0x93, 0x70, 0xa6, 0x57,
-		0xd9, 0x1e, 0xa1, 0xac, 0x12, 0xdc, 0xe4, 0xf4, 0xba, 0xe6, 0xaf, 0x4a,
-		0x7d, 0x11, 0x90, 0x9d, 0x41, 0x59, 0xbf, 0x61, 0x87, 0x53, 0x16, 0x34,
-		0xc8, 0x05, 0x1b, 0xc7, 0x01, 0x76, 0x26, 0x3a, 0x2a, 0x44, 0x36, 0xee,
-		0xad, 0x8a, 0xd1, 0x52, 0x20, 0xc2, 0xf2, 0xc2, 0xb5, 0x1b, 0x65, 0x94,
-		0x9d, 0x99, 0x96, 0x5e, 0x51, 0xe6, 0x34, 0xe7, 0x6f, 0xed, 0xa5, 0x9e,
-		0xb9, 0xae, 0x0f, 0xa9, 0x98, 0x2f, 0xa5, 0x60, 0xbb, 0x99, 0x78, 0x54,
-		0x1d, 0x01, 0x40, 0x25, 0xdd, 0x26, 0x0a, 0xb6, 0x84, 0xbc, 0x3b, 0xfa,
-		0xdf, 0x6e, 0xd7, 0x3a, 0xed, 0x6f, 0x8a, 0x41, 0x53, 0xe3, 0x41, 0x48,
-		0x39, 0xf1, 0x28, 0x25, 0x11, 0x33, 0x6e, 0xe4, 0xec, 0xd8, 0xee, 0xd9,
-		0x9e, 0x47, 0x2d, 0xc9, 0xc8, 0x19, 0xda, 0x4f, 0xf7, 0x6f, 0x7c, 0x10,
-		0x03, 0x63, 0x6a, 0xc1, 0x66, 0xcb, 0x2c, 0xda, 0xdb, 0xe0, 0x5c, 0x2d,
-		0xc2, 0x03, 0x42, 0x37, 0xfe, 0x1e, 0xbe, 0x39, 0xaa, 0xe0, 0x1d, 0xbf,
-		0x69, 0x35, 0xcf, 0xa0, 0x35, 0x9b, 0x23, 0x9c, 0x41, 0x70, 0xd6, 0xf3,
-		0xce, 0x86, 0x17, 0x93, 0x3e, 0x0e, 0x31, 0x53, 0x8f, 0x3a, 0x9a, 0x03,
-		0xd0, 0xde, 0x6f, 0xa9, 0x48, 0x17, 0x51, 0x20, 0x84, 0x51, 0xaf, 0x95,
-		0xd0, 0x78, 0x2a, 0xcb, 0x74, 0x8a, 0x08, 0xc3, 0xaa, 0xec, 0xa7, 0x30,
-		0xf4, 0xa9, 0xbd, 0x4f, 0xc2, 0x88, 0x53, 0x2f, 0x51, 0x8d, 0x1b, 0x68,
-		0x3c, 0xf6, 0xc7, 0x25, 0xa2, 0x4b, 0x8d, 0xef, 0x44, 0x26, 0x96, 0x4f,
-		0x02, 0xb2, 0x9a, 0xc7, 0x61, 0xee, 0xa5, 0xd3, 0x27, 0x8f, 0x54, 0x95,
-		0x67, 0xdd, 0xce, 0x9c, 0xba, 0x4f, 0x5a, 0x0a, 0xeb, 0x0b, 0xca, 0xa7,
-		0xf2, 0xc9, 0xa9, 0x7a, 0x33, 0x68, 0x10, 0x42, 0x55, 0x15, 0x35, 0x19,
-		0x81, 0x68, 0xc8, 0xf8, 0x0e, 0x85, 0x6a, 0xa9, 0x47, 0xfd, 0xbe, 0xf0,
-		0x44, 0x95, 0x7a, 0x6f, 0xd9, 0x2c, 0x01, 0x4a, 0x69, 0x1a, 0x92, 0x61,
-		0x8a, 0xe7, 0xa1, 0x79, 0xe0, 0x49, 0xb1, 0x52, 0xe4, 0x40, 0x1a, 0xbd,
-		0x14, 0xa9, 0x3a, 0x74, 0xaa, 0x6d, 0x7b, 0x26, 0xee, 0x5b, 0x56, 0xd5,
-		0xe7, 0x57, 0xa3, 0xff, 0xce, 0x22, 0xff, 0x49, 0x7d, 0xdf, 0x35, 0xb8,
-		0xa9, 0x0d, 0xf7, 0x0b, 0x5c, 0x03, 0x99, 0x39, 0xe0, 0x37, 0xcb, 0x39,
-		0xfd, 0x70, 0x50, 0x61, 0xd1, 0xdf, 0xcf, 0x61, 0x61, 0xec, 0xb7, 0x8b,
-		0x42, 0x16, 0xf4, 0xa3, 0x5f, 0x08, 0xea, 0xa8, 0x9f, 0x52, 0x63, 0x29,
-		0xc1, 0x1a, 0xa1, 0x85, 0x22, 0x7a, 0x37, 0x9f, 0x56, 0x4d, 0xf1, 0xb5,
-		0x6f, 0x8c, 0xe9, 0x65, 0xbf, 0x49, 0xd7, 0xd0, 0xae, 0xc6, 0xaf, 0x37,
-		0xdb, 0x36, 0x3b, 0x8c, 0x37, 0x9e, 0x2e, 0xa7, 0xc1, 0xc6, 0x5a, 0x7a,
-		0x76, 0xaa, 0xf9, 0x01, 0xd3, 0xe5, 0x9b, 0x07, 0x7e, 0x18, 0x68, 0xd1,
-		0x3b, 0x91, 0x09, 0x6c, 0x45, 0xcf, 0x00, 0x32, 0xc5, 0x0d, 0xc4, 0xb4,
-		0x8a, 0x15, 0x52, 0xe3, 0xf7, 0x4b, 0x85, 0x7c, 0x1f, 0x19, 0x87, 0xce,
-		0x24, 0xf5, 0xc9, 0x80, 0x6c, 0x4d, 0xda, 0xaf, 0xbe, 0x26, 0x80, 0xd1,
-		0xf4, 0x34, 0x70, 0xa7, 0x7e, 0xcf, 0x6f, 0x44, 0xfe, 0x38, 0x7c, 0x40,
-		0xbc, 0x66, 0xa0, 0xab, 0xa5, 0x79, 0xe0, 0x80, 0x28, 0x05, 0x29, 0xb8,
-		0x60, 0xd2, 0x73, 0x4b, 0x86, 0x71, 0x37, 0x1c, 0x3e, 0xee, 0xfd, 0x12,
-		0xd0, 0xfb, 0xa0, 0x57, 0x5f, 0x81, 0xb9, 0x04, 0x12, 0xa4, 0xc0, 0xd4,
-		0x08, 0x34, 0x31, 0xd3, 0xcf, 0xc9, 0x39, 0x7c, 0x87, 0x74, 0x12, 0x66,
-		0x10, 0xc8, 0x7e, 0xfa, 0x09, 0x5f, 0x7b, 0x0c, 0xf1, 0x3c, 0x3e, 0x31,
-		0x72, 0x3d, 0xe7, 0x77, 0x60, 0xa8, 0x33, 0x67, 0x68, 0x1e, 0x2b, 0xdf,
-		0x99, 0x80, 0x9d, 0xa7, 0x54, 0xef, 0x91, 0xd5, 0x31, 0x2a, 0xeb, 0xf5,
-		0xd7, 0x76, 0x0d, 0xd0, 0x3e, 0x5f, 0x7d, 0x65, 0x99, 0xfd, 0x90, 0x0b,
-		0x64, 0x14, 0xf3, 0x64, 0x43, 0xea, 0x90, 0x00, 0xd2, 0xe5, 0x65, 0xcc,
-		0x13, 0x4e, 0x0f, 0x07, 0x33, 0x7a, 0x4f, 0x48, 0xa1, 0x36, 0xad, 0xd8,
-		0x76, 0xd7, 0x5b, 0xa3, 0xcc, 0xe6, 0x61, 0xa7, 0x81, 0x80, 0x6c, 0xd7,
-		0xf5, 0x67, 0x8d, 0xfb, 0xa4, 0xe7, 0x9b, 0x2a, 0xeb, 0x97, 0x29, 0x9f,
-		0xde, 0x3e, 0xca, 0x57, 0xee, 0xca, 0x21, 0x29, 0x28, 0x28, 0x9c, 0xf3,
-		0x1d, 0xe4, 0xee, 0xda, 0x48, 0x2e, 0x13, 0x34, 0xa4, 0x01, 0x28, 0x67,
-		0xec, 0x35, 0x5f, 0x58, 0x7d, 0xec, 0x47, 0x1c, 0x16, 0x1b, 0xd9, 0xab,
-		0x05, 0xcf, 0x9a, 0xe5, 0x05, 0x84, 0x24, 0x38, 0xee, 0x39, 0xa9, 0xcd,
-		0x74, 0x51, 0x85, 0x8c, 0x8e, 0x72, 0x0a, 0x87, 0x65, 0x26, 0x1e, 0x4a,
-		0x5e, 0x58, 0xc6, 0xf9, 0x93, 0x98, 0xa0, 0x25, 0xcd, 0x77, 0x6b, 0x7c,
-		0x43, 0xc0, 0x59, 0xb3, 0x9a, 0xa9, 0x5f, 0x9e, 0x37, 0x2f, 0x7a, 0x86,
-		0x66, 0x9e, 0xf8, 0x89, 0x06, 0xb7, 0xfc, 0xf4, 0x5c, 0x67, 0xbe, 0xad,
-		0xc2, 0x40, 0x84, 0xf3, 0x0c, 0x07, 0x8a, 0xa8, 0x76, 0x5e, 0xd9, 0x54,
-		0x1b, 0x9a, 0x6c, 0x35, 0xba, 0xf8, 0x67, 0x17, 0x3e, 0x69, 0xeb, 0xb7,
-		0xbb, 0xf4, 0x6f, 0xef, 0xc4, 0xcb, 0x1b, 0xe6, 0x54, 0x51, 0x80, 0xff,
-		0xa2, 0x30, 0x63, 0x37, 0x64, 0x26, 0x27, 0xf7, 0xa1, 0x48, 0xe2, 0x15,
-		0x27, 0x7e, 0x69, 0x1d, 0x7c, 0x6c, 0x3c, 0x42, 0xb7, 0xf6, 0x5a, 0x87,
-		0x5b, 0xdf, 0xd7, 0x74, 0x2f, 0x36, 0x3d, 0x95, 0x78, 0x4d, 0xd7, 0x6d,
-		0x78, 0xf9, 0xa9, 0xfb, 0x1e, 0x1f, 0x84, 0x1b, 0x2e, 0xdc, 0x7e, 0x19,
-		0x66, 0x5b, 0x8f, 0xb4, 0xd6, 0xc0, 0x25, 0xe9, 0xe5, 0xc2, 0x13, 0xec,
-		0x8c, 0xe9, 0xbf, 0xb7, 0x3c, 0xc8, 0x22, 0x2d, 0x35, 0x3c, 0x36, 0x8f,
-		0xbc, 0xc7, 0xf4, 0xcf, 0xc7, 0xcd, 0x7f, 0x7d, 0x30, 0xf4, 0xf3, 0x7f,
-		0x60, 0xe7, 0x02, 0x95, 0xc4, 0x87, 0xa5, 0x9e, 0xbd, 0xb3, 0x08, 0x3c,
-		0x24, 0xe4, 0xef, 0x01, 0x00, 0x00, 0xff, 0xff, 0xca, 0xc7, 0x79, 0x5b,
-		0xc3, 0x19, 0x00, 0x00,
+		0xeb, 0x72, 0xdb, 0xc8, 0x95, 0xfe, 0x8f, 0xa7, 0x68, 0x73, 0x67, 0x76,
+		0xec, 0x2d, 0x89, 0xa4, 0xe4, 0xb5, 0xec, 0x91, 0xc7, 0xb5, 0xa6, 0x48,
+		0x50, 0xc2, 0x9a, 0x17, 0x0d, 0x00, 0xc9, 0xa3, 0xb8, 0x54, 0x28, 0x08,
+		0x68, 0x92, 0x1d, 0x01, 0x68, 0x08, 0xdd, 0x14, 0xc5, 0xfc, 0xcb, 0x2b,
+		0xa4, 0xf2, 0x34, 0x79, 0x9e, 0xfc, 0xc8, 0x63, 0xe4, 0x3b, 0x0d, 0x80,
+		0x02, 0x65, 0x8e, 0xc6, 0xb9, 0x55, 0x52, 0x16, 0xd1, 0xdd, 0xe7, 0xf4,
+		0xb9, 0x7c, 0xe7, 0xd6, 0xf3, 0x9e, 0xf5, 0xf2, 0x9c, 0x65, 0x61, 0xca,
+		0x99, 0x5e, 0x84, 0x9a, 0xa9, 0x85, 0x5c, 0x29, 0x26, 0x33, 0xc6, 0xef,
+		0x79, 0xb1, 0x66, 0x79, 0x38, 0xc7, 0x86, 0xd0, 0x09, 0xb7, 0x7a, 0xe7,
+		0xe7, 0xc1, 0xa4, 0x37, 0xb6, 0xd9, 0x07, 0x76, 0x2a, 0xe7, 0xea, 0x18,
+		0xff, 0xb2, 0x53, 0xa1, 0x99, 0xc7, 0x8b, 0x7b, 0x11, 0x95, 0xfb, 0xa3,
+		0xe9, 0xe9, 0x14, 0xfb, 0x22, 0x9d, 0x77, 0x66, 0x21, 0x56, 0x65, 0xd6,
+		0xce, 0xb3, 0xb9, 0xf5, 0x9e, 0xf5, 0x17, 0x61, 0x06, 0x4e, 0x38, 0x2e,
+		0x66, 0x6c, 0x2d, 0x97, 0xac, 0x58, 0x66, 0x2c, 0x91, 0x51, 0x98, 0x24,
+		0x6b, 0xcb, 0xbd, 0x98, 0x04, 0x17, 0x9e, 0xed, 0x82, 0x72, 0x2e, 0x34,
+		0x4e, 0xdb, 0x42, 0x2f, 0x78, 0xc1, 0x5a, 0x31, 0xbf, 0x6f, 0xed, 0xb1,
+		0x56, 0x5e, 0xc8, 0xb8, 0xc5, 0x24, 0x16, 0x34, 0x57, 0x1a, 0x2b, 0x31,
+		0x9f, 0x85, 0xcb, 0x04, 0xbc, 0x54, 0x79, 0xc6, 0x70, 0x18, 0x4f, 0x07,
+		0x24, 0x1b, 0xbe, 0x2d, 0xeb, 0x4b, 0xc1, 0x73, 0xa9, 0x84, 0x96, 0xc5,
+		0xfa, 0xda, 0x72, 0xa7, 0x53, 0x1f, 0x1b, 0x96, 0xd7, 0x77, 0x9d, 0x73,
+		0x3f, 0xf0, 0xaf, 0xce, 0xe9, 0xdc, 0x4d, 0xa8, 0x16, 0x38, 0xa8, 0x20,
+		0x3d, 0x2f, 0xae, 0xad, 0x73, 0x77, 0xea, 0x4f, 0xfb, 0xd3, 0x11, 0x76,
+		0x16, 0x5a, 0xe7, 0xd6, 0x60, 0x3a, 0xee, 0x39, 0x13, 0x7c, 0x19, 0x21,
+		0x17, 0x52, 0x69, 0xc3, 0x27, 0xb8, 0x70, 0xe9, 0xc8, 0xf7, 0x2f, 0xeb,
+		0xf3, 0xaf, 0xd4, 0x71, 0xa7, 0xf3, 0xfd, 0xcb, 0xf2, 0x38, 0x3e, 0xbe,
+		0x7f, 0x79, 0xe6, 0xfb, 0xe7, 0xc1, 0xf9, 0xd4, 0xf5, 0x5f, 0xa9, 0x8e,
+		0x65, 0x3e, 0x7a, 0x83, 0x01, 0xe9, 0x66, 0x6d, 0x76, 0xf0, 0xf1, 0xba,
+		0xdb, 0xed, 0x5a, 0x9e, 0x77, 0x56, 0x7f, 0x1f, 0x1e, 0x42, 0xef, 0x81,
+		0x50, 0xe1, 0x4d, 0xc2, 0x59, 0x7f, 0x30, 0x21, 0xfb, 0x67, 0x4c, 0x64,
+		0xb5, 0xf6, 0xa9, 0x8c, 0xb9, 0x35, 0x1d, 0x0e, 0x47, 0xce, 0xc4, 0xae,
+		0x55, 0x9d, 0x85, 0x89, 0xe2, 0xd6, 0xc0, 0xf1, 0x7a, 0x27, 0x23, 0x3b,
+		0x70, 0xa7, 0x17, 0xbe, 0xed, 0x92, 0x0b, 0x36, 0x5b, 0xef, 0xd9, 0x29,
+		0xcf, 0x78, 0x11, 0x6a, 0xce, 0x94, 0xe6, 0xb9, 0x3a, 0xc6, 0xca, 0x77,
+		0x2c, 0x8a, 0xe1, 0x56, 0xbd, 0xe8, 0x68, 0xd9, 0x99, 0xc3, 0x91, 0x9d,
+		0x68, 0xa9, 0xb4, 0x4c, 0x3b, 0xa4, 0xb6, 0x32, 0x07, 0xe6, 0xd2, 0xb8,
+		0xe7, 0xbb, 0xd3, 0x29, 0xa9, 0xdc, 0x51, 0x45, 0xd4, 0xc9, 0x6f, 0xe7,
+		0x9d, 0xa8, 0x58, 0xe7, 0xa0, 0xd1, 0x89, 0xea, 0xcc, 0x2b, 0xb6, 0x41,
+		0xc4, 0x0b, 0xdd, 0xc6, 0xf9, 0xfd, 0x28, 0xfc, 0xa0, 0x8b, 0x25, 0x67,
+		0xfb, 0xf1, 0x12, 0x1b, 0x42, 0x66, 0x1f, 0xde, 0xbd, 0x3d, 0xea, 0x2e,
+		0xba, 0x69, 0x57, 0xb1, 0x7d, 0x32, 0xdf, 0x87, 0x74, 0x4d, 0x7f, 0xda,
+		0xfc, 0x21, 0x4c, 0xf3, 0x84, 0xb7, 0x23, 0x99, 0x5a, 0x7d, 0xdb, 0xf5,
+		0x83, 0xa1, 0x33, 0x22, 0x65, 0x9a, 0x52, 0x74, 0x0c, 0xdb, 0x9c, 0xa7,
+		0xd6, 0x27, 0xfb, 0x6a, 0xe7, 0x81, 0x5b, 0xbe, 0x36, 0xfb, 0xef, 0xd9,
+		0x45, 0x9e, 0x03, 0x2a, 0x09, 0xcc, 0x95, 0x30, 0x39, 0x63, 0x9a, 0x83,
+		0x3b, 0x29, 0x1c, 0x66, 0x31, 0x94, 0x86, 0x28, 0x11, 0x9b, 0x09, 0xd8,
+		0x94, 0x54, 0xc6, 0xf1, 0x06, 0x74, 0x80, 0x31, 0xb3, 0xca, 0x56, 0x00,
+		0x1b, 0x37, 0xa0, 0xa6, 0x65, 0xfe, 0xc0, 0xa3, 0xa5, 0xe6, 0xb1, 0xe5,
+		0xf9, 0x3d, 0xdf, 0xe9, 0x07, 0xc6, 0xed, 0xe7, 0x3d, 0xff, 0x8c, 0x5c,
+		0x68, 0x7d, 0x89, 0x43, 0x1d, 0x02, 0x3b, 0xfc, 0xba, 0x81, 0xd3, 0x74,
+		0xad, 0xee, 0x12, 0x83, 0x54, 0x68, 0x38, 0x2f, 0xb8, 0x2a, 0xd1, 0x8a,
+		0x45, 0xa1, 0xf9, 0x6b, 0x6c, 0x08, 0xfd, 0x83, 0x22, 0xd8, 0x17, 0x2c,
+		0x5a, 0x48, 0x0a, 0x96, 0xc1, 0x49, 0x8d, 0x43, 0x43, 0x6b, 0x9d, 0x4d,
+		0x3d, 0x42, 0xc1, 0xc1, 0xe1, 0xdb, 0x76, 0x17, 0xff, 0x3b, 0x38, 0x7e,
+		0xfd, 0xba, 0x7b, 0x64, 0x55, 0xe1, 0x46, 0x5e, 0xb2, 0xaa, 0x00, 0x29,
+		0xa4, 0xd4, 0xd6, 0x79, 0xcf, 0xf3, 0x3e, 0x0f, 0xd8, 0x07, 0x88, 0x30,
+		0xa4, 0x8b, 0x1a, 0xd7, 0x66, 0xc9, 0x7a, 0x8f, 0xf1, 0x3a, 0x7e, 0x4a,
+		0x3c, 0x91, 0x64, 0x05, 0xbf, 0x5b, 0x8a, 0x82, 0x97, 0x82, 0x01, 0xf1,
+		0x62, 0xb6, 0xde, 0x9f, 0x2d, 0x93, 0xa4, 0x05, 0x10, 0x8e, 0x36, 0xb1,
+		0x53, 0x9e, 0xaf, 0xd9, 0xd6, 0xf2, 0x1b, 0xae, 0x56, 0x65, 0x02, 0xd2,
+		0xdf, 0xe0, 0xa6, 0x1d, 0xdf, 0xc0, 0x1c, 0x61, 0x9c, 0x8a, 0xec, 0xda,
+		0x04, 0x52, 0xb4, 0x2c, 0x84, 0x46, 0xbc, 0x39, 0x13, 0x58, 0x6e, 0x34,
+		0x02, 0x12, 0xfb, 0x9f, 0x1a, 0x50, 0x7c, 0xf1, 0xa2, 0x7f, 0xd6, 0x9b,
+		0x9c, 0xda, 0xcc, 0x3f, 0x73, 0x3c, 0xe6, 0x4f, 0xd9, 0x27, 0xdb, 0x3e,
+		0x67, 0x57, 0xd3, 0x0b, 0x97, 0x19, 0xdd, 0x06, 0x3d, 0xbf, 0xc7, 0xbc,
+		0xde, 0xd0, 0x7e, 0xf1, 0xc2, 0xf2, 0xec, 0xbe, 0x6b, 0xfb, 0x01, 0xbc,
+		0x0f, 0x06, 0x2f, 0xfe, 0xeb, 0xe3, 0x70, 0x60, 0x7f, 0x76, 0xf1, 0xff,
+		0xff, 0xfe, 0x9f, 0x97, 0xe0, 0xd4, 0x5b, 0x6a, 0xb9, 0x9f, 0xc8, 0x39,
+		0xa2, 0xa3, 0xe0, 0x29, 0x4f, 0x6f, 0xa0, 0x6b, 0x1c, 0xae, 0x95, 0x05,
+		0xec, 0x3b, 0x93, 0xc0, 0xb5, 0xc7, 0xf6, 0xf8, 0x04, 0xa1, 0x30, 0xe8,
+		0x5d, 0x79, 0xa0, 0x7f, 0x6b, 0xf5, 0xa7, 0xd3, 0x4f, 0x8e, 0x6d, 0x72,
+		0x4c, 0xc3, 0xa4, 0x41, 0xb8, 0xe2, 0x4a, 0xa6, 0xbc, 0xde, 0xde, 0xd0,
+		0x35, 0xcf, 0x88, 0x2c, 0x2a, 0x78, 0x2c, 0x4a, 0xab, 0xb8, 0x94, 0x14,
+		0x15, 0x50, 0x53, 0xc8, 0x87, 0x35, 0x0b, 0x97, 0xb0, 0x72, 0x06, 0x80,
+		0x19, 0xbc, 0xb3, 0x05, 0x0f, 0x63, 0x08, 0x62, 0x52, 0x29, 0x80, 0xb8,
+		0x54, 0xd5, 0x87, 0xe5, 0xda, 0x97, 0xb6, 0xeb, 0xd9, 0x01, 0x52, 0xc6,
+		0x2f, 0x57, 0x41, 0xef, 0xc2, 0x3f, 0xb3, 0x27, 0x00, 0x16, 0xc0, 0x35,
+		0xdd, 0xe4, 0xbd, 0x5f, 0xf6, 0x3f, 0xdb, 0x27, 0xb4, 0xb5, 0x4f, 0x0b,
+		0x55, 0x5e, 0x02, 0x50, 0xae, 0xad, 0x5e, 0xdf, 0x77, 0x2e, 0xed, 0xa0,
+		0x0f, 0x0f, 0x05, 0x23, 0xfa, 0x35, 0x76, 0x26, 0x08, 0x74, 0x52, 0xec,
+		0xe0, 0x5d, 0x17, 0xcc, 0x3d, 0x9b, 0xe0, 0x49, 0x80, 0xf8, 0xd5, 0x43,
+		0x88, 0x12, 0x23, 0x0d, 0xe7, 0x31, 0xd3, 0x92, 0x21, 0x2d, 0xcf, 0x44,
+		0x91, 0x32, 0xbe, 0x9f, 0x86, 0x22, 0x61, 0x33, 0xf8, 0xba, 0xe0, 0x73,
+		0xa1, 0x74, 0x19, 0xb9, 0xe0, 0x79, 0xea, 0x78, 0x94, 0x4b, 0x6c, 0x24,
+		0xb5, 0x11, 0xb8, 0x4e, 0x86, 0x8e, 0x3b, 0x6e, 0xb8, 0x72, 0x20, 0xb9,
+		0x62, 0x99, 0xd4, 0x0c, 0xe9, 0x5b, 0xae, 0x2a, 0x62, 0x5c, 0x40, 0x31,
+		0x67, 0x00, 0xc1, 0x60, 0x34, 0x13, 0x84, 0x51, 0x24, 0x97, 0x99, 0x2e,
+		0x01, 0xb4, 0x49, 0x54, 0x86, 0xbd, 0x6b, 0xf4, 0x6f, 0x30, 0x35, 0x22,
+		0xa6, 0x08, 0x72, 0xa6, 0xc4, 0xdc, 0xa4, 0x3e, 0x88, 0x7a, 0x2f, 0xf8,
+		0x0a, 0x6c, 0xd7, 0x7a, 0x21, 0xb2, 0x79, 0x1b, 0x92, 0xfd, 0x7c, 0xe1,
+		0xb8, 0x76, 0xe0, 0x39, 0xa7, 0x13, 0x78, 0xfa, 0xd2, 0xb1, 0x3f, 0x37,
+		0x38, 0xf4, 0xc3, 0x08, 0x21, 0x1d, 0xde, 0x03, 0xa1, 0x90, 0x45, 0xb1,
+		0x5c, 0x44, 0x7a, 0x59, 0x70, 0xcb, 0x9e, 0x98, 0x7b, 0xfb, 0xbd, 0xfe,
+		0x99, 0x1d, 0xf4, 0x2e, 0x81, 0x33, 0xb7, 0x41, 0x35, 0x26, 0x1b, 0x40,
+		0x19, 0x31, 0xab, 0x3c, 0x59, 0x9f, 0x9f, 0x4c, 0x7d, 0x67, 0x78, 0x15,
+		0x90, 0x0d, 0x9a, 0xc7, 0x25, 0x72, 0x45, 0xcc, 0x35, 0xa8, 0x8e, 0x4d,
+		0xa9, 0xa0, 0x02, 0x80, 0xb2, 0xb5, 0x58, 0xde, 0x50, 0x4e, 0xa3, 0xd0,
+		0x10, 0x5a, 0x95, 0x99, 0x55, 0x28, 0xb5, 0xe4, 0xaa, 0x73, 0x70, 0xf4,
+		0xa6, 0xe6, 0xf9, 0x1c, 0x16, 0x36, 0x97, 0x58, 0x5f, 0x56, 0xfc, 0x66,
+		0x21, 0xe5, 0x2d, 0xe5, 0x98, 0x7e, 0x01, 0x6c, 0xe9, 0x50, 0xdd, 0xc2,
+		0x22, 0xb0, 0xf1, 0x7d, 0x98, 0x90, 0x69, 0x60, 0x63, 0xe4, 0x28, 0x65,
+		0xf9, 0x3d, 0xef, 0x53, 0xe0, 0x4c, 0xe0, 0xac, 0xcb, 0x1e, 0x49, 0x79,
+		0x40, 0xde, 0xe1, 0x89, 0x00, 0x4e, 0x51, 0xb6, 0x53, 0x2e, 0x97, 0x9a,
+		0x8e, 0x23, 0x38, 0x65, 0x16, 0x2b, 0x6b, 0x60, 0x13, 0x3a, 0xdc, 0xc0,
+		0x77, 0xc6, 0x36, 0xca, 0x05, 0x08, 0xde, 0xe0, 0x36, 0x42, 0x01, 0xd5,
+		0xc0, 0x52, 0xc6, 0x41, 0x43, 0xd9, 0x93, 0xe5, 0x6c, 0x66, 0xb2, 0x6b,
+		0x36, 0x47, 0x9e, 0x04, 0xaa, 0x23, 0xd4, 0xf1, 0x8c, 0x27, 0x7b, 0xec,
+		0x96, 0xf3, 0x9c, 0xca, 0x39, 0xcc, 0x2c, 0x4c, 0x36, 0xad, 0xea, 0x7a,
+		0x2c, 0xb3, 0x1f, 0x34, 0xbb, 0xcd, 0x00, 0x8b, 0x15, 0xf5, 0x13, 0x66,
+		0xb3, 0x8d, 0x80, 0x9e, 0x0c, 0x82, 0x93, 0x8b, 0xe1, 0x90, 0x2a, 0x94,
+		0x4d, 0xaa, 0x1e, 0x10, 0x2c, 0x27, 0x14, 0x2c, 0xc8, 0x3a, 0x48, 0xd9,
+		0x6b, 0x60, 0x93, 0x14, 0x23, 0x6f, 0x94, 0x0d, 0x87, 0x77, 0x71, 0xf2,
+		0xff, 0x76, 0xdf, 0x37, 0xe5, 0xb6, 0x6e, 0x3e, 0x5e, 0xa9, 0xda, 0x63,
+		0x65, 0xe1, 0xa6, 0x12, 0x97, 0x1a, 0x57, 0xa8, 0x54, 0xe7, 0xed, 0x39,
+		0xfd, 0x26, 0x37, 0x1c, 0xbf, 0x79, 0xf7, 0x16, 0x7b, 0x3f, 0xff, 0x5c,
+		0x6d, 0xdc, 0xdd, 0x99, 0xd5, 0xc3, 0x37, 0x75, 0xa6, 0xad, 0xd9, 0xcc,
+		0x0a, 0x99, 0x02, 0xb3, 0x31, 0xb2, 0xa7, 0xb2, 0x86, 0xee, 0x74, 0xfc,
+		0xb8, 0x07, 0xc5, 0x37, 0x41, 0x6c, 0xa0, 0x9d, 0x87, 0x4a, 0xad, 0x64,
+		0x11, 0xd7, 0xb9, 0x78, 0x93, 0x87, 0xa9, 0x2e, 0x48, 0x4a, 0x07, 0x5f,
+		0xdb, 0xb0, 0xda, 0x68, 0x97, 0x08, 0xf9, 0x7a, 0xbf, 0x3f, 0x72, 0x80,
+		0x80, 0xc0, 0x31, 0x5c, 0xaa, 0x8f, 0x32, 0xfb, 0x95, 0x2d, 0xcb, 0xf4,
+		0xdc, 0x44, 0x71, 0x0d, 0xb4, 0x30, 0x17, 0xed, 0x06, 0xd8, 0x48, 0x3e,
+		0x8b, 0x50, 0x54, 0xf5, 0x25, 0x3b, 0xf0, 0x68, 0xf2, 0x64, 0xc7, 0x08,
+		0xd1, 0xa1, 0x7f, 0x64, 0x21, 0xfe, 0xc0, 0x2d, 0x7f, 0xfa, 0xc9, 0x9e,
+		0x7c, 0x23, 0x51, 0x14, 0xc1, 0x36, 0x81, 0x96, 0xb7, 0x3c, 0xb3, 0x4c,
+		0x4b, 0xa1, 0x59, 0x94, 0x08, 0x64, 0x3e, 0x26, 0xe2, 0xb2, 0xcc, 0x72,
+		0x84, 0xbb, 0x36, 0xa6, 0xc4, 0x7e, 0xcd, 0x0e, 0x88, 0x53, 0x12, 0x85,
+		0x3e, 0xa6, 0xd2, 0x2c, 0x51, 0xa4, 0x15, 0x1a, 0x05, 0x39, 0x2f, 0x4b,
+		0x7f, 0x07, 0x29, 0xf4, 0xf7, 0x3c, 0xd2, 0x1b, 0xf3, 0x98, 0x9d, 0x7f,
+		0xd9, 0x3c, 0xab, 0xd5, 0xaa, 0x62, 0x05, 0x43, 0x29, 0x73, 0x91, 0xd1,
+		0x81, 0xec, 0x24, 0xb2, 0x99, 0x6c, 0x73, 0x83, 0xaf, 0x6f, 0x3e, 0x0e,
+		0x29, 0xa9, 0x79, 0xd8, 0x65, 0xe2, 0x2a, 0xb5, 0x6d, 0x29, 0x25, 0x4b,
+		0x93, 0x1d, 0x1a, 0x2e, 0x3b, 0x6d, 0xfc, 0x2c, 0x55, 0x65, 0xe2, 0xca,
+		0x24, 0x77, 0x77, 0xff, 0xb4, 0x39, 0x90, 0x96, 0x0d, 0xf8, 0xd9, 0x5f,
+		0xff, 0xf2, 0xa7, 0xbf, 0xfd, 0xf1, 0xcf, 0x54, 0x32, 0x77, 0x60, 0xa4,
+		0x08, 0xf3, 0x45, 0x15, 0x18, 0x95, 0x04, 0xed, 0x6e, 0x03, 0x22, 0xef,
+		0xd9, 0x4e, 0x90, 0xec, 0xa4, 0x2a, 0x25, 0x07, 0x05, 0xcf, 0x22, 0x02,
+		0xc6, 0x8a, 0x8b, 0x1b, 0xb9, 0xcb, 0x6a, 0xc0, 0x41, 0xd6, 0xd6, 0x35,
+		0x7d, 0x34, 0x17, 0xfb, 0x37, 0x35, 0xd0, 0x0e, 0x7f, 0x03, 0x9e, 0xcf,
+		0x93, 0x6e, 0x81, 0xb4, 0xb2, 0xa0, 0x5e, 0x09, 0xad, 0x77, 0x25, 0xb6,
+		0x7f, 0xc0, 0x8c, 0xbb, 0x3c, 0x8f, 0x18, 0xac, 0x58, 0x3f, 0x5a, 0xe1,
+		0x37, 0x84, 0xff, 0x15, 0x9a, 0x5d, 0x52, 0x1b, 0xdb, 0xfd, 0x27, 0x64,
+		0x36, 0x8c, 0x1b, 0x7e, 0xfb, 0x06, 0x91, 0xbf, 0x26, 0xd9, 0x96, 0x38,
+		0xa2, 0x8a, 0xbb, 0xd5, 0x09, 0xf3, 0x14, 0x33, 0x57, 0xd9, 0x70, 0x22,
+		0xaf, 0xe3, 0x87, 0x2c, 0x57, 0xcd, 0xc9, 0x27, 0xa3, 0x5b, 0x75, 0xd8,
+		0xea, 0x0d, 0x7a, 0xe7, 0xbe, 0xc9, 0xa8, 0xe5, 0x4a, 0xdd, 0x7f, 0x56,
+		0xfb, 0x55, 0x53, 0x7b, 0xda, 0xdf, 0xaa, 0x80, 0x55, 0x49, 0xdb, 0xe2,
+		0x78, 0xd4, 0xb5, 0x1a, 0xb5, 0xf0, 0xa8, 0x5b, 0x33, 0x2a, 0x65, 0x31,
+		0xb9, 0xaa, 0x29, 0x0b, 0x18, 0x64, 0xc8, 0x41, 0xa6, 0x79, 0x43, 0x07,
+		0xbd, 0x29, 0x03, 0xef, 0x99, 0x21, 0x38, 0x66, 0xad, 0xe3, 0xa3, 0xee,
+		0xeb, 0x1f, 0x5b, 0x58, 0xa8, 0xa9, 0xb0, 0xf6, 0xd8, 0xa3, 0x1f, 0x1c,
+		0x1c, 0x1e, 0x1c, 0xb4, 0xaa, 0x8a, 0x62, 0x7a, 0x36, 0xa5, 0xc0, 0x6c,
+		0xb7, 0x3d, 0x28, 0x8f, 0x3c, 0xda, 0xa5, 0x34, 0x4b, 0x35, 0x36, 0xec,
+		0xb2, 0x09, 0x1a, 0x84, 0x4b, 0x67, 0x60, 0x8c, 0x62, 0x32, 0xd0, 0x7b,
+		0x76, 0x5e, 0xc8, 0x7b, 0x41, 0x1d, 0xa6, 0x69, 0xdf, 0xe6, 0x4c, 0xe6,
+		0x24, 0xb9, 0x2a, 0x85, 0x03, 0xcd, 0xb1, 0xe9, 0xc8, 0x16, 0xe1, 0x3d,
+		0x15, 0xab, 0x75, 0x7d, 0x6a, 0xcd, 0x69, 0xa0, 0x26, 0x16, 0xa8, 0x84,
+		0xa5, 0x7c, 0x8f, 0xf3, 0x10, 0x26, 0x85, 0xf6, 0xbc, 0x8d, 0x39, 0x81,
+		0x7a, 0xfa, 0x6a, 0x57, 0xb5, 0x1e, 0xf5, 0xaf, 0x78, 0x24, 0xe2, 0x96,
+		0x97, 0x4b, 0x55, 0xd5, 0x35, 0x96, 0xda, 0x63, 0xb9, 0x94, 0x89, 0x07,
+		0xf8, 0xec, 0x6d, 0x2a, 0x63, 0xcd, 0xf0, 0xd1, 0x46, 0x47, 0xaf, 0xdf,
+		0xfe, 0xb8, 0x77, 0xd0, 0xed, 0xee, 0x85, 0x18, 0xc6, 0x1e, 0x04, 0x37,
+		0xc6, 0x24, 0xbd, 0x8f, 0xd1, 0x5f, 0xef, 0xe3, 0xef, 0x7e, 0x5c, 0x50,
+		0xb7, 0xd2, 0x31, 0x8b, 0x2c, 0x56, 0x59, 0x7d, 0x2b, 0xda, 0x51, 0xf4,
+		0x7c, 0x35, 0x47, 0x9a, 0x7b, 0x8e, 0xeb, 0x6b, 0x3e, 0xd6, 0xc2, 0x06,
+		0xda, 0xcc, 0x37, 0x1b, 0x6b, 0x95, 0xbd, 0xea, 0x69, 0x3d, 0xa6, 0xd4,
+		0x2a, 0xe1, 0x4e, 0xaf, 0xd2, 0x3d, 0x42, 0x5b, 0x25, 0x78, 0xd9, 0x98,
+		0x57, 0x7d, 0x7f, 0xd5, 0xee, 0x8b, 0x80, 0xf4, 0x0c, 0xca, 0xfe, 0x0d,
+		0x14, 0x4e, 0xd9, 0xd0, 0xa0, 0x16, 0x6c, 0x0c, 0x07, 0xd8, 0x99, 0xe8,
+		0xa8, 0x10, 0xd9, 0xf0, 0x5b, 0x15, 0xa3, 0x25, 0x43, 0x84, 0xe5, 0x85,
+		0x6b, 0x37, 0xda, 0x28, 0x3b, 0x33, 0x63, 0xbd, 0xa2, 0xca, 0x69, 0xee,
+		0xdf, 0xa2, 0xa5, 0xb9, 0xb9, 0xee, 0x0f, 0xa9, 0x99, 0x2f, 0xb9, 0x80,
+		0xdc, 0x6c, 0x3c, 0x8a, 0x8e, 0x00, 0xa0, 0x96, 0x6e, 0x13, 0x05, 0x5b,
+		0x4c, 0xde, 0x1d, 0xfd, 0x6f, 0xb7, 0x6b, 0x9d, 0xf6, 0x37, 0xcd, 0xa0,
+		0xe9, 0xf1, 0xc0, 0xa4, 0xdc, 0x78, 0xe4, 0x92, 0x88, 0x19, 0x37, 0x7c,
+		0x76, 0x90, 0x7b, 0xb6, 0xe7, 0xd1, 0x50, 0x32, 0x72, 0x86, 0xf6, 0x53,
+		0xfa, 0x8d, 0x0d, 0x62, 0x60, 0x4c, 0x2d, 0xd8, 0x6c, 0x99, 0x45, 0x7b,
+		0x1b, 0x9c, 0xab, 0x45, 0x78, 0x40, 0xe8, 0xc6, 0xdf, 0xc3, 0x37, 0x47,
+		0x15, 0xbc, 0xe3, 0x37, 0xad, 0xe6, 0x1d, 0x74, 0x66, 0x73, 0x85, 0x33,
+		0x08, 0xce, 0x7a, 0xde, 0xd9, 0xf0, 0x62, 0xd2, 0xc7, 0x25, 0x66, 0xeb,
+		0x51, 0x46, 0x73, 0x01, 0x46, 0xfc, 0x2d, 0x11, 0xc9, 0x11, 0x05, 0x42,
+		0x18, 0xfd, 0x5a, 0x09, 0x8d, 0xa7, 0xbc, 0xcc, 0xb4, 0x88, 0x30, 0xac,
+		0xda, 0x7e, 0x0a, 0x43, 0x9f, 0x46, 0xfc, 0x24, 0x8c, 0x38, 0xcd, 0x12,
+		0xd5, 0xba, 0x81, 0xc6, 0xe3, 0x8c, 0x5c, 0x22, 0xba, 0x94, 0xf8, 0x4e,
+		0x64, 0x62, 0xf9, 0x24, 0x20, 0xab, 0x7d, 0x5c, 0xe6, 0x5e, 0x3a, 0x7d,
+		0xb2, 0x48, 0xd5, 0x79, 0xd6, 0xe3, 0xcc, 0xa9, 0xfb, 0x64, 0xa4, 0xb0,
+		0xbe, 0xa0, 0x7d, 0x2a, 0x9f, 0x9d, 0xaa, 0x77, 0x83, 0x46, 0x42, 0xa8,
+		0xba, 0xa2, 0x66, 0x46, 0xa0, 0x34, 0x64, 0x6c, 0x87, 0x46, 0xb5, 0x94,
+		0xa3, 0x7e, 0x63, 0x78, 0x22, 0x4a, 0x4d, 0x5b, 0x0e, 0x4b, 0x80, 0x52,
+		0x9a, 0x86, 0xa4, 0x98, 0xe2, 0x79, 0x68, 0x1e, 0x79, 0x52, 0x9c, 0x14,
+		0x39, 0x90, 0x46, 0xaf, 0x45, 0xaa, 0x0e, 0x9d, 0x8a, 0x6c, 0xcf, 0xc4,
+		0x7d, 0xcb, 0xaa, 0x66, 0xfd, 0x6a, 0xf5, 0xdf, 0xd9, 0xe4, 0x3f, 0xe9,
+		0xef, 0xbb, 0x06, 0x37, 0xb5, 0xe2, 0x7e, 0x01, 0x37, 0x90, 0x9a, 0x03,
+		0x7e, 0xb3, 0x9c, 0xd3, 0x0f, 0x07, 0x1d, 0x16, 0xfd, 0xfd, 0x1c, 0x16,
+		0x46, 0x7f, 0xbb, 0x28, 0x64, 0x41, 0x3f, 0xfa, 0x85, 0xa0, 0xa9, 0xfa,
+		0x69, 0x6a, 0x2c, 0x39, 0x58, 0x23, 0x8c, 0x50, 0x94, 0xde, 0xcd, 0xa7,
+		0x55, 0xa7, 0xf8, 0xda, 0x36, 0x46, 0xf5, 0x72, 0xde, 0x24, 0x37, 0xb4,
+		0xab, 0xf5, 0xeb, 0x0d, 0xd9, 0x86, 0xc2, 0x58, 0xe3, 0xe9, 0x71, 0x5a,
+		0x6c, 0x9c, 0xa5, 0xa7, 0xa7, 0x3a, 0x3f, 0x60, 0xbb, 0x7c, 0xf7, 0xc0,
+		0x0f, 0x03, 0x2d, 0x7a, 0x2b, 0x32, 0x81, 0xad, 0xe8, 0x29, 0x40, 0xa6,
+		0xf0, 0x40, 0x4c, 0xa7, 0x58, 0x21, 0x35, 0x7e, 0xbf, 0x54, 0xa8, 0xf7,
+		0x91, 0x31, 0xe8, 0x4c, 0xd2, 0x9c, 0x0c, 0xc8, 0xd6, 0x49, 0xfb, 0xd5,
+		0xd7, 0x09, 0x60, 0x34, 0x3d, 0x0d, 0xdc, 0xa9, 0xdf, 0xf3, 0x1b, 0x91,
+		0x3f, 0x0e, 0x1f, 0x10, 0xaf, 0x19, 0xd2, 0xd5, 0xd2, 0x3c, 0x72, 0x80,
+		0x95, 0x02, 0x17, 0x38, 0x98, 0xe4, 0xdc, 0xe2, 0x61, 0xcc, 0x0d, 0x83,
+		0x8f, 0x7b, 0xbf, 0x04, 0xf4, 0x46, 0xe8, 0xd5, 0x2e, 0x30, 0x4e, 0x20,
+		0x46, 0x0a, 0x99, 0x1a, 0x81, 0x26, 0x66, 0xfa, 0x39, 0x3e, 0x87, 0xef,
+		0x50, 0x4e, 0xc2, 0x0c, 0x0c, 0xd9, 0x4f, 0x3f, 0xe1, 0x6b, 0x8f, 0x21,
+		0x9e, 0xc7, 0x27, 0x86, 0xaf, 0xe7, 0xfc, 0x0e, 0x19, 0xea, 0xcc, 0x19,
+		0x9a, 0x07, 0xcb, 0x77, 0x26, 0x60, 0xe7, 0x29, 0xf5, 0x7b, 0xa4, 0x75,
+		0x8c, 0xce, 0x7a, 0xfd, 0xb5, 0x5e, 0x03, 0x8c, 0xcf, 0x57, 0x5f, 0x69,
+		0x66, 0x3f, 0xe4, 0x02, 0x15, 0xc5, 0x3c, 0xdb, 0x90, 0x38, 0xc4, 0x80,
+		0x64, 0x79, 0x19, 0xf3, 0x84, 0xd3, 0xc3, 0xc1, 0x8c, 0xde, 0x13, 0x52,
+		0x88, 0x4d, 0x27, 0xb6, 0xcd, 0xf5, 0xd6, 0x08, 0xb3, 0x79, 0xdc, 0x69,
+		0x20, 0x20, 0xdb, 0xe5, 0xfe, 0xac, 0xe1, 0x4f, 0x7a, 0xc2, 0xa9, 0xaa,
+		0x7e, 0x59, 0xf2, 0xe9, 0xed, 0xa3, 0x7c, 0xe9, 0xae, 0x0c, 0x92, 0x22,
+		0x05, 0x85, 0x73, 0xbe, 0x23, 0xb9, 0xbb, 0x36, 0x8a, 0xcb, 0x04, 0x03,
+		0x69, 0x80, 0x94, 0x33, 0xf6, 0x9a, 0xaf, 0xac, 0x3e, 0xe8, 0x11, 0x87,
+		0xc5, 0x86, 0xf7, 0x6a, 0xc1, 0xb3, 0x66, 0x7b, 0x01, 0x26, 0x09, 0xae,
+		0x7b, 0x8e, 0x6b, 0xb3, 0x5c, 0x54, 0x21, 0xa3, 0xa3, 0x9c, 0xc2, 0x61,
+		0x99, 0x89, 0x87, 0x32, 0x2f, 0x2c, 0xe3, 0xfc, 0x49, 0x4c, 0xd0, 0x91,
+		0xe6, 0xdb, 0x35, 0xbe, 0xc1, 0xe0, 0xac, 0xd9, 0xcd, 0xd4, 0xaf, 0xcf,
+		0x9b, 0x57, 0x3d, 0x93, 0x66, 0x9e, 0xd8, 0x89, 0x16, 0xb7, 0xec, 0xf4,
+		0xdc, 0x64, 0xbe, 0x2d, 0xc2, 0x40, 0x84, 0xf3, 0x0c, 0x17, 0x8a, 0xa8,
+		0x36, 0x5e, 0x39, 0x54, 0x9b, 0x34, 0xd9, 0x6a, 0x4c, 0xf1, 0xcf, 0x1e,
+		0x7c, 0x32, 0xd6, 0x6f, 0x4f, 0xe9, 0xdf, 0x3e, 0x89, 0x97, 0x1e, 0xe6,
+		0xd4, 0x51, 0x20, 0xff, 0x45, 0x61, 0xc6, 0x6e, 0x48, 0x4d, 0x4e, 0xe6,
+		0x43, 0x93, 0xc4, 0xab, 0x9c, 0xf8, 0xa5, 0x75, 0xf0, 0xb1, 0xf1, 0x10,
+		0xdd, 0xda, 0x6b, 0x1d, 0x6e, 0x7d, 0x5f, 0x93, 0x5f, 0x6c, 0x7a, 0x2a,
+		0xf1, 0x9a, 0xa6, 0xdb, 0xe4, 0xe5, 0xa7, 0xe6, 0x7b, 0x7c, 0x14, 0x6e,
+		0x98, 0x70, 0xfb, 0x75, 0x98, 0x6d, 0x3d, 0xd4, 0x5a, 0x03, 0x97, 0xb8,
+		0x97, 0x07, 0x4f, 0x40, 0x19, 0xd3, 0x7f, 0x73, 0x79, 0x90, 0x45, 0x5a,
+		0x4a, 0x78, 0x6c, 0x1e, 0x7a, 0x8f, 0xe9, 0x9f, 0x8f, 0x9b, 0xff, 0x02,
+		0x61, 0xd2, 0xcf, 0xff, 0x21, 0x3b, 0x17, 0xe8, 0x24, 0x3e, 0x2c, 0xf5,
+		0xec, 0x9d, 0x45, 0xe0, 0x21, 0x26, 0x7f, 0x0f, 0x00, 0x00, 0xff, 0xff,
+		0xc9, 0x2e, 0x07, 0x65, 0xc7, 0x19, 0x00, 0x00,
 	},
 	},
 		"conf/app.ini",
 		"conf/app.ini",
 	)
 	)

+ 14 - 5
modules/mailer/mail.go

@@ -17,6 +17,15 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
+const (
+	AUTH_ACTIVE           base.TplName = "mail/auth/active"
+	AUTH_REGISTER_SUCCESS base.TplName = "mail/auth/register_success"
+	AUTH_RESET_PASSWORD   base.TplName = "mail/auth/reset_passwd"
+
+	NOTIFY_COLLABORATOR base.TplName = "mail/notify/collaborator"
+	NOTIFY_MENTION      base.TplName = "mail/notify/mention"
+)
+
 // Create New mail message use MailFrom and MailUser
 // Create New mail message use MailFrom and MailUser
 func NewMailMessageFrom(To []string, from, subject, body string) Message {
 func NewMailMessageFrom(To []string, from, subject, body string) Message {
 	msg := NewHtmlMessage(To, from, subject, body)
 	msg := NewHtmlMessage(To, from, subject, body)
@@ -61,7 +70,7 @@ func SendRegisterMail(r *middleware.Render, u *models.User) {
 
 
 	data := GetMailTmplData(u)
 	data := GetMailTmplData(u)
 	data["Code"] = code
 	data["Code"] = code
-	body, err := r.HTMLString("mail/auth/register_success", data)
+	body, err := r.HTMLString(string(AUTH_REGISTER_SUCCESS), data)
 	if err != nil {
 	if err != nil {
 		log.Error("mail.SendRegisterMail(fail to render): %v", err)
 		log.Error("mail.SendRegisterMail(fail to render): %v", err)
 		return
 		return
@@ -81,7 +90,7 @@ func SendActiveMail(r *middleware.Render, u *models.User) {
 
 
 	data := GetMailTmplData(u)
 	data := GetMailTmplData(u)
 	data["Code"] = code
 	data["Code"] = code
-	body, err := r.HTMLString("mail/auth/active_email", data)
+	body, err := r.HTMLString(string(AUTH_ACTIVE), data)
 	if err != nil {
 	if err != nil {
 		log.Error("mail.SendActiveMail(fail to render): %v", err)
 		log.Error("mail.SendActiveMail(fail to render): %v", err)
 		return
 		return
@@ -101,7 +110,7 @@ func SendResetPasswdMail(r *middleware.Render, u *models.User) {
 
 
 	data := GetMailTmplData(u)
 	data := GetMailTmplData(u)
 	data["Code"] = code
 	data["Code"] = code
-	body, err := r.HTMLString("mail/auth/reset_passwd", data)
+	body, err := r.HTMLString(string(AUTH_RESET_PASSWORD), data)
 	if err != nil {
 	if err != nil {
 		log.Error("mail.SendResetPasswdMail(fail to render): %v", err)
 		log.Error("mail.SendResetPasswdMail(fail to render): %v", err)
 		return
 		return
@@ -161,7 +170,7 @@ func SendIssueMentionMail(r *middleware.Render, u, owner *models.User,
 	data["IssueLink"] = fmt.Sprintf("%s/%s/issues/%d", owner.Name, repo.Name, issue.Index)
 	data["IssueLink"] = fmt.Sprintf("%s/%s/issues/%d", owner.Name, repo.Name, issue.Index)
 	data["Subject"] = subject
 	data["Subject"] = subject
 
 
-	body, err := r.HTMLString("mail/notify/mention", data)
+	body, err := r.HTMLString(string(NOTIFY_MENTION), data)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("mail.SendIssueMentionMail(fail to render): %v", err)
 		return fmt.Errorf("mail.SendIssueMentionMail(fail to render): %v", err)
 	}
 	}
@@ -182,7 +191,7 @@ func SendCollaboratorMail(r *middleware.Render, u, owner *models.User,
 	data["RepoLink"] = path.Join(owner.Name, repo.Name)
 	data["RepoLink"] = path.Join(owner.Name, repo.Name)
 	data["Subject"] = subject
 	data["Subject"] = subject
 
 
-	body, err := r.HTMLString("mail/notify/collaborator", data)
+	body, err := r.HTMLString(string(NOTIFY_COLLABORATOR), data)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("mail.SendCollaboratorMail(fail to render): %v", err)
 		return fmt.Errorf("mail.SendCollaboratorMail(fail to render): %v", err)
 	}
 	}

+ 4 - 4
modules/middleware/context.go

@@ -104,12 +104,12 @@ func (ctx *Context) HasError() bool {
 }
 }
 
 
 // HTML calls render.HTML underlying but reduce one argument.
 // HTML calls render.HTML underlying but reduce one argument.
-func (ctx *Context) HTML(status int, name string, htmlOpt ...HTMLOptions) {
-	ctx.Render.HTML(status, name, ctx.Data, htmlOpt...)
+func (ctx *Context) HTML(status int, name base.TplName, htmlOpt ...HTMLOptions) {
+	ctx.Render.HTML(status, string(name), ctx.Data, htmlOpt...)
 }
 }
 
 
 // RenderWithErr used for page has form validation but need to prompt error to users.
 // RenderWithErr used for page has form validation but need to prompt error to users.
-func (ctx *Context) RenderWithErr(msg, tpl string, form auth.Form) {
+func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form auth.Form) {
 	if form != nil {
 	if form != nil {
 		auth.AssignForm(form, ctx.Data)
 		auth.AssignForm(form, ctx.Data)
 	}
 	}
@@ -133,7 +133,7 @@ func (ctx *Context) Handle(status int, title string, err error) {
 	case 500:
 	case 500:
 		ctx.Data["Title"] = "Internal Server Error"
 		ctx.Data["Title"] = "Internal Server Error"
 	}
 	}
-	ctx.HTML(status, fmt.Sprintf("status/%d", status))
+	ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
 }
 }
 
 
 func (ctx *Context) Debug(msg string, args ...interface{}) {
 func (ctx *Context) Debug(msg string, args ...interface{}) {

+ 2 - 2
modules/middleware/repo.go

@@ -46,7 +46,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 
 
 		// Collaborators who have write access can be seen as owners.
 		// Collaborators who have write access can be seen as owners.
 		if ctx.IsSigned {
 		if ctx.IsSigned {
-			ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.AU_WRITABLE)
+			ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
 			if err != nil {
 			if err != nil {
 				ctx.Handle(500, "RepoAssignment(HasAccess)", err)
 				ctx.Handle(500, "RepoAssignment(HasAccess)", err)
 				return
 				return
@@ -107,7 +107,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 				return
 				return
 			}
 			}
 
 
-			hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.AU_READABLE)
+			hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
 			if err != nil {
 			if err != nil {
 				ctx.Handle(500, "RepoAssignment(HasAccess)", err)
 				ctx.Handle(500, "RepoAssignment(HasAccess)", err)
 				return
 				return

+ 7 - 7
modules/setting/setting.go

@@ -47,12 +47,12 @@ var (
 	StaticRootPath     string
 	StaticRootPath     string
 
 
 	// Security settings.
 	// Security settings.
-	InstallLock         bool
-	SecretKey           string
-	LogInRememberDays   int
-	CookieUserName      string
-	CookieRememberName  string
-	ReverseProxyAuthUid string
+	InstallLock          bool
+	SecretKey            string
+	LogInRememberDays    int
+	CookieUserName       string
+	CookieRememberName   string
+	ReverseProxyAuthUser string
 
 
 	// Webhook settings.
 	// Webhook settings.
 	WebhookTaskInterval   int
 	WebhookTaskInterval   int
@@ -164,7 +164,7 @@ func NewConfigContext() {
 	LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
 	LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
 	CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
 	CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
 	CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
 	CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
-	ReverseProxyAuthUid = Cfg.MustValue("security", "REVERSE_PROXY_AUTHENTICATION_UID", "X-WEBAUTH-UID")
+	ReverseProxyAuthUser = Cfg.MustValue("security", "REVERSE_PROXY_AUTHENTICATION_USER", "X-WEBAUTH-USER")
 
 
 	RunUser = Cfg.MustValue("", "RUN_USER")
 	RunUser = Cfg.MustValue("", "RUN_USER")
 	curUser := os.Getenv("USER")
 	curUser := os.Getenv("USER")

+ 114 - 3
public/css/gogs.css

@@ -257,6 +257,9 @@ html, body {
 
 
 .card .btn {
 .card .btn {
     cursor: pointer;
     cursor: pointer;
+}
+
+.card .btn-primary {
     margin-right: 1.2em;
     margin-right: 1.2em;
 }
 }
 
 
@@ -372,7 +375,7 @@ html, body {
 
 
 /* gogits repo create */
 /* gogits repo create */
 
 
-#repo-create {
+#repo-create, #org-create, #org-teams-create, #org-teams-edit {
     width: 800px;
     width: 800px;
 }
 }
 
 
@@ -638,7 +641,7 @@ html, body {
     margin: 0 .5em;
     margin: 0 .5em;
 }
 }
 
 
-#dashboard-switch .btn {
+#dashboard-switch .btn, #repo-owner-switch .btn {
     height: 40px;
     height: 40px;
 }
 }
 
 
@@ -647,7 +650,7 @@ html, body {
     margin-right: 18px;
     margin-right: 18px;
 }
 }
 
 
-#dashboard-switch .dropdown-menu {
+#dashboard-switch .dropdown-menu,#repo-owner-switch .dropdown-menu {
     padding: 0;
     padding: 0;
 }
 }
 
 
@@ -662,6 +665,14 @@ html, body {
     padding: .8em 1.2em;
     padding: .8em 1.2em;
 }
 }
 
 
+#dashboard-switch-menu > li > a:hover {
+    text-decoration: none;
+}
+
+#dashboard-switch-menu > li > a img, #dashboard-switch button img {
+    margin-right: 6px;
+}
+
 #dashboard-switch-menu > li {
 #dashboard-switch-menu > li {
     border-bottom: 1px solid #eaeaea;
     border-bottom: 1px solid #eaeaea;
 }
 }
@@ -1864,16 +1875,44 @@ html, body {
     padding: 16px 0;
     padding: 16px 0;
 }
 }
 
 
+#body-nav.org-nav.org-nav-auto {
+    height: auto;
+}
+
+.org-nav > .container {
+    padding-left: 0;
+    padding-left: 0;
+}
+
 .org-nav .org-logo {
 .org-nav .org-logo {
     margin-right: 16px;
     margin-right: 16px;
     width: 100px;
     width: 100px;
     height: 100px;
     height: 100px;
 }
 }
 
 
+.org-nav .org-small-logo {
+    margin-right: 16px;
+    width: 50px;
+    height: 50px;
+}
+
 .org-nav .org-name {
 .org-nav .org-name {
     margin-top: 0;
     margin-top: 0;
 }
 }
 
 
+.org-nav-auto .org-name {
+    font-size: 1.4em;
+    line-height: 48px;
+}
+
+#body-nav.org-nav-auto .nav {
+    margin-top: 6px;
+}
+
+#body-nav.org-nav-auto .nav a:hover {
+    text-decoration: none;
+}
+
 .org-description {
 .org-description {
     font-size: 16px;
     font-size: 16px;
 }
 }
@@ -1894,6 +1933,10 @@ html, body {
     margin-left: 0;
     margin-left: 0;
 }
 }
 
 
+.org-main {
+    padding-left: 0;
+}
+
 .org-sidebar {
 .org-sidebar {
     margin-top: -100px;
     margin-top: -100px;
 }
 }
@@ -1947,4 +1990,72 @@ html, body {
 
 
 .org-team a:hover .org-team-name {
 .org-team a:hover .org-team-name {
     color: #0079bc !important;
     color: #0079bc !important;
+}
+
+#org-members {
+    margin-right: 30px;
+}
+
+#org-members .member .avatar img {
+    width: 50px;
+    height: 50px;
+}
+
+#org-members .member {
+    padding-bottom: 20px;
+    margin-bottom: 20px;
+    border-bottom: 1px solid #DDD;
+    height: 70px;
+}
+
+#org-members .member .name {
+    padding-top: 4px;
+}
+
+#org-members .member .nick {
+    display: block;
+    color: #888;
+}
+
+#org-members .member .name a {
+    color: #444;
+}
+
+#org-members .member .name strong {
+    font-size: 1.2em;
+}
+
+#org-members .status, #org-members .role {
+    line-height: 48px;
+    text-align: right;
+}
+
+#org-teams .org-team .panel-heading {
+    margin-top: 0;
+}
+
+#org-teams .org-team .panel-heading a {
+    color: #444;
+}
+
+#org-teams .org-team-members {
+    margin-top: 18px;
+}
+
+#org-teams .org-team-members img {
+    width: 40px;
+    height: 40px;
+    margin-right: 12px;
+}
+
+#org-teams .org-team-members a {
+    display: inline-block;
+}
+
+#org-teams .org-team .panel-footer {
+    height: 60px;
+}
+
+#org-teams .org-team {
+    border-bottom: none;
 }
 }

+ 24 - 0
public/js/app.js

@@ -758,6 +758,27 @@ function initRepoSetting() {
     });
     });
 }
 }
 
 
+function initRepoCreating() {
+    // owner switch menu click
+    (function () {
+        $('#repo-owner-switch .dropdown-menu').on("click", "li", function () {
+            var uid = $(this).data('uid');
+            // set to input
+            $('#repo-owner-id').val(uid);
+            // set checked class
+            if (!$(this).hasClass("checked")) {
+                $(this).parent().find(".checked").removeClass("checked");
+                $(this).addClass("checked");
+            }
+            // set button group to show clicked owner
+            $('#repo-owner-avatar').attr("src",$(this).find('img').attr("src"));
+            $('#repo-owner-name').text($(this).text().trim());
+            console.log("set repo owner to uid :",uid,$(this).text().trim());
+        });
+    }());
+    console.log("init repo-creating scripts");
+}
+
 (function ($) {
 (function ($) {
     $(function () {
     $(function () {
         initCore();
         initCore();
@@ -780,6 +801,9 @@ function initRepoSetting() {
         if ($('#repo-setting-container').length) {
         if ($('#repo-setting-container').length) {
             initRepoSetting();
             initRepoSetting();
         }
         }
+        if ($('#repo-create').length) {
+            initRepoCreating();
+        }
     });
     });
 })(jQuery);
 })(jQuery);
 
 

+ 19 - 10
routers/admin/admin.go

@@ -20,6 +20,16 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
+const (
+	DASHBOARD       base.TplName = "admin/dashboard"
+	USERS           base.TplName = "admin/users"
+	REPOS           base.TplName = "admin/repos"
+	AUTHS           base.TplName = "admin/auths"
+	CONFIG          base.TplName = "admin/config"
+	MONITOR_PROCESS base.TplName = "admin/monitor/process"
+	MONITOR_CRON    base.TplName = "admin/monitor/cron"
+)
+
 var startTime = time.Now()
 var startTime = time.Now()
 
 
 var sysStatus struct {
 var sysStatus struct {
@@ -140,7 +150,7 @@ func Dashboard(ctx *middleware.Context) {
 	ctx.Data["Stats"] = models.GetStatistic()
 	ctx.Data["Stats"] = models.GetStatistic()
 	updateSystemStatus()
 	updateSystemStatus()
 	ctx.Data["SysStatus"] = sysStatus
 	ctx.Data["SysStatus"] = sysStatus
-	ctx.HTML(200, "admin/dashboard")
+	ctx.HTML(200, DASHBOARD)
 }
 }
 
 
 func Users(ctx *middleware.Context) {
 func Users(ctx *middleware.Context) {
@@ -150,10 +160,10 @@ func Users(ctx *middleware.Context) {
 	var err error
 	var err error
 	ctx.Data["Users"], err = models.GetUsers(200, 0)
 	ctx.Data["Users"], err = models.GetUsers(200, 0)
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.Users", err)
+		ctx.Handle(500, "admin.Users(GetUsers)", err)
 		return
 		return
 	}
 	}
-	ctx.HTML(200, "admin/users")
+	ctx.HTML(200, USERS)
 }
 }
 
 
 func Repositories(ctx *middleware.Context) {
 func Repositories(ctx *middleware.Context) {
@@ -166,7 +176,7 @@ func Repositories(ctx *middleware.Context) {
 		ctx.Handle(500, "admin.Repositories", err)
 		ctx.Handle(500, "admin.Repositories", err)
 		return
 		return
 	}
 	}
-	ctx.HTML(200, "admin/repos")
+	ctx.HTML(200, REPOS)
 }
 }
 
 
 func Auths(ctx *middleware.Context) {
 func Auths(ctx *middleware.Context) {
@@ -179,7 +189,7 @@ func Auths(ctx *middleware.Context) {
 		ctx.Handle(500, "admin.Auths", err)
 		ctx.Handle(500, "admin.Auths", err)
 		return
 		return
 	}
 	}
-	ctx.HTML(200, "admin/auths")
+	ctx.HTML(200, AUTHS)
 }
 }
 
 
 func Config(ctx *middleware.Context) {
 func Config(ctx *middleware.Context) {
@@ -196,7 +206,7 @@ func Config(ctx *middleware.Context) {
 	ctx.Data["StaticRootPath"] = setting.StaticRootPath
 	ctx.Data["StaticRootPath"] = setting.StaticRootPath
 	ctx.Data["LogRootPath"] = setting.LogRootPath
 	ctx.Data["LogRootPath"] = setting.LogRootPath
 	ctx.Data["ScriptType"] = setting.ScriptType
 	ctx.Data["ScriptType"] = setting.ScriptType
-	ctx.Data["ReverseProxyAuthUid"] = setting.ReverseProxyAuthUid
+	ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
 
 
 	ctx.Data["Service"] = setting.Service
 	ctx.Data["Service"] = setting.Service
 
 
@@ -235,7 +245,7 @@ func Config(ctx *middleware.Context) {
 	}
 	}
 	ctx.Data["Loggers"] = loggers
 	ctx.Data["Loggers"] = loggers
 
 
-	ctx.HTML(200, "admin/config")
+	ctx.HTML(200, CONFIG)
 }
 }
 
 
 func Monitor(ctx *middleware.Context) {
 func Monitor(ctx *middleware.Context) {
@@ -247,11 +257,10 @@ func Monitor(ctx *middleware.Context) {
 	case "process":
 	case "process":
 		ctx.Data["PageIsMonitorProcess"] = true
 		ctx.Data["PageIsMonitorProcess"] = true
 		ctx.Data["Processes"] = process.Processes
 		ctx.Data["Processes"] = process.Processes
-		ctx.HTML(200, "admin/monitor/process")
+		ctx.HTML(200, MONITOR_PROCESS)
 	default:
 	default:
 		ctx.Data["PageIsMonitorCron"] = true
 		ctx.Data["PageIsMonitorCron"] = true
 		ctx.Data["Entries"] = cron.ListEntries()
 		ctx.Data["Entries"] = cron.ListEntries()
-		ctx.HTML(200, "admin/monitor/cron")
+		ctx.HTML(200, MONITOR_CRON)
 	}
 	}
-
 }
 }

+ 14 - 9
routers/admin/auths.go → routers/admin/auth.go

@@ -18,12 +18,17 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	AUTH_NEW  base.TplName = "admin/auth/new"
+	AUTH_EDIT base.TplName = "admin/auth/edit"
+)
+
 func NewAuthSource(ctx *middleware.Context) {
 func NewAuthSource(ctx *middleware.Context) {
 	ctx.Data["Title"] = "New Authentication"
 	ctx.Data["Title"] = "New Authentication"
 	ctx.Data["PageIsAuths"] = true
 	ctx.Data["PageIsAuths"] = true
 	ctx.Data["LoginTypes"] = models.LoginTypes
 	ctx.Data["LoginTypes"] = models.LoginTypes
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
-	ctx.HTML(200, "admin/auths/new")
+	ctx.HTML(200, AUTH_NEW)
 }
 }
 
 
 func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
@@ -33,7 +38,7 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "admin/auths/new")
+		ctx.HTML(200, AUTH_NEW)
 		return
 		return
 	}
 	}
 
 
@@ -74,7 +79,7 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	}
 	}
 
 
 	if err := models.CreateSource(source); err != nil {
 	if err := models.CreateSource(source); err != nil {
-		ctx.Handle(500, "admin.auths.NewAuth", err)
+		ctx.Handle(500, "admin.auths.NewAuth(CreateSource)", err)
 		return
 		return
 	}
 	}
 
 
@@ -97,11 +102,11 @@ func EditAuthSource(ctx *middleware.Context, params martini.Params) {
 	}
 	}
 	u, err := models.GetLoginSourceById(id)
 	u, err := models.GetLoginSourceById(id)
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.user.EditUser", err)
+		ctx.Handle(500, "admin.user.EditUser(GetLoginSourceById)", err)
 		return
 		return
 	}
 	}
 	ctx.Data["Source"] = u
 	ctx.Data["Source"] = u
-	ctx.HTML(200, "admin/auths/edit")
+	ctx.HTML(200, AUTH_EDIT)
 }
 }
 
 
 func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
@@ -111,7 +116,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
 	ctx.Data["SMTPAuths"] = models.SMTPAuths
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "admin/auths/edit")
+		ctx.HTML(200, AUTH_EDIT)
 		return
 		return
 	}
 	}
 
 
@@ -153,7 +158,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	}
 	}
 
 
 	if err := models.UpdateSource(&u); err != nil {
 	if err := models.UpdateSource(&u); err != nil {
-		ctx.Handle(500, "admin.auths.EditAuth", err)
+		ctx.Handle(500, "admin.auths.EditAuth(UpdateSource)", err)
 		return
 		return
 	}
 	}
 
 
@@ -175,7 +180,7 @@ func DeleteAuthSource(ctx *middleware.Context, params martini.Params) {
 
 
 	a, err := models.GetLoginSourceById(id)
 	a, err := models.GetLoginSourceById(id)
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.auths.DeleteAuth", err)
+		ctx.Handle(500, "admin.auths.DeleteAuth(GetLoginSourceById)", err)
 		return
 		return
 	}
 	}
 
 
@@ -185,7 +190,7 @@ func DeleteAuthSource(ctx *middleware.Context, params martini.Params) {
 			ctx.Flash.Error("This authentication still has used by some users, you should move them and then delete again.")
 			ctx.Flash.Error("This authentication still has used by some users, you should move them and then delete again.")
 			ctx.Redirect("/admin/auths/" + params["authid"])
 			ctx.Redirect("/admin/auths/" + params["authid"])
 		default:
 		default:
-			ctx.Handle(500, "admin.auths.DeleteAuth", err)
+			ctx.Handle(500, "admin.auths.DeleteAuth(DelLoginSource)", err)
 		}
 		}
 		return
 		return
 	}
 	}

+ 29 - 21
routers/admin/user.go

@@ -5,8 +5,6 @@
 package admin
 package admin
 
 
 import (
 import (
-	"fmt"
-	"strconv"
 	"strings"
 	"strings"
 
 
 	"github.com/go-martini/martini"
 	"github.com/go-martini/martini"
@@ -18,16 +16,21 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	USER_NEW  base.TplName = "admin/user/new"
+	USER_EDIT base.TplName = "admin/user/edit"
+)
+
 func NewUser(ctx *middleware.Context) {
 func NewUser(ctx *middleware.Context) {
 	ctx.Data["Title"] = "New Account"
 	ctx.Data["Title"] = "New Account"
 	ctx.Data["PageIsUsers"] = true
 	ctx.Data["PageIsUsers"] = true
 	auths, err := models.GetAuths()
 	auths, err := models.GetAuths()
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.user.NewUser", err)
+		ctx.Handle(500, "admin.user.NewUser(GetAuths)", err)
 		return
 		return
 	}
 	}
 	ctx.Data["LoginSources"] = auths
 	ctx.Data["LoginSources"] = auths
-	ctx.HTML(200, "admin/users/new")
+	ctx.HTML(200, USER_NEW)
 }
 }
 
 
 func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) {
 func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) {
@@ -35,7 +38,7 @@ func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) {
 	ctx.Data["PageIsUsers"] = true
 	ctx.Data["PageIsUsers"] = true
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "admin/users/new")
+		ctx.HTML(200, USER_NEW)
 		return
 		return
 	}
 	}
 
 
@@ -55,25 +58,25 @@ func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) {
 	}
 	}
 
 
 	if len(form.LoginType) > 0 {
 	if len(form.LoginType) > 0 {
+		// NOTE: need rewrite.
 		fields := strings.Split(form.LoginType, "-")
 		fields := strings.Split(form.LoginType, "-")
-		tp, _ := strconv.Atoi(fields[0])
+		tp, _ := base.StrTo(fields[0]).Int()
 		u.LoginType = models.LoginType(tp)
 		u.LoginType = models.LoginType(tp)
-		u.LoginSource, _ = strconv.ParseInt(fields[1], 10, 64)
+		u.LoginSource, _ = base.StrTo(fields[1]).Int64()
 		u.LoginName = form.LoginName
 		u.LoginName = form.LoginName
-		fmt.Println(u.LoginType, u.LoginSource, u.LoginName)
 	}
 	}
 
 
 	var err error
 	var err error
-	if u, err = models.RegisterUser(u); err != nil {
+	if u, err = models.CreateUser(u); err != nil {
 		switch err {
 		switch err {
 		case models.ErrUserAlreadyExist:
 		case models.ErrUserAlreadyExist:
-			ctx.RenderWithErr("Username has been already taken", "admin/users/new", &form)
+			ctx.RenderWithErr("Username has been already taken", USER_NEW, &form)
 		case models.ErrEmailAlreadyUsed:
 		case models.ErrEmailAlreadyUsed:
-			ctx.RenderWithErr("E-mail address has been already used", "admin/users/new", &form)
+			ctx.RenderWithErr("E-mail address has been already used", USER_NEW, &form)
 		case models.ErrUserNameIllegal:
 		case models.ErrUserNameIllegal:
-			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "admin/users/new", &form)
+			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), USER_NEW, &form)
 		default:
 		default:
-			ctx.Handle(500, "admin.user.NewUser", err)
+			ctx.Handle(500, "admin.user.NewUser(CreateUser)", err)
 		}
 		}
 		return
 		return
 	}
 	}
@@ -96,18 +99,18 @@ func EditUser(ctx *middleware.Context, params martini.Params) {
 
 
 	u, err := models.GetUserById(int64(uid))
 	u, err := models.GetUserById(int64(uid))
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.user.EditUser", err)
+		ctx.Handle(500, "admin.user.EditUser(GetUserById)", err)
 		return
 		return
 	}
 	}
 
 
 	ctx.Data["User"] = u
 	ctx.Data["User"] = u
 	auths, err := models.GetAuths()
 	auths, err := models.GetAuths()
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.user.NewUser", err)
+		ctx.Handle(500, "admin.user.NewUser(GetAuths)", err)
 		return
 		return
 	}
 	}
 	ctx.Data["LoginSources"] = auths
 	ctx.Data["LoginSources"] = auths
-	ctx.HTML(200, "admin/users/edit")
+	ctx.HTML(200, USER_EDIT)
 }
 }
 
 
 func EditUserPost(ctx *middleware.Context, params martini.Params, form auth.AdminEditUserForm) {
 func EditUserPost(ctx *middleware.Context, params martini.Params, form auth.AdminEditUserForm) {
@@ -116,13 +119,18 @@ func EditUserPost(ctx *middleware.Context, params martini.Params, form auth.Admi
 
 
 	uid, err := base.StrTo(params["userid"]).Int()
 	uid, err := base.StrTo(params["userid"]).Int()
 	if err != nil {
 	if err != nil {
-		ctx.Handle(404, "admin.user.EditUser", err)
+		ctx.Handle(404, "admin.user.EditUserPost", err)
 		return
 		return
 	}
 	}
 
 
 	u, err := models.GetUserById(int64(uid))
 	u, err := models.GetUserById(int64(uid))
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.user.EditUser", err)
+		ctx.Handle(500, "admin.user.EditUserPost(GetUserById)", err)
+		return
+	}
+
+	if ctx.HasError() {
+		ctx.HTML(200, USER_EDIT)
 		return
 		return
 	}
 	}
 
 
@@ -134,7 +142,7 @@ func EditUserPost(ctx *middleware.Context, params martini.Params, form auth.Admi
 	u.IsActive = form.Active
 	u.IsActive = form.Active
 	u.IsAdmin = form.Admin
 	u.IsAdmin = form.Admin
 	if err := models.UpdateUser(u); err != nil {
 	if err := models.UpdateUser(u); err != nil {
-		ctx.Handle(500, "admin.user.EditUser", err)
+		ctx.Handle(500, "admin.user.EditUserPost(UpdateUser)", err)
 		return
 		return
 	}
 	}
 	log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI,
 	log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI,
@@ -152,13 +160,13 @@ func DeleteUser(ctx *middleware.Context, params martini.Params) {
 	//log.Info("delete")
 	//log.Info("delete")
 	uid, err := base.StrTo(params["userid"]).Int()
 	uid, err := base.StrTo(params["userid"]).Int()
 	if err != nil {
 	if err != nil {
-		ctx.Handle(404, "admin.user.EditUser", err)
+		ctx.Handle(404, "admin.user.DeleteUser", err)
 		return
 		return
 	}
 	}
 
 
 	u, err := models.GetUserById(int64(uid))
 	u, err := models.GetUserById(int64(uid))
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "admin.user.EditUser", err)
+		ctx.Handle(500, "admin.user.DeleteUser(GetUserById)", err)
 		return
 		return
 	}
 	}
 
 

+ 6 - 1
routers/dashboard.go

@@ -6,11 +6,16 @@ package routers
 
 
 import (
 import (
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/models"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/routers/user"
 	"github.com/gogits/gogs/routers/user"
 )
 )
 
 
+const (
+	HOME base.TplName = "home"
+)
+
 func Home(ctx *middleware.Context) {
 func Home(ctx *middleware.Context) {
 	if ctx.IsSigned {
 	if ctx.IsSigned {
 		user.Dashboard(ctx)
 		user.Dashboard(ctx)
@@ -40,7 +45,7 @@ func Home(ctx *middleware.Context) {
 		}
 		}
 	}
 	}
 	ctx.Data["Repos"] = repos
 	ctx.Data["Repos"] = repos
-	ctx.HTML(200, "home")
+	ctx.HTML(200, HOME)
 }
 }
 
 
 func NotFound(ctx *middleware.Context) {
 func NotFound(ctx *middleware.Context) {

+ 2 - 1
routers/dev/template.go

@@ -8,6 +8,7 @@ import (
 	"github.com/go-martini/martini"
 	"github.com/go-martini/martini"
 
 
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/models"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
@@ -22,5 +23,5 @@ func TemplatePreview(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["ActiveCodeLives"] = setting.Service.ActiveCodeLives / 60
 	ctx.Data["ActiveCodeLives"] = setting.Service.ActiveCodeLives / 60
 	ctx.Data["ResetPwdCodeLives"] = setting.Service.ResetPwdCodeLives / 60
 	ctx.Data["ResetPwdCodeLives"] = setting.Service.ResetPwdCodeLives / 60
 	ctx.Data["CurDbValue"] = ""
 	ctx.Data["CurDbValue"] = ""
-	ctx.HTML(200, params["_1"])
+	ctx.HTML(200, base.TplName(params["_1"]))
 }
 }

+ 17 - 11
routers/install.go

@@ -26,6 +26,10 @@ import (
 	"github.com/gogits/gogs/modules/social"
 	"github.com/gogits/gogs/modules/social"
 )
 )
 
 
+const (
+	INSTALL base.TplName = "install"
+)
+
 func checkRunMode() {
 func checkRunMode() {
 	switch setting.Cfg.MustValue("", "RUN_MODE") {
 	switch setting.Cfg.MustValue("", "RUN_MODE") {
 	case "prod":
 	case "prod":
@@ -72,6 +76,7 @@ func renderDbOption(ctx *middleware.Context) {
 	ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
 	ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
 }
 }
 
 
+// @router /install [get]
 func Install(ctx *middleware.Context, form auth.InstallForm) {
 func Install(ctx *middleware.Context, form auth.InstallForm) {
 	if setting.InstallLock {
 	if setting.InstallLock {
 		ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
 		ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
@@ -119,12 +124,12 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
 	ctx.Data["CurDbOption"] = curDbOp
 	ctx.Data["CurDbOption"] = curDbOp
 
 
 	auth.AssignForm(form, ctx.Data)
 	auth.AssignForm(form, ctx.Data)
-	ctx.HTML(200, "install")
+	ctx.HTML(200, INSTALL)
 }
 }
 
 
 func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 	if setting.InstallLock {
 	if setting.InstallLock {
-		ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
+		ctx.Handle(404, "install.InstallPost", errors.New("Installation is prohibited"))
 		return
 		return
 	}
 	}
 
 
@@ -135,12 +140,12 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 	ctx.Data["CurDbOption"] = form.Database
 	ctx.Data["CurDbOption"] = form.Database
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "install")
+		ctx.HTML(200, INSTALL)
 		return
 		return
 	}
 	}
 
 
 	if _, err := exec.LookPath("git"); err != nil {
 	if _, err := exec.LookPath("git"); err != nil {
-		ctx.RenderWithErr("Fail to test 'git' command: "+err.Error(), "install", &form)
+		ctx.RenderWithErr("Fail to test 'git' command: "+err.Error(), INSTALL, &form)
 		return
 		return
 	}
 	}
 
 
@@ -158,18 +163,19 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 	// Set test engine.
 	// Set test engine.
 	var x *xorm.Engine
 	var x *xorm.Engine
 	if err := models.NewTestEngine(x); err != nil {
 	if err := models.NewTestEngine(x); err != nil {
+		// NOTE: should use core.QueryDriver (github.com/go-xorm/core)
 		if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
 		if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
 			ctx.RenderWithErr("Your release version does not support SQLite3, please download the official binary version "+
 			ctx.RenderWithErr("Your release version does not support SQLite3, please download the official binary version "+
-				"from http://gogs.io/docs/installation/install_from_binary.md, NOT the gobuild version.", "install", &form)
+				"from http://gogs.io/docs/installation/install_from_binary.md, NOT the gobuild version.", INSTALL, &form)
 		} else {
 		} else {
-			ctx.RenderWithErr("Database setting is not correct: "+err.Error(), "install", &form)
+			ctx.RenderWithErr("Database setting is not correct: "+err.Error(), INSTALL, &form)
 		}
 		}
 		return
 		return
 	}
 	}
 
 
 	// Test repository root path.
 	// Test repository root path.
 	if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
 	if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
-		ctx.RenderWithErr("Repository root path is invalid: "+err.Error(), "install", &form)
+		ctx.RenderWithErr("Repository root path is invalid: "+err.Error(), INSTALL, &form)
 		return
 		return
 	}
 	}
 
 
@@ -180,7 +186,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 	}
 	}
 	// Does not check run user when the install lock is off.
 	// Does not check run user when the install lock is off.
 	if form.RunUser != curUser {
 	if form.RunUser != curUser {
-		ctx.RenderWithErr("Run user isn't the current user: "+form.RunUser+" -> "+curUser, "install", &form)
+		ctx.RenderWithErr("Run user isn't the current user: "+form.RunUser+" -> "+curUser, INSTALL, &form)
 		return
 		return
 	}
 	}
 
 
@@ -214,18 +220,18 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 
 
 	os.MkdirAll("custom/conf", os.ModePerm)
 	os.MkdirAll("custom/conf", os.ModePerm)
 	if err := goconfig.SaveConfigFile(setting.Cfg, path.Join(setting.CustomPath, "conf/app.ini")); err != nil {
 	if err := goconfig.SaveConfigFile(setting.Cfg, path.Join(setting.CustomPath, "conf/app.ini")); err != nil {
-		ctx.RenderWithErr("Fail to save configuration: "+err.Error(), "install", &form)
+		ctx.RenderWithErr("Fail to save configuration: "+err.Error(), INSTALL, &form)
 		return
 		return
 	}
 	}
 
 
 	GlobalInit()
 	GlobalInit()
 
 
 	// Create admin account.
 	// Create admin account.
-	if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd,
+	if _, err := models.CreateUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd,
 		IsAdmin: true, IsActive: true}); err != nil {
 		IsAdmin: true, IsActive: true}); err != nil {
 		if err != models.ErrUserAlreadyExist {
 		if err != models.ErrUserAlreadyExist {
 			setting.InstallLock = false
 			setting.InstallLock = false
-			ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), "install", &form)
+			ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), INSTALL, &form)
 			return
 			return
 		}
 		}
 		log.Info("Admin account already exist")
 		log.Info("Admin account already exist")

+ 152 - 1
routers/org/org.go

@@ -1,11 +1,162 @@
+// 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 org
 package org
 
 
 import (
 import (
 	"github.com/go-martini/martini"
 	"github.com/go-martini/martini"
+
+	"github.com/gogits/gogs/models"
+	"github.com/gogits/gogs/modules/auth"
+	"github.com/gogits/gogs/modules/base"
+	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
+	"github.com/gogits/gogs/routers/user"
+)
+
+const (
+	NEW      base.TplName = "org/new"
+	SETTINGS base.TplName = "org/settings"
 )
 )
 
 
 func Organization(ctx *middleware.Context, params martini.Params) {
 func Organization(ctx *middleware.Context, params martini.Params) {
-	ctx.Data["Title"] = "Organization Name" + params["org"]
+	ctx.Data["Title"] = "Organization " + params["org"]
 	ctx.HTML(200, "org/org")
 	ctx.HTML(200, "org/org")
 }
 }
+
+func Members(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Organization " + params["org"] + " Members"
+	ctx.HTML(200, "org/members")
+}
+
+
+func New(ctx *middleware.Context) {
+	ctx.Data["Title"] = "Create An Organization"
+	ctx.HTML(200, NEW)
+}
+
+func NewPost(ctx *middleware.Context, form auth.CreateOrgForm) {
+	ctx.Data["Title"] = "Create An Organization"
+
+	if ctx.HasError() {
+		ctx.HTML(200, NEW)
+		return
+	}
+
+	org := &models.User{
+		Name:     form.OrgName,
+		Email:    form.Email,
+		IsActive: true, // NOTE: may need to set false when require e-mail confirmation.
+		Type:     models.ORGANIZATION,
+	}
+
+	var err error
+	if org, err = models.CreateOrganization(org, ctx.User); err != nil {
+		switch err {
+		case models.ErrUserAlreadyExist:
+			ctx.Data["Err_OrgName"] = true
+			ctx.RenderWithErr("Organization name has been already taken", NEW, &form)
+		case models.ErrEmailAlreadyUsed:
+			ctx.Data["Err_Email"] = true
+			ctx.RenderWithErr("E-mail address has been already used", NEW, &form)
+		case models.ErrUserNameIllegal:
+			ctx.Data["Err_OrgName"] = true
+			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), NEW, &form)
+		default:
+			ctx.Handle(500, "user.NewPost(CreateUser)", err)
+		}
+		return
+	}
+	log.Trace("%s Organization created: %s", ctx.Req.RequestURI, org.Name)
+
+	ctx.Redirect("/org/" + form.OrgName + "/dashboard")
+}
+
+func Dashboard(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Dashboard"
+	ctx.Data["PageIsUserDashboard"] = true
+	ctx.Data["PageIsOrgDashboard"] = true
+
+	org, err := models.GetUserByName(params["org"])
+	if err != nil {
+		if err == models.ErrUserNotExist {
+			ctx.Handle(404, "org.Dashboard(GetUserByName)", err)
+		} else {
+			ctx.Handle(500, "org.Dashboard(GetUserByName)", err)
+		}
+		return
+	}
+
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+		return
+	}
+	ctx.Data["Orgs"] = ctx.User.Orgs
+	ctx.Data["ContextUser"] = org
+
+	ctx.Data["MyRepos"], err = models.GetRepositories(org.Id, true)
+	if err != nil {
+		ctx.Handle(500, "org.Dashboard(GetRepositories)", err)
+		return
+	}
+
+	actions, err := models.GetFeeds(org.Id, 0, false)
+	if err != nil {
+		ctx.Handle(500, "org.Dashboard(GetFeeds)", err)
+		return
+	}
+	ctx.Data["Feeds"] = actions
+
+	ctx.HTML(200, user.DASHBOARD)
+}
+
+func Settings(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Settings"
+
+	org, err := models.GetUserByName(params["org"])
+	if err != nil {
+		if err == models.ErrUserNotExist {
+			ctx.Handle(404, "org.Settings(GetUserByName)", err)
+		} else {
+			ctx.Handle(500, "org.Settings(GetUserByName)", err)
+		}
+		return
+	}
+	ctx.Data["Org"] = org
+
+	ctx.HTML(200, SETTINGS)
+}
+
+func SettingsPost(ctx *middleware.Context, params martini.Params, form auth.OrgSettingForm) {
+	ctx.Data["Title"] = "Settings"
+
+	org, err := models.GetUserByName(params["org"])
+	if err != nil {
+		if err == models.ErrUserNotExist {
+			ctx.Handle(404, "org.SettingsPost(GetUserByName)", err)
+		} else {
+			ctx.Handle(500, "org.SettingsPost(GetUserByName)", err)
+		}
+		return
+	}
+	ctx.Data["Org"] = org
+
+	if ctx.HasError() {
+		ctx.HTML(200, SETTINGS)
+		return
+	}
+
+	org.FullName = form.DisplayName
+	org.Email = form.Email
+	org.Description = form.Description
+	org.Website = form.Website
+	org.Location = form.Location
+	if err = models.UpdateUser(org); err != nil {
+		ctx.Handle(500, "org.SettingsPost(UpdateUser)", err)
+		return
+	}
+	log.Trace("%s Organization setting updated: %s", ctx.Req.RequestURI, org.LowerName)
+	ctx.Flash.Success("Organization profile has been successfully updated.")
+	ctx.Redirect("/org/" + org.Name + "/settings")
+}

+ 21 - 0
routers/org/teams.go

@@ -0,0 +1,21 @@
+package org
+
+import (
+	"github.com/go-martini/martini"
+	"github.com/gogits/gogs/modules/middleware"
+)
+
+func Teams(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Organization "+params["org"]+" Teams"
+	ctx.HTML(200, "org/teams")
+}
+
+func NewTeam(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Organization "+params["org"]+" New Team"
+	ctx.HTML(200, "org/new_team")
+}
+
+func EditTeam(ctx *middleware.Context, params martini.Params){
+	ctx.Data["Title"] = "Organization "+params["org"]+" Edit Team"
+	ctx.HTML(200,"org/edit_team")
+}

+ 8 - 3
routers/repo/branch.go

@@ -7,22 +7,27 @@ package repo
 import (
 import (
 	"github.com/go-martini/martini"
 	"github.com/go-martini/martini"
 
 
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	BRANCH base.TplName = "repo/branch"
+)
+
 func Branches(ctx *middleware.Context, params martini.Params) {
 func Branches(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Title"] = "Branches"
 	ctx.Data["Title"] = "Branches"
 	ctx.Data["IsRepoToolbarBranches"] = true
 	ctx.Data["IsRepoToolbarBranches"] = true
 
 
 	brs, err := ctx.Repo.GitRepo.GetBranches()
 	brs, err := ctx.Repo.GitRepo.GetBranches()
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "repo.Branches", err)
+		ctx.Handle(500, "repo.Branches(GetBranches)", err)
 		return
 		return
 	} else if len(brs) == 0 {
 	} else if len(brs) == 0 {
-		ctx.Handle(404, "repo.Branches", nil)
+		ctx.Handle(404, "repo.Branches(GetBranches)", nil)
 		return
 		return
 	}
 	}
 
 
 	ctx.Data["Branches"] = brs
 	ctx.Data["Branches"] = brs
-	ctx.HTML(200, "repo/branches")
+	ctx.HTML(200, BRANCH)
 }
 }

+ 48 - 44
routers/repo/commit.go

@@ -14,6 +14,11 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	COMMITS base.TplName = "repo/commits"
+	DIFF    base.TplName = "repo/diff"
+)
+
 func Commits(ctx *middleware.Context, params martini.Params) {
 func Commits(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["IsRepoToolbarCommits"] = true
 	ctx.Data["IsRepoToolbarCommits"] = true
 
 
@@ -22,10 +27,10 @@ func Commits(ctx *middleware.Context, params martini.Params) {
 
 
 	brs, err := ctx.Repo.GitRepo.GetBranches()
 	brs, err := ctx.Repo.GitRepo.GetBranches()
 	if err != nil {
 	if err != nil {
-		ctx.Handle(500, "repo.Commits", err)
+		ctx.Handle(500, "repo.Commits(GetBranches)", err)
 		return
 		return
 	} else if len(brs) == 0 {
 	} else if len(brs) == 0 {
-		ctx.Handle(404, "repo.Commits", nil)
+		ctx.Handle(404, "repo.Commits(GetBranches)", nil)
 		return
 		return
 	}
 	}
 
 
@@ -61,7 +66,43 @@ func Commits(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["CommitCount"] = commitsCount
 	ctx.Data["CommitCount"] = commitsCount
 	ctx.Data["LastPageNum"] = lastPage
 	ctx.Data["LastPageNum"] = lastPage
 	ctx.Data["NextPageNum"] = nextPage
 	ctx.Data["NextPageNum"] = nextPage
-	ctx.HTML(200, "repo/commits")
+	ctx.HTML(200, COMMITS)
+}
+
+func SearchCommits(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["IsSearchPage"] = true
+	ctx.Data["IsRepoToolbarCommits"] = true
+
+	keyword := ctx.Query("q")
+	if len(keyword) == 0 {
+		ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchName)
+		return
+	}
+
+	userName := params["username"]
+	repoName := params["reponame"]
+
+	brs, err := ctx.Repo.GitRepo.GetBranches()
+	if err != nil {
+		ctx.Handle(500, "repo.SearchCommits(GetBranches)", err)
+		return
+	} else if len(brs) == 0 {
+		ctx.Handle(404, "repo.SearchCommits(GetBranches)", nil)
+		return
+	}
+
+	commits, err := ctx.Repo.Commit.SearchCommits(keyword)
+	if err != nil {
+		ctx.Handle(500, "repo.SearchCommits(SearchCommits)", err)
+		return
+	}
+
+	ctx.Data["Keyword"] = keyword
+	ctx.Data["Username"] = userName
+	ctx.Data["Reponame"] = repoName
+	ctx.Data["CommitCount"] = commits.Len()
+	ctx.Data["Commits"] = commits
+	ctx.HTML(200, COMMITS)
 }
 }
 
 
 func Diff(ctx *middleware.Context, params martini.Params) {
 func Diff(ctx *middleware.Context, params martini.Params) {
@@ -75,7 +116,7 @@ func Diff(ctx *middleware.Context, params martini.Params) {
 
 
 	diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
 	diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
 	if err != nil {
 	if err != nil {
-		ctx.Handle(404, "repo.Diff", err)
+		ctx.Handle(404, "repo.Diff(GetDiff)", err)
 		return
 		return
 	}
 	}
 
 
@@ -119,43 +160,7 @@ func Diff(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 	ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
 	ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
 	ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId)
 	ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", commitId)
-	ctx.HTML(200, "repo/diff")
-}
-
-func SearchCommits(ctx *middleware.Context, params martini.Params) {
-	ctx.Data["IsSearchPage"] = true
-	ctx.Data["IsRepoToolbarCommits"] = true
-
-	keyword := ctx.Query("q")
-	if len(keyword) == 0 {
-		ctx.Redirect(ctx.Repo.RepoLink + "/commits/" + ctx.Repo.BranchName)
-		return
-	}
-
-	userName := params["username"]
-	repoName := params["reponame"]
-
-	brs, err := ctx.Repo.GitRepo.GetBranches()
-	if err != nil {
-		ctx.Handle(500, "repo.SearchCommits(GetBranches)", err)
-		return
-	} else if len(brs) == 0 {
-		ctx.Handle(404, "repo.SearchCommits(GetBranches)", nil)
-		return
-	}
-
-	commits, err := ctx.Repo.Commit.SearchCommits(keyword)
-	if err != nil {
-		ctx.Handle(500, "repo.SearchCommits(SearchCommits)", err)
-		return
-	}
-
-	ctx.Data["Keyword"] = keyword
-	ctx.Data["Username"] = userName
-	ctx.Data["Reponame"] = repoName
-	ctx.Data["CommitCount"] = commits.Len()
-	ctx.Data["Commits"] = commits
-	ctx.HTML(200, "repo/commits")
+	ctx.HTML(200, DIFF)
 }
 }
 
 
 func FileHistory(ctx *middleware.Context, params martini.Params) {
 func FileHistory(ctx *middleware.Context, params martini.Params) {
@@ -184,8 +189,7 @@ func FileHistory(ctx *middleware.Context, params martini.Params) {
 	if err != nil {
 	if err != nil {
 		ctx.Handle(500, "repo.FileHistory(GetCommitsCount)", err)
 		ctx.Handle(500, "repo.FileHistory(GetCommitsCount)", err)
 		return
 		return
-	}
-	if commitsCount == 0 {
+	} else if commitsCount == 0 {
 		ctx.Handle(404, "repo.FileHistory", nil)
 		ctx.Handle(404, "repo.FileHistory", nil)
 		return
 		return
 	}
 	}
@@ -217,5 +221,5 @@ func FileHistory(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["CommitCount"] = commitsCount
 	ctx.Data["CommitCount"] = commitsCount
 	ctx.Data["LastPageNum"] = lastPage
 	ctx.Data["LastPageNum"] = lastPage
 	ctx.Data["NextPageNum"] = nextPage
 	ctx.Data["NextPageNum"] = nextPage
-	ctx.HTML(200, "repo/commits")
+	ctx.HTML(200, COMMITS)
 }
 }

+ 4 - 4
routers/repo/http.go

@@ -107,9 +107,9 @@ func Http(ctx *middleware.Context, params martini.Params) {
 		}
 		}
 
 
 		if !isPublicPull {
 		if !isPublicPull {
-			var tp = models.AU_WRITABLE
+			var tp = models.WRITABLE
 			if isPull {
 			if isPull {
-				tp = models.AU_READABLE
+				tp = models.READABLE
 			}
 			}
 
 
 			has, err := models.HasAccess(authUsername, username+"/"+reponame, tp)
 			has, err := models.HasAccess(authUsername, username+"/"+reponame, tp)
@@ -117,8 +117,8 @@ func Http(ctx *middleware.Context, params martini.Params) {
 				ctx.Handle(401, "no basic auth and digit auth", nil)
 				ctx.Handle(401, "no basic auth and digit auth", nil)
 				return
 				return
 			} else if !has {
 			} else if !has {
-				if tp == models.AU_READABLE {
-					has, err = models.HasAccess(authUsername, username+"/"+reponame, models.AU_WRITABLE)
+				if tp == models.READABLE {
+					has, err = models.HasAccess(authUsername, username+"/"+reponame, models.WRITABLE)
 					if err != nil || !has {
 					if err != nil || !has {
 						ctx.Handle(401, "no basic auth and digit auth", nil)
 						ctx.Handle(401, "no basic auth and digit auth", nil)
 						return
 						return

+ 27 - 7
routers/repo/issue.go

@@ -22,6 +22,16 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
+const (
+	ISSUES       base.TplName = "repo/issue/list"
+	ISSUE_CREATE base.TplName = "repo/issue/create"
+	ISSUE_VIEW   base.TplName = "repo/issue/view"
+
+	MILESTONE      base.TplName = "repo/issue/milestone"
+	MILESTONE_NEW  base.TplName = "repo/issue/milestone_new"
+	MILESTONE_EDIT base.TplName = "repo/issue/milestone_edit"
+)
+
 func Issues(ctx *middleware.Context) {
 func Issues(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Issues"
 	ctx.Data["Title"] = "Issues"
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
@@ -134,7 +144,7 @@ func Issues(ctx *middleware.Context) {
 	} else {
 	} else {
 		ctx.Data["ShowCount"] = issueStats.OpenCount
 		ctx.Data["ShowCount"] = issueStats.OpenCount
 	}
 	}
-	ctx.HTML(200, "issue/list")
+	ctx.HTML(200, ISSUES)
 }
 }
 
 
 func CreateIssue(ctx *middleware.Context, params martini.Params) {
 func CreateIssue(ctx *middleware.Context, params martini.Params) {
@@ -161,7 +171,7 @@ func CreateIssue(ctx *middleware.Context, params martini.Params) {
 		return
 		return
 	}
 	}
 	ctx.Data["Collaborators"] = us
 	ctx.Data["Collaborators"] = us
-	ctx.HTML(200, "issue/create")
+	ctx.HTML(200, ISSUE_CREATE)
 }
 }
 
 
 func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
 func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
@@ -190,7 +200,7 @@ func CreateIssuePost(ctx *middleware.Context, params martini.Params, form auth.C
 	ctx.Data["Collaborators"] = us
 	ctx.Data["Collaborators"] = us
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "issue/create")
+		ctx.HTML(200, ISSUE_CREATE)
 		return
 		return
 	}
 	}
 
 
@@ -392,7 +402,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
 	ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = false
 	ctx.Data["IsRepoToolbarIssuesList"] = false
-	ctx.HTML(200, "issue/view")
+	ctx.HTML(200, ISSUE_VIEW)
 }
 }
 
 
 func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
 func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
@@ -794,14 +804,14 @@ func Milestones(ctx *middleware.Context) {
 	} else {
 	} else {
 		ctx.Data["State"] = "open"
 		ctx.Data["State"] = "open"
 	}
 	}
-	ctx.HTML(200, "issue/milestone")
+	ctx.HTML(200, MILESTONE)
 }
 }
 
 
 func NewMilestone(ctx *middleware.Context) {
 func NewMilestone(ctx *middleware.Context) {
 	ctx.Data["Title"] = "New Milestone"
 	ctx.Data["Title"] = "New Milestone"
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
-	ctx.HTML(200, "issue/milestone_new")
+	ctx.HTML(200, MILESTONE_NEW)
 }
 }
 
 
 func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
 func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
@@ -809,6 +819,11 @@ func NewMilestonePost(ctx *middleware.Context, form auth.CreateMilestoneForm) {
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssues"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
 	ctx.Data["IsRepoToolbarIssuesList"] = true
 
 
+	if ctx.HasError() {
+		ctx.HTML(200, MILESTONE_NEW)
+		return
+	}
+
 	var deadline time.Time
 	var deadline time.Time
 	var err error
 	var err error
 	if len(form.Deadline) == 0 {
 	if len(form.Deadline) == 0 {
@@ -890,7 +905,7 @@ func UpdateMilestone(ctx *middleware.Context, params martini.Params) {
 	}
 	}
 	ctx.Data["Milestone"] = mile
 	ctx.Data["Milestone"] = mile
 
 
-	ctx.HTML(200, "issue/milestone_edit")
+	ctx.HTML(200, MILESTONE_EDIT)
 }
 }
 
 
 func UpdateMilestonePost(ctx *middleware.Context, params martini.Params, form auth.CreateMilestoneForm) {
 func UpdateMilestonePost(ctx *middleware.Context, params martini.Params, form auth.CreateMilestoneForm) {
@@ -914,6 +929,11 @@ func UpdateMilestonePost(ctx *middleware.Context, params martini.Params, form au
 		return
 		return
 	}
 	}
 
 
+	if ctx.HasError() {
+		ctx.HTML(200, MILESTONE_EDIT)
+		return
+	}
+
 	var deadline time.Time
 	var deadline time.Time
 	if len(form.Deadline) == 0 {
 	if len(form.Deadline) == 0 {
 		form.Deadline = "12/31/9999"
 		form.Deadline = "12/31/9999"

+ 6 - 1
routers/repo/pull.go

@@ -7,10 +7,15 @@ package repo
 import (
 import (
 	"github.com/go-martini/martini"
 	"github.com/go-martini/martini"
 
 
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	PULLS base.TplName = "repo/pulls"
+)
+
 func Pulls(ctx *middleware.Context, params martini.Params) {
 func Pulls(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["IsRepoToolbarPulls"] = true
 	ctx.Data["IsRepoToolbarPulls"] = true
-	ctx.HTML(200, "repo/pulls")
+	ctx.HTML(200, PULLS)
 }
 }

+ 15 - 4
routers/repo/release.go

@@ -14,6 +14,12 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	RELEASES     base.TplName = "repo/release/list"
+	RELEASE_NEW  base.TplName = "repo/release/new"
+	RELEASE_EDIT base.TplName = "repo/release/edit"
+)
+
 func Releases(ctx *middleware.Context) {
 func Releases(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Releases"
 	ctx.Data["Title"] = "Releases"
 	ctx.Data["IsRepoToolbarReleases"] = true
 	ctx.Data["IsRepoToolbarReleases"] = true
@@ -100,7 +106,7 @@ func Releases(ctx *middleware.Context) {
 	}
 	}
 	models.SortReleases(tags)
 	models.SortReleases(tags)
 	ctx.Data["Releases"] = tags
 	ctx.Data["Releases"] = tags
-	ctx.HTML(200, "release/list")
+	ctx.HTML(200, RELEASES)
 }
 }
 
 
 func NewRelease(ctx *middleware.Context) {
 func NewRelease(ctx *middleware.Context) {
@@ -112,7 +118,7 @@ func NewRelease(ctx *middleware.Context) {
 	ctx.Data["Title"] = "New Release"
 	ctx.Data["Title"] = "New Release"
 	ctx.Data["IsRepoToolbarReleases"] = true
 	ctx.Data["IsRepoToolbarReleases"] = true
 	ctx.Data["IsRepoReleaseNew"] = true
 	ctx.Data["IsRepoReleaseNew"] = true
-	ctx.HTML(200, "release/new")
+	ctx.HTML(200, RELEASE_NEW)
 }
 }
 
 
 func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
 func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
@@ -126,7 +132,7 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
 	ctx.Data["IsRepoReleaseNew"] = true
 	ctx.Data["IsRepoReleaseNew"] = true
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "release/new")
+		ctx.HTML(200, RELEASE_NEW)
 		return
 		return
 	}
 	}
 
 
@@ -187,7 +193,7 @@ func EditRelease(ctx *middleware.Context, params martini.Params) {
 
 
 	ctx.Data["Title"] = "Edit Release"
 	ctx.Data["Title"] = "Edit Release"
 	ctx.Data["IsRepoToolbarReleases"] = true
 	ctx.Data["IsRepoToolbarReleases"] = true
-	ctx.HTML(200, "release/edit")
+	ctx.HTML(200, RELEASE_EDIT)
 }
 }
 
 
 func EditReleasePost(ctx *middleware.Context, params martini.Params, form auth.EditReleaseForm) {
 func EditReleasePost(ctx *middleware.Context, params martini.Params, form auth.EditReleaseForm) {
@@ -208,6 +214,11 @@ func EditReleasePost(ctx *middleware.Context, params martini.Params, form auth.E
 	}
 	}
 	ctx.Data["Release"] = rel
 	ctx.Data["Release"] = rel
 
 
+	if ctx.HasError() {
+		ctx.HTML(200, RELEASE_EDIT)
+		return
+	}
+
 	ctx.Data["Title"] = "Edit Release"
 	ctx.Data["Title"] = "Edit Release"
 	ctx.Data["IsRepoToolbarReleases"] = true
 	ctx.Data["IsRepoToolbarReleases"] = true
 
 

+ 84 - 22
routers/repo/repo.go

@@ -25,12 +25,25 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	CREATE  base.TplName = "repo/create"
+	MIGRATE base.TplName = "repo/migrate"
+	SINGLE  base.TplName = "repo/single"
+)
+
 func Create(ctx *middleware.Context) {
 func Create(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Create repository"
 	ctx.Data["Title"] = "Create repository"
 	ctx.Data["PageIsNewRepo"] = true
 	ctx.Data["PageIsNewRepo"] = true
 	ctx.Data["LanguageIgns"] = models.LanguageIgns
 	ctx.Data["LanguageIgns"] = models.LanguageIgns
 	ctx.Data["Licenses"] = models.Licenses
 	ctx.Data["Licenses"] = models.Licenses
-	ctx.HTML(200, "repo/create")
+
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+		return
+	}
+	ctx.Data["Orgs"] = ctx.User.Orgs
+
+	ctx.HTML(200, CREATE)
 }
 }
 
 
 func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
 func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
@@ -39,76 +52,125 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
 	ctx.Data["LanguageIgns"] = models.LanguageIgns
 	ctx.Data["LanguageIgns"] = models.LanguageIgns
 	ctx.Data["Licenses"] = models.Licenses
 	ctx.Data["Licenses"] = models.Licenses
 
 
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "home.CreatePost(GetOrganizations)", err)
+		return
+	}
+	ctx.Data["Orgs"] = ctx.User.Orgs
+
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "repo/create")
+		ctx.HTML(200, CREATE)
 		return
 		return
 	}
 	}
 
 
-	repo, err := models.CreateRepository(ctx.User, form.RepoName, form.Description,
+	u := ctx.User
+	// Not equal means current user is an organization.
+	if u.Id != form.Uid {
+		var err error
+		u, err = models.GetUserById(form.Uid)
+		if err != nil {
+			if err == models.ErrUserNotExist {
+				ctx.Handle(404, "home.CreatePost(GetUserById)", err)
+			} else {
+				ctx.Handle(500, "home.CreatePost(GetUserById)", err)
+			}
+			return
+		}
+	}
+
+	repo, err := models.CreateRepository(u, form.RepoName, form.Description,
 		form.Language, form.License, form.Private, false, form.InitReadme)
 		form.Language, form.License, form.Private, false, form.InitReadme)
 	if err == nil {
 	if err == nil {
-		log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
-		ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
+		log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName)
+		ctx.Redirect("/" + u.Name + "/" + form.RepoName)
 		return
 		return
 	} else if err == models.ErrRepoAlreadyExist {
 	} else if err == models.ErrRepoAlreadyExist {
-		ctx.RenderWithErr("Repository name has already been used", "repo/create", &form)
+		ctx.RenderWithErr("Repository name has already been used", CREATE, &form)
 		return
 		return
 	} else if err == models.ErrRepoNameIllegal {
 	} else if err == models.ErrRepoNameIllegal {
-		ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/create", &form)
+		ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), CREATE, &form)
 		return
 		return
 	}
 	}
 
 
 	if repo != nil {
 	if repo != nil {
-		if errDelete := models.DeleteRepository(ctx.User.Id, repo.Id, ctx.User.Name); errDelete != nil {
-			log.Error("repo.MigratePost(CreatePost): %v", errDelete)
+		if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
+			log.Error("repo.CreatePost(DeleteRepository): %v", errDelete)
 		}
 		}
 	}
 	}
-	ctx.Handle(500, "repo.Create", err)
+	ctx.Handle(500, "repo.CreatePost(CreateRepository)", err)
 }
 }
 
 
 func Migrate(ctx *middleware.Context) {
 func Migrate(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Migrate repository"
 	ctx.Data["Title"] = "Migrate repository"
 	ctx.Data["PageIsNewRepo"] = true
 	ctx.Data["PageIsNewRepo"] = true
-	ctx.HTML(200, "repo/migrate")
+
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "home.Migrate(GetOrganizations)", err)
+		return
+	}
+	ctx.Data["Orgs"] = ctx.User.Orgs
+
+	ctx.HTML(200, MIGRATE)
 }
 }
 
 
 func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
 func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
 	ctx.Data["Title"] = "Migrate repository"
 	ctx.Data["Title"] = "Migrate repository"
 	ctx.Data["PageIsNewRepo"] = true
 	ctx.Data["PageIsNewRepo"] = true
 
 
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "home.MigratePost(GetOrganizations)", err)
+		return
+	}
+	ctx.Data["Orgs"] = ctx.User.Orgs
+
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "repo/migrate")
+		ctx.HTML(200, MIGRATE)
 		return
 		return
 	}
 	}
 
 
+	u := ctx.User
+	// Not equal means current user is an organization.
+	if u.Id != form.Uid {
+		var err error
+		u, err = models.GetUserById(form.Uid)
+		if err != nil {
+			if err == models.ErrUserNotExist {
+				ctx.Handle(404, "home.MigratePost(GetUserById)", err)
+			} else {
+				ctx.Handle(500, "home.MigratePost(GetUserById)", err)
+			}
+			return
+		}
+	}
+
 	authStr := strings.Replace(fmt.Sprintf("://%s:%s",
 	authStr := strings.Replace(fmt.Sprintf("://%s:%s",
 		form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
 		form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
 	url := strings.Replace(form.Url, "://", authStr+"@", 1)
 	url := strings.Replace(form.Url, "://", authStr+"@", 1)
-	repo, err := models.MigrateRepository(ctx.User, form.RepoName, form.Description, form.Private,
+	repo, err := models.MigrateRepository(u, form.RepoName, form.Description, form.Private,
 		form.Mirror, url)
 		form.Mirror, url)
 	if err == nil {
 	if err == nil {
-		log.Trace("%s Repository migrated: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName)
-		ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName)
+		log.Trace("%s Repository migrated: %s/%s", ctx.Req.RequestURI, u.LowerName, form.RepoName)
+		ctx.Redirect("/" + u.Name + "/" + form.RepoName)
 		return
 		return
 	} else if err == models.ErrRepoAlreadyExist {
 	} else if err == models.ErrRepoAlreadyExist {
-		ctx.RenderWithErr("Repository name has already been used", "repo/migrate", &form)
+		ctx.RenderWithErr("Repository name has already been used", MIGRATE, &form)
 		return
 		return
 	} else if err == models.ErrRepoNameIllegal {
 	} else if err == models.ErrRepoNameIllegal {
-		ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/migrate", &form)
+		ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), MIGRATE, &form)
 		return
 		return
 	}
 	}
 
 
 	if repo != nil {
 	if repo != nil {
-		if errDelete := models.DeleteRepository(ctx.User.Id, repo.Id, ctx.User.Name); errDelete != nil {
+		if errDelete := models.DeleteRepository(u.Id, repo.Id, u.Name); errDelete != nil {
 			log.Error("repo.MigratePost(DeleteRepository): %v", errDelete)
 			log.Error("repo.MigratePost(DeleteRepository): %v", errDelete)
 		}
 		}
 	}
 	}
 
 
 	if strings.Contains(err.Error(), "Authentication failed") {
 	if strings.Contains(err.Error(), "Authentication failed") {
-		ctx.RenderWithErr(err.Error(), "repo/migrate", &form)
+		ctx.RenderWithErr(err.Error(), MIGRATE, &form)
 		return
 		return
 	}
 	}
-	ctx.Handle(500, "repo.Migrate", err)
+	ctx.Handle(500, "repo.Migrate(MigrateRepository)", err)
 }
 }
 
 
 func Single(ctx *middleware.Context, params martini.Params) {
 func Single(ctx *middleware.Context, params martini.Params) {
@@ -291,7 +353,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Treenames"] = treenames
 	ctx.Data["Treenames"] = treenames
 	ctx.Data["TreePath"] = treePath
 	ctx.Data["TreePath"] = treePath
 	ctx.Data["BranchLink"] = branchLink
 	ctx.Data["BranchLink"] = branchLink
-	ctx.HTML(200, "repo/single")
+	ctx.HTML(200, SINGLE)
 }
 }
 
 
 func basicEncode(username, password string) string {
 func basicEncode(username, password string) string {
@@ -318,7 +380,7 @@ func basicDecode(encoded string) (user string, name string, err error) {
 func authRequired(ctx *middleware.Context) {
 func authRequired(ctx *middleware.Context) {
 	ctx.ResponseWriter.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
 	ctx.ResponseWriter.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
 	ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
 	ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
-	ctx.HTML(401, fmt.Sprintf("status/401"))
+	ctx.HTML(401, base.TplName("status/401"))
 }
 }
 
 
 func Action(ctx *middleware.Context, params martini.Params) {
 func Action(ctx *middleware.Context, params martini.Params) {

+ 43 - 28
routers/repo/setting.go

@@ -20,10 +20,19 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
+const (
+	SETTING       base.TplName = "repo/setting"
+	COLLABORATION base.TplName = "repo/collaboration"
+
+	HOOKS     base.TplName = "repo/hooks"
+	HOOK_ADD  base.TplName = "repo/hook_add"
+	HOOK_EDIT base.TplName = "repo/hook_edit"
+)
+
 func Setting(ctx *middleware.Context) {
 func Setting(ctx *middleware.Context) {
 	ctx.Data["IsRepoToolbarSetting"] = true
 	ctx.Data["IsRepoToolbarSetting"] = true
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - settings"
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - settings"
-	ctx.HTML(200, "repo/setting")
+	ctx.HTML(200, SETTING)
 }
 }
 
 
 func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
@@ -32,7 +41,7 @@ func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 	switch ctx.Query("action") {
 	switch ctx.Query("action") {
 	case "update":
 	case "update":
 		if ctx.HasError() {
 		if ctx.HasError() {
-			ctx.HTML(200, "repo/setting")
+			ctx.HTML(200, SETTING)
 			return
 			return
 		}
 		}
 
 
@@ -44,7 +53,7 @@ func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 				ctx.Handle(500, "setting.SettingPost(update: check existence)", err)
 				ctx.Handle(500, "setting.SettingPost(update: check existence)", err)
 				return
 				return
 			} else if isExist {
 			} else if isExist {
-				ctx.RenderWithErr("Repository name has been taken in your repositories.", "repo/setting", nil)
+				ctx.RenderWithErr("Repository name has been taken in your repositories.", SETTING, nil)
 				return
 				return
 			} else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
 			} else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
 				ctx.Handle(500, "setting.SettingPost(change repository name)", err)
 				ctx.Handle(500, "setting.SettingPost(change repository name)", err)
@@ -84,7 +93,7 @@ func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 		ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
 		ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name))
 	case "transfer":
 	case "transfer":
 		if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
 		if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
-			ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil)
+			ctx.RenderWithErr("Please make sure you entered repository name is correct.", SETTING, nil)
 			return
 			return
 		} else if ctx.Repo.Repository.IsMirror {
 		} else if ctx.Repo.Repository.IsMirror {
 			ctx.Error(404)
 			ctx.Error(404)
@@ -98,7 +107,7 @@ func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 			ctx.Handle(500, "setting.SettingPost(transfer: check existence)", err)
 			ctx.Handle(500, "setting.SettingPost(transfer: check existence)", err)
 			return
 			return
 		} else if !isExist {
 		} else if !isExist {
-			ctx.RenderWithErr("Please make sure you entered owner name is correct.", "repo/setting", nil)
+			ctx.RenderWithErr("Please make sure you entered owner name is correct.", SETTING, nil)
 			return
 			return
 		} else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
 		} else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
 			ctx.Handle(500, "setting.SettingPost(transfer repository)", err)
 			ctx.Handle(500, "setting.SettingPost(transfer repository)", err)
@@ -109,7 +118,7 @@ func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) {
 		ctx.Redirect("/")
 		ctx.Redirect("/")
 	case "delete":
 	case "delete":
 		if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
 		if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") {
-			ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil)
+			ctx.RenderWithErr("Please make sure you entered repository name is correct.", SETTING, nil)
 			return
 			return
 		}
 		}
 
 
@@ -156,7 +165,7 @@ func Collaboration(ctx *middleware.Context) {
 	}
 	}
 
 
 	ctx.Data["Collaborators"] = us
 	ctx.Data["Collaborators"] = us
-	ctx.HTML(200, "repo/collaboration")
+	ctx.HTML(200, COLLABORATION)
 }
 }
 
 
 func CollaborationPost(ctx *middleware.Context) {
 func CollaborationPost(ctx *middleware.Context) {
@@ -166,7 +175,7 @@ func CollaborationPost(ctx *middleware.Context) {
 		ctx.Redirect(ctx.Req.RequestURI)
 		ctx.Redirect(ctx.Req.RequestURI)
 		return
 		return
 	}
 	}
-	has, err := models.HasAccess(name, repoLink, models.AU_WRITABLE)
+	has, err := models.HasAccess(name, repoLink, models.WRITABLE)
 	if err != nil {
 	if err != nil {
 		ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err)
 		ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err)
 		return
 		return
@@ -187,7 +196,7 @@ func CollaborationPost(ctx *middleware.Context) {
 	}
 	}
 
 
 	if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink,
 	if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink,
-		Mode: models.AU_WRITABLE}); err != nil {
+		Mode: models.WRITABLE}); err != nil {
 		ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err)
 		ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err)
 		return
 		return
 	}
 	}
@@ -226,13 +235,13 @@ func WebHooks(ctx *middleware.Context) {
 	}
 	}
 
 
 	ctx.Data["Webhooks"] = ws
 	ctx.Data["Webhooks"] = ws
-	ctx.HTML(200, "repo/hooks")
+	ctx.HTML(200, HOOKS)
 }
 }
 
 
 func WebHooksAdd(ctx *middleware.Context) {
 func WebHooksAdd(ctx *middleware.Context) {
 	ctx.Data["IsRepoToolbarWebHooks"] = true
 	ctx.Data["IsRepoToolbarWebHooks"] = true
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
-	ctx.HTML(200, "repo/hooks_add")
+	ctx.HTML(200, HOOK_ADD)
 }
 }
 
 
 func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
 func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
@@ -240,7 +249,7 @@ func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook"
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "repo/hooks_add")
+		ctx.HTML(200, HOOK_ADD)
 		return
 		return
 	}
 	}
 
 
@@ -293,40 +302,46 @@ func WebHooksEdit(ctx *middleware.Context, params martini.Params) {
 
 
 	w.GetEvent()
 	w.GetEvent()
 	ctx.Data["Webhook"] = w
 	ctx.Data["Webhook"] = w
-	ctx.HTML(200, "repo/hooks_edit")
+	ctx.HTML(200, HOOK_EDIT)
 }
 }
 
 
 func WebHooksEditPost(ctx *middleware.Context, params martini.Params, form auth.NewWebhookForm) {
 func WebHooksEditPost(ctx *middleware.Context, params martini.Params, form auth.NewWebhookForm) {
 	ctx.Data["IsRepoToolbarWebHooks"] = true
 	ctx.Data["IsRepoToolbarWebHooks"] = true
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook"
 	ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook"
 
 
-	if ctx.HasError() {
-		ctx.HTML(200, "repo/hooks_add")
-		return
-	}
-
 	hookId, _ := base.StrTo(params["id"]).Int64()
 	hookId, _ := base.StrTo(params["id"]).Int64()
 	if hookId == 0 {
 	if hookId == 0 {
 		ctx.Handle(404, "setting.WebHooksEditPost", nil)
 		ctx.Handle(404, "setting.WebHooksEditPost", nil)
 		return
 		return
 	}
 	}
 
 
+	w, err := models.GetWebhookById(hookId)
+	if err != nil {
+		if err == models.ErrWebhookNotExist {
+			ctx.Handle(404, "setting.WebHooksEditPost(GetWebhookById)", nil)
+		} else {
+			ctx.Handle(500, "setting.WebHooksEditPost(GetWebhookById)", err)
+		}
+		return
+	}
+
+	if ctx.HasError() {
+		ctx.HTML(200, HOOK_EDIT)
+		return
+	}
+
 	ct := models.JSON
 	ct := models.JSON
 	if form.ContentType == "2" {
 	if form.ContentType == "2" {
 		ct = models.FORM
 		ct = models.FORM
 	}
 	}
 
 
-	w := &models.Webhook{
-		Id:          hookId,
-		RepoId:      ctx.Repo.Repository.Id,
-		Url:         form.Url,
-		ContentType: ct,
-		Secret:      form.Secret,
-		HookEvent: &models.HookEvent{
-			PushOnly: form.PushOnly,
-		},
-		IsActive: form.Active,
+	w.Url = form.Url
+	w.ContentType = ct
+	w.Secret = form.Secret
+	w.HookEvent = &models.HookEvent{
+		PushOnly: form.PushOnly,
 	}
 	}
+	w.IsActive = form.Active
 	if err := w.UpdateEvent(); err != nil {
 	if err := w.UpdateEvent(); err != nil {
 		ctx.Handle(500, "setting.WebHooksEditPost(UpdateEvent)", err)
 		ctx.Handle(500, "setting.WebHooksEditPost(UpdateEvent)", err)
 		return
 		return

+ 30 - 11
routers/user/home.go

@@ -17,10 +17,25 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	DASHBOARD base.TplName = "user/dashboard"
+	PROFILE   base.TplName = "user/profile"
+	ISSUES    base.TplName = "user/issues"
+	PULLS     base.TplName = "user/pulls"
+	STARS     base.TplName = "user/stars"
+)
+
 func Dashboard(ctx *middleware.Context) {
 func Dashboard(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Dashboard"
 	ctx.Data["Title"] = "Dashboard"
 	ctx.Data["PageIsUserDashboard"] = true
 	ctx.Data["PageIsUserDashboard"] = true
 
 
+	if err := ctx.User.GetOrganizations(); err != nil {
+		ctx.Handle(500, "home.Dashboard(GetOrganizations)", err)
+		return
+	}
+	ctx.Data["Orgs"] = ctx.User.Orgs
+	ctx.Data["ContextUser"] = ctx.User
+
 	var err error
 	var err error
 	ctx.Data["MyRepos"], err = models.GetRepositories(ctx.User.Id, true)
 	ctx.Data["MyRepos"], err = models.GetRepositories(ctx.User.Id, true)
 	if err != nil {
 	if err != nil {
@@ -45,21 +60,21 @@ func Dashboard(ctx *middleware.Context) {
 	for _, act := range actions {
 	for _, act := range actions {
 		if act.IsPrivate {
 		if act.IsPrivate {
 			if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
 			if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
-				models.AU_READABLE); !has {
+				models.READABLE); !has {
 				continue
 				continue
 			}
 			}
 		}
 		}
 		feeds = append(feeds, act)
 		feeds = append(feeds, act)
 	}
 	}
 	ctx.Data["Feeds"] = feeds
 	ctx.Data["Feeds"] = feeds
-	ctx.HTML(200, "user/dashboard")
+	ctx.HTML(200, DASHBOARD)
 }
 }
 
 
 func Profile(ctx *middleware.Context, params martini.Params) {
 func Profile(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Title"] = "Profile"
 	ctx.Data["Title"] = "Profile"
 	ctx.Data["PageIsUserProfile"] = true
 	ctx.Data["PageIsUserProfile"] = true
 
 
-	user, err := models.GetUserByName(params["username"])
+	u, err := models.GetUserByName(params["username"])
 	if err != nil {
 	if err != nil {
 		if err == models.ErrUserNotExist {
 		if err == models.ErrUserNotExist {
 			ctx.Handle(404, "user.Profile(GetUserByName)", err)
 			ctx.Handle(404, "user.Profile(GetUserByName)", err)
@@ -68,26 +83,30 @@ func Profile(ctx *middleware.Context, params martini.Params) {
 		}
 		}
 		return
 		return
 	}
 	}
-	ctx.Data["Owner"] = user
+	// For security reason, hide e-mail address for anonymous visitors.
+	if !ctx.IsSigned {
+		u.Email = ""
+	}
+	ctx.Data["Owner"] = u
 
 
 	tab := ctx.Query("tab")
 	tab := ctx.Query("tab")
 	ctx.Data["TabName"] = tab
 	ctx.Data["TabName"] = tab
 	switch tab {
 	switch tab {
 	case "activity":
 	case "activity":
-		ctx.Data["Feeds"], err = models.GetFeeds(user.Id, 0, true)
+		ctx.Data["Feeds"], err = models.GetFeeds(u.Id, 0, true)
 		if err != nil {
 		if err != nil {
 			ctx.Handle(500, "user.Profile(GetFeeds)", err)
 			ctx.Handle(500, "user.Profile(GetFeeds)", err)
 			return
 			return
 		}
 		}
 	default:
 	default:
-		ctx.Data["Repos"], err = models.GetRepositories(user.Id, ctx.IsSigned && ctx.User.Id == user.Id)
+		ctx.Data["Repos"], err = models.GetRepositories(u.Id, ctx.IsSigned && ctx.User.Id == u.Id)
 		if err != nil {
 		if err != nil {
 			ctx.Handle(500, "user.Profile(GetRepositories)", err)
 			ctx.Handle(500, "user.Profile(GetRepositories)", err)
 			return
 			return
 		}
 		}
 	}
 	}
 
 
-	ctx.HTML(200, "user/profile")
+	ctx.HTML(200, PROFILE)
 }
 }
 
 
 func Email2User(ctx *middleware.Context) {
 func Email2User(ctx *middleware.Context) {
@@ -119,7 +138,7 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
 	for _, act := range actions {
 	for _, act := range actions {
 		if act.IsPrivate {
 		if act.IsPrivate {
 			if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
 			if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
-				models.AU_READABLE); !has {
+				models.READABLE); !has {
 				continue
 				continue
 			}
 			}
 		}
 		}
@@ -254,13 +273,13 @@ func Issues(ctx *middleware.Context) {
 	} else {
 	} else {
 		ctx.Data["ShowCount"] = issueStats.OpenCount
 		ctx.Data["ShowCount"] = issueStats.OpenCount
 	}
 	}
-	ctx.HTML(200, "user/issue")
+	ctx.HTML(200, ISSUES)
 }
 }
 
 
 func Pulls(ctx *middleware.Context) {
 func Pulls(ctx *middleware.Context) {
-	ctx.HTML(200, "user/pulls")
+	ctx.HTML(200, PULLS)
 }
 }
 
 
 func Stars(ctx *middleware.Context) {
 func Stars(ctx *middleware.Context) {
-	ctx.HTML(200, "user/stars")
+	ctx.HTML(200, STARS)
 }
 }

+ 18 - 9
routers/user/setting.go

@@ -14,12 +14,21 @@ import (
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gogits/gogs/modules/middleware"
 )
 )
 
 
+const (
+	SETTING      base.TplName = "user/setting"
+	SOCIAL       base.TplName = "user/social"
+	PASSWORD     base.TplName = "user/password"
+	PUBLICKEY    base.TplName = "user/publickey"
+	NOTIFICATION base.TplName = "user/notification"
+	SECURITY     base.TplName = "user/security"
+)
+
 func Setting(ctx *middleware.Context) {
 func Setting(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Setting"
 	ctx.Data["Title"] = "Setting"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSetting"] = true
 	ctx.Data["IsUserPageSetting"] = true
 	ctx.Data["Owner"] = ctx.User
 	ctx.Data["Owner"] = ctx.User
-	ctx.HTML(200, "user/setting")
+	ctx.HTML(200, SETTING)
 }
 }
 
 
 func SettingPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
 func SettingPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
@@ -28,7 +37,7 @@ func SettingPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
 	ctx.Data["IsUserPageSetting"] = true
 	ctx.Data["IsUserPageSetting"] = true
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "user/setting")
+		ctx.HTML(200, SETTING)
 		return
 		return
 	}
 	}
 
 
@@ -59,7 +68,7 @@ func SettingPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
 	ctx.User.Avatar = base.EncodeMd5(form.Avatar)
 	ctx.User.Avatar = base.EncodeMd5(form.Avatar)
 	ctx.User.AvatarEmail = form.Avatar
 	ctx.User.AvatarEmail = form.Avatar
 	if err := models.UpdateUser(ctx.User); err != nil {
 	if err := models.UpdateUser(ctx.User); err != nil {
-		ctx.Handle(500, "setting.Setting", err)
+		ctx.Handle(500, "setting.Setting(UpdateUser)", err)
 		return
 		return
 	}
 	}
 	log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
 	log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
@@ -90,14 +99,14 @@ func SettingSocial(ctx *middleware.Context) {
 		ctx.Handle(500, "user.SettingSocial(GetOauthByUserId)", err)
 		ctx.Handle(500, "user.SettingSocial(GetOauthByUserId)", err)
 		return
 		return
 	}
 	}
-	ctx.HTML(200, "user/social")
+	ctx.HTML(200, SOCIAL)
 }
 }
 
 
 func SettingPassword(ctx *middleware.Context) {
 func SettingPassword(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Password"
 	ctx.Data["Title"] = "Password"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingPasswd"] = true
 	ctx.Data["IsUserPageSettingPasswd"] = true
-	ctx.HTML(200, "user/password")
+	ctx.HTML(200, PASSWORD)
 }
 }
 
 
 func SettingPasswordPost(ctx *middleware.Context, form auth.UpdatePasswdForm) {
 func SettingPasswordPost(ctx *middleware.Context, form auth.UpdatePasswdForm) {
@@ -106,7 +115,7 @@ func SettingPasswordPost(ctx *middleware.Context, form auth.UpdatePasswdForm) {
 	ctx.Data["IsUserPageSettingPasswd"] = true
 	ctx.Data["IsUserPageSettingPasswd"] = true
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "user/password")
+		ctx.HTML(200, PASSWORD)
 		return
 		return
 	}
 	}
 
 
@@ -207,7 +216,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
 		}
 		}
 	}
 	}
 
 
-	ctx.HTML(200, "user/publickey")
+	ctx.HTML(200, PUBLICKEY)
 }
 }
 
 
 func SettingNotification(ctx *middleware.Context) {
 func SettingNotification(ctx *middleware.Context) {
@@ -215,7 +224,7 @@ func SettingNotification(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Notification"
 	ctx.Data["Title"] = "Notification"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingNotify"] = true
 	ctx.Data["IsUserPageSettingNotify"] = true
-	ctx.HTML(200, "user/notification")
+	ctx.HTML(200, NOTIFICATION)
 }
 }
 
 
 func SettingSecurity(ctx *middleware.Context) {
 func SettingSecurity(ctx *middleware.Context) {
@@ -223,5 +232,5 @@ func SettingSecurity(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Security"
 	ctx.Data["Title"] = "Security"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingSecurity"] = true
 	ctx.Data["IsUserPageSettingSecurity"] = true
-	ctx.HTML(200, "user/security")
+	ctx.HTML(200, SECURITY)
 }
 }

+ 36 - 26
routers/user/user.go

@@ -17,12 +17,21 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 	"github.com/gogits/gogs/modules/setting"
 )
 )
 
 
+const (
+	SIGNIN          base.TplName = "user/signin"
+	SIGNUP          base.TplName = "user/signup"
+	DELETE          base.TplName = "user/delete"
+	ACTIVATE        base.TplName = "user/activate"
+	FORGOT_PASSWORD base.TplName = "user/forgot_passwd"
+	RESET_PASSWORD  base.TplName = "user/reset_passwd"
+)
+
 func SignIn(ctx *middleware.Context) {
 func SignIn(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Log In"
 	ctx.Data["Title"] = "Log In"
 
 
 	if _, ok := ctx.Session.Get("socialId").(int64); ok {
 	if _, ok := ctx.Session.Get("socialId").(int64); ok {
 		ctx.Data["IsSocialLogin"] = true
 		ctx.Data["IsSocialLogin"] = true
-		ctx.HTML(200, "user/signin")
+		ctx.HTML(200, SIGNIN)
 		return
 		return
 	}
 	}
 
 
@@ -34,7 +43,7 @@ func SignIn(ctx *middleware.Context) {
 	// Check auto-login.
 	// Check auto-login.
 	uname := ctx.GetCookie(setting.CookieUserName)
 	uname := ctx.GetCookie(setting.CookieUserName)
 	if len(uname) == 0 {
 	if len(uname) == 0 {
-		ctx.HTML(200, "user/signin")
+		ctx.HTML(200, SIGNIN)
 		return
 		return
 	}
 	}
 
 
@@ -57,7 +66,7 @@ func SignIn(ctx *middleware.Context) {
 	secret := base.EncodeMd5(user.Rands + user.Passwd)
 	secret := base.EncodeMd5(user.Rands + user.Passwd)
 	value, _ := ctx.GetSecureCookie(secret, setting.CookieRememberName)
 	value, _ := ctx.GetSecureCookie(secret, setting.CookieRememberName)
 	if value != user.Name {
 	if value != user.Name {
-		ctx.HTML(200, "user/signin")
+		ctx.HTML(200, SIGNIN)
 		return
 		return
 	}
 	}
 
 
@@ -86,7 +95,7 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
 	}
 	}
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "user/signin")
+		ctx.HTML(200, SIGNIN)
 		return
 		return
 	}
 	}
 
 
@@ -94,7 +103,7 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
 	if err != nil {
 	if err != nil {
 		if err == models.ErrUserNotExist {
 		if err == models.ErrUserNotExist {
 			log.Trace("%s Log in failed: %s", ctx.Req.RequestURI, form.UserName)
 			log.Trace("%s Log in failed: %s", ctx.Req.RequestURI, form.UserName)
-			ctx.RenderWithErr("Username or password is not correct", "user/signin", &form)
+			ctx.RenderWithErr("Username or password is not correct", SIGNIN, &form)
 			return
 			return
 		}
 		}
 
 
@@ -151,7 +160,7 @@ func SignUp(ctx *middleware.Context) {
 
 
 	if setting.Service.DisableRegistration {
 	if setting.Service.DisableRegistration {
 		ctx.Data["DisableRegistration"] = true
 		ctx.Data["DisableRegistration"] = true
-		ctx.HTML(200, "user/signup")
+		ctx.HTML(200, SIGNUP)
 		return
 		return
 	}
 	}
 
 
@@ -160,7 +169,7 @@ func SignUp(ctx *middleware.Context) {
 		return
 		return
 	}
 	}
 
 
-	ctx.HTML(200, "user/signup")
+	ctx.HTML(200, SIGNUP)
 }
 }
 
 
 func oauthSignUp(ctx *middleware.Context, sid int64) {
 func oauthSignUp(ctx *middleware.Context, sid int64) {
@@ -180,7 +189,7 @@ func oauthSignUp(ctx *middleware.Context, sid int64) {
 	ctx.Data["username"] = strings.Replace(ctx.Session.Get("socialName").(string), " ", "", -1)
 	ctx.Data["username"] = strings.Replace(ctx.Session.Get("socialName").(string), " ", "", -1)
 	ctx.Data["email"] = ctx.Session.Get("socialEmail")
 	ctx.Data["email"] = ctx.Session.Get("socialEmail")
 	log.Trace("user.oauthSignUp(social ID): %v", ctx.Session.Get("socialId"))
 	log.Trace("user.oauthSignUp(social ID): %v", ctx.Session.Get("socialId"))
-	ctx.HTML(200, "user/signup")
+	ctx.HTML(200, SIGNUP)
 }
 }
 
 
 func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) {
 func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) {
@@ -198,14 +207,14 @@ func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) {
 	}
 	}
 
 
 	if ctx.HasError() {
 	if ctx.HasError() {
-		ctx.HTML(200, "user/signup")
+		ctx.HTML(200, SIGNUP)
 		return
 		return
 	}
 	}
 
 
 	if form.Password != form.RetypePasswd {
 	if form.Password != form.RetypePasswd {
 		ctx.Data["Err_Password"] = true
 		ctx.Data["Err_Password"] = true
 		ctx.Data["Err_RetypePasswd"] = true
 		ctx.Data["Err_RetypePasswd"] = true
-		ctx.RenderWithErr("Password and re-type password are not same.", "user/signup", &form)
+		ctx.RenderWithErr("Password and re-type password are not same.", SIGNUP, &form)
 		return
 		return
 	}
 	}
 
 
@@ -217,22 +226,23 @@ func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) {
 	}
 	}
 
 
 	var err error
 	var err error
-	if u, err = models.RegisterUser(u); err != nil {
+	if u, err = models.CreateUser(u); err != nil {
 		switch err {
 		switch err {
 		case models.ErrUserAlreadyExist:
 		case models.ErrUserAlreadyExist:
 			ctx.Data["Err_UserName"] = true
 			ctx.Data["Err_UserName"] = true
-			ctx.RenderWithErr("Username has been already taken", "user/signup", &form)
+			ctx.RenderWithErr("Username has been already taken", SIGNUP, &form)
 		case models.ErrEmailAlreadyUsed:
 		case models.ErrEmailAlreadyUsed:
 			ctx.Data["Err_Email"] = true
 			ctx.Data["Err_Email"] = true
-			ctx.RenderWithErr("E-mail address has been already used", "user/signup", &form)
+			ctx.RenderWithErr("E-mail address has been already used", SIGNUP, &form)
 		case models.ErrUserNameIllegal:
 		case models.ErrUserNameIllegal:
-			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "user/signup", &form)
+			ctx.Data["Err_UserName"] = true
+			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), SIGNUP, &form)
 		default:
 		default:
-			ctx.Handle(500, "user.SignUpPost(RegisterUser)", err)
+			ctx.Handle(500, "user.SignUpPost(CreateUser)", err)
 		}
 		}
 		return
 		return
 	}
 	}
-	log.Trace("%s User created: %s", ctx.Req.RequestURI, form.UserName)
+	log.Trace("%s User created: %s", ctx.Req.RequestURI, u.Name)
 
 
 	// Bind social account.
 	// Bind social account.
 	if isOauth {
 	if isOauth {
@@ -265,7 +275,7 @@ func Delete(ctx *middleware.Context) {
 	ctx.Data["Title"] = "Delete Account"
 	ctx.Data["Title"] = "Delete Account"
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["PageIsUserSetting"] = true
 	ctx.Data["IsUserPageSettingDelete"] = true
 	ctx.Data["IsUserPageSettingDelete"] = true
-	ctx.HTML(200, "user/delete")
+	ctx.HTML(200, DELETE)
 }
 }
 
 
 func DeletePost(ctx *middleware.Context) {
 func DeletePost(ctx *middleware.Context) {
@@ -286,7 +296,7 @@ func DeletePost(ctx *middleware.Context) {
 			case models.ErrUserOwnRepos:
 			case models.ErrUserOwnRepos:
 				ctx.Flash.Error("Your account still have ownership of repository, you have to delete or transfer them first.")
 				ctx.Flash.Error("Your account still have ownership of repository, you have to delete or transfer them first.")
 			default:
 			default:
-				ctx.Handle(500, "user.Delete", err)
+				ctx.Handle(500, "user.Delete(DeleteUser)", err)
 				return
 				return
 			}
 			}
 		} else {
 		} else {
@@ -321,7 +331,7 @@ func Activate(ctx *middleware.Context) {
 		} else {
 		} else {
 			ctx.Data["ServiceNotEnabled"] = true
 			ctx.Data["ServiceNotEnabled"] = true
 		}
 		}
-		ctx.HTML(200, "user/activate")
+		ctx.HTML(200, ACTIVATE)
 		return
 		return
 	}
 	}
 
 
@@ -343,7 +353,7 @@ func Activate(ctx *middleware.Context) {
 	}
 	}
 
 
 	ctx.Data["IsActivateFailed"] = true
 	ctx.Data["IsActivateFailed"] = true
-	ctx.HTML(200, "user/activate")
+	ctx.HTML(200, ACTIVATE)
 }
 }
 
 
 func ForgotPasswd(ctx *middleware.Context) {
 func ForgotPasswd(ctx *middleware.Context) {
@@ -351,12 +361,12 @@ func ForgotPasswd(ctx *middleware.Context) {
 
 
 	if setting.MailService == nil {
 	if setting.MailService == nil {
 		ctx.Data["IsResetDisable"] = true
 		ctx.Data["IsResetDisable"] = true
-		ctx.HTML(200, "user/forgot_passwd")
+		ctx.HTML(200, FORGOT_PASSWORD)
 		return
 		return
 	}
 	}
 
 
 	ctx.Data["IsResetRequest"] = true
 	ctx.Data["IsResetRequest"] = true
-	ctx.HTML(200, "user/forgot_passwd")
+	ctx.HTML(200, FORGOT_PASSWORD)
 }
 }
 
 
 func ForgotPasswdPost(ctx *middleware.Context) {
 func ForgotPasswdPost(ctx *middleware.Context) {
@@ -381,7 +391,7 @@ func ForgotPasswdPost(ctx *middleware.Context) {
 
 
 	if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) {
 	if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) {
 		ctx.Data["ResendLimited"] = true
 		ctx.Data["ResendLimited"] = true
-		ctx.HTML(200, "user/forgot_passwd")
+		ctx.HTML(200, FORGOT_PASSWORD)
 		return
 		return
 	}
 	}
 
 
@@ -393,7 +403,7 @@ func ForgotPasswdPost(ctx *middleware.Context) {
 	ctx.Data["Email"] = email
 	ctx.Data["Email"] = email
 	ctx.Data["Hours"] = setting.Service.ActiveCodeLives / 60
 	ctx.Data["Hours"] = setting.Service.ActiveCodeLives / 60
 	ctx.Data["IsResetSent"] = true
 	ctx.Data["IsResetSent"] = true
-	ctx.HTML(200, "user/forgot_passwd")
+	ctx.HTML(200, FORGOT_PASSWORD)
 }
 }
 
 
 func ResetPasswd(ctx *middleware.Context) {
 func ResetPasswd(ctx *middleware.Context) {
@@ -406,7 +416,7 @@ func ResetPasswd(ctx *middleware.Context) {
 	}
 	}
 	ctx.Data["Code"] = code
 	ctx.Data["Code"] = code
 	ctx.Data["IsResetForm"] = true
 	ctx.Data["IsResetForm"] = true
-	ctx.HTML(200, "user/reset_passwd")
+	ctx.HTML(200, RESET_PASSWORD)
 }
 }
 
 
 func ResetPasswdPost(ctx *middleware.Context) {
 func ResetPasswdPost(ctx *middleware.Context) {
@@ -443,5 +453,5 @@ func ResetPasswdPost(ctx *middleware.Context) {
 	}
 	}
 
 
 	ctx.Data["IsResetFailed"] = true
 	ctx.Data["IsResetFailed"] = true
-	ctx.HTML(200, "user/reset_passwd")
+	ctx.HTML(200, RESET_PASSWORD)
 }
 }

+ 1 - 1
templates/VERSION

@@ -1 +1 @@
-0.4.5.0621 Alpha
+0.4.5.0627 Alpha

+ 0 - 0
templates/admin/auths/edit.tmpl → templates/admin/auth/edit.tmpl


+ 0 - 0
templates/admin/auths/new.tmpl → templates/admin/auth/new.tmpl


+ 2 - 2
templates/admin/config.tmpl

@@ -36,8 +36,8 @@
                     <dd>{{.LogRootPath}}</dd>
                     <dd>{{.LogRootPath}}</dd>
                     <dt>Script Type</dt>
                     <dt>Script Type</dt>
                     <dd>{{.ScriptType}}</dd>
                     <dd>{{.ScriptType}}</dd>
-                    <dt>Reverse Authentication UID</dt>
-                    <dd>{{.ReverseProxyAuthUid}}</dd>
+                    <dt>Reverse Authentication User</dt>
+                    <dd>{{.ReverseProxyAuthUser}}</dd>
                 </dl>
                 </dl>
             </div>
             </div>
         </div>
         </div>

+ 0 - 0
templates/admin/users/edit.tmpl → templates/admin/user/edit.tmpl


+ 0 - 0
templates/admin/users/new.tmpl → templates/admin/user/new.tmpl


+ 0 - 0
templates/mail/auth/active_email.tmpl → templates/mail/auth/active.tmpl


+ 75 - 0
templates/org/edit_team.tmpl

@@ -0,0 +1,75 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="body-nav" class="org-nav org-nav-auto">
+    <div class="container clearfix">
+        <div id="org-nav-wrapper">
+            <ul class="nav nav-pills pull-right">
+                <li><a href="#"><i class="fa fa-users"></i>Members
+                    <span class="label label-default">5</span></a>
+                </li>
+                <li class="active"><a href="#"><i class="fa fa-tags"></i>Teams
+                    <span class="label label-default">2</span></a>
+                </li>
+            </ul>
+            <img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/>
+            <div id="org-nav-info">
+                <h2 class="org-name">Organization Name</h2>
+            </div>
+        </div>
+    </div>
+</div>
+<div id="body" class="container">
+    <div id="org">
+        <form id="org-teams-edit" class="form-horizontal card">
+            <h3>Edit team</h3>
+            <div class="form-group">
+                <label class="col-md-2 control-label">Team Name<strong class="text-danger">*</strong></label>
+                <div class="col-md-8">
+                    <input name="team" type="text" class="form-control" placeholder="Type your team name" value="" required="required">
+                    <span class="help-block">You'll use this name to mention this team in conversations.</span>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label">Description</label>
+                <div class="col-md-8">
+                    <input name="desc" type="text" class="form-control" placeholder="Type your team description (optional)" value="">
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label">Permission</label>
+                <div class="col-md-8">
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="permission" value="pull" checked="">
+                            <strong>Read & Clone</strong>
+                        </label>
+                        <p>This team will be able to view and clone its repositories.</p>
+                    </div>
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="permission" value="push">
+                            <strong>Push, Read & Clone</strong>
+                        </label>
+                        <p>This team will be able to read its repositories, as well as push to them.</p>
+                    </div>
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="permission" value="admin">
+                            <strong>Collaboration, Push, Read & Clone</strong>
+                        </label>
+                        <p>This team will be able to push/pull to its repositories, as well as add other collaborators to them.</p>
+                    </div>
+                </div>
+            </div>
+            <hr/>
+            <div class="form-group">
+                <label class="col-md-2">&nbsp;</label>
+                <div class="col-md-8">
+                    <button class="btn btn-primary">Edit this team</button>
+                    <button class="btn btn-danger pull-right" value="delete" name="delete">Delete this team</button>
+                </div>
+            </div>
+        </form>
+    </div>
+</div>
+{{template "base/footer" .}}

+ 56 - 0
templates/org/members.tmpl

@@ -0,0 +1,56 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="body-nav" class="org-nav org-nav-auto">
+    <div class="container clearfix">
+        <div id="org-nav-wrapper">
+            <ul class="nav nav-pills pull-right">
+                <li class="active"><a href="#"><i class="fa fa-users"></i>Members
+                    <span class="label label-default">5</span></a>
+                </li>
+                <li><a href="#"><i class="fa fa-tags"></i>Teams
+                    <span class="label label-default">2</span></a>
+                </li>
+            </ul>
+            <img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/>
+            <div id="org-nav-info">
+                <h2 class="org-name">Organization Name</h2>
+            </div>
+        </div>
+
+    </div>
+</div>
+<div id="body" class="container">
+    <div id="org">
+        <div id="org-members">
+            <div class="member">&nbsp;
+                <div class="avatar col-md-1">
+                    <img src="https://avatars3.githubusercontent.com/u/2142787?s=140" alt=""/>
+                </div>
+                <div class="name col-md-4">
+                    <a href="#"><strong>fuxiaohei</strong><span class="nick">傅小黑</span></a>
+                </div>
+                <div class="role col-md-2 pull-right">
+                    <strong>Member</strong>
+                </div>
+                <div class="status col-md-1 pull-right">
+                    <strong>Public</strong>
+                </div>
+            </div>
+            <div class="member">&nbsp;
+                <div class="avatar col-md-1">
+                    <img src="https://avatars3.githubusercontent.com/u/2142787?s=140" alt=""/>
+                </div>
+                <div class="name col-md-4">
+                    <a href="#"><strong>fuxiaohei</strong><span class="nick">傅小黑</span></a>
+                </div>
+                <div class="role col-md-2 pull-right">
+                    <strong><i class="fa fa-user"></i>Owner</strong>
+                </div>
+                <div class="status col-md-1 pull-right">
+                    <i class="fa fa-lock"></i>Private
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}

+ 32 - 0
templates/org/new.tmpl

@@ -0,0 +1,32 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div class="container" id="body">
+    <form action="/org/create" method="post" class="form-horizontal card" id="org-create">
+        {{.CsrfTokenHtml}}
+        <h3>Create New Organization</h3>
+        {{template "base/alert" .}}
+        <div class="form-group {{if .Err_OrgName}}has-error has-feedback{{end}}">
+            <label class="col-md-2 control-label">Organization<strong class="text-danger">*</strong></label>
+            <div class="col-md-8">
+                <input name="orgname" type="text" class="form-control" placeholder="Type your organization name" value="{{.orgname}}" required="required">
+                <span class="help-block">Great organization names are short and memorable. </span>
+            </div>
+        </div>
+
+        <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}">
+            <label class="col-md-2 control-label">Email<strong class="text-danger">*</strong></label>
+            <div class="col-md-8">
+                <input name="email" type="text" class="form-control" placeholder="Type organization's email" value="{{.email}}" required="required">
+                <span class="help-block">Organization's Email receives all notifications and confirmations.</span>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <div class="col-md-offset-2 col-md-8">
+                <button type="submit" class="btn btn-lg btn-primary">Create An Organization</button>
+                <a href="/" class="text-danger">Cancel</a>
+            </div>
+        </div>
+    </form>
+</div>
+{{template "base/footer" .}}

+ 74 - 0
templates/org/new_team.tmpl

@@ -0,0 +1,74 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="body-nav" class="org-nav org-nav-auto">
+    <div class="container clearfix">
+        <div id="org-nav-wrapper">
+            <ul class="nav nav-pills pull-right">
+                <li><a href="#"><i class="fa fa-users"></i>Members
+                    <span class="label label-default">5</span></a>
+                </li>
+                <li class="active"><a href="#"><i class="fa fa-tags"></i>Teams
+                    <span class="label label-default">2</span></a>
+                </li>
+            </ul>
+            <img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/>
+            <div id="org-nav-info">
+                <h2 class="org-name">Organization Name</h2>
+            </div>
+        </div>
+    </div>
+</div>
+<div id="body" class="container">
+    <div id="org">
+        <form id="org-teams-create" class="form-horizontal card">
+            <h3>Create new team</h3>
+            <div class="form-group">
+                <label class="col-md-2 control-label">Team Name<strong class="text-danger">*</strong></label>
+                <div class="col-md-8">
+                    <input name="team" type="text" class="form-control" placeholder="Type your team name" value="" required="required">
+                    <span class="help-block">You'll use this name to mention this team in conversations.</span>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label">Description</label>
+                <div class="col-md-8">
+                    <input name="desc" type="text" class="form-control" placeholder="Type your team description (optional)" value="">
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label">Permission</label>
+                <div class="col-md-8">
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="permission" value="pull" checked="">
+                            <strong>Read & Clone</strong>
+                        </label>
+                        <p>This team will be able to view and clone its repositories.</p>
+                    </div>
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="permission" value="push">
+                            <strong>Push, Read & Clone</strong>
+                        </label>
+                        <p>This team will be able to read its repositories, as well as push to them.</p>
+                    </div>
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="permission" value="admin">
+                            <strong>Collaboration, Push, Read & Clone</strong>
+                        </label>
+                        <p>This team will be able to push/pull to its repositories, as well as add other collaborators to them.</p>
+                    </div>
+                </div>
+            </div>
+            <hr/>
+            <div class="form-group">
+                <label class="col-md-2">&nbsp;</label>
+                <div class="col-md-8">
+                    <button class="btn btn-primary">Create team</button>
+                </div>
+            </div>
+        </form>
+    </div>
+</div>
+{{template "base/footer" .}}

+ 130 - 0
templates/org/settings.tmpl

@@ -0,0 +1,130 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="body-nav">
+    <div class="container">
+        <div class="btn-group pull-left" id="dashboard-switch">
+            <button type="button" class="btn btn-default">
+                <img src="{{.Org.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                {{.Org.Name}}
+            </button>
+        </div>
+        <ul class="nav nav-pills pull-right">
+            <li><a href="/org/{{.Org.Name}}/dashboard/">News Feed</a></li>
+            <li><a href="/org/{{.Org.Name}}/dashboard/issues">Issues</a></li>
+            <li class="active"><a href="/org/{{.Org.Name}}/settings">Settings</a></li>
+            <!-- <li><a href="/pulls">Pull Requests</a></li>
+            <li><a href="/stars">Stars</a></li> -->
+        </ul>
+    </div>
+</div>
+
+<div id="body" class="container" data-page="org">
+    <div id="user-setting-nav" class="col-md-2 repo-setting-nav">
+        <ul class="list-group">
+            <li class="list-group-item active"><a href="#">Options</a></li>
+        </ul>
+    </div>
+    <div id="repo-setting-container" class="col-md-10">
+        {{template "base/alert" .}}
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                Organization Options
+            </div>
+
+            <div class="panel-body">
+                <form action="/org/{{.Org.Name}}/settings" method="post" class="form-horizontal">
+                    {{.CsrfTokenHtml}}
+                    <input type="hidden" name="action" value="update">
+
+                    <div class="form-group{{if .Err_DisplayName}} has-error has-feedback{{end}}">
+                        <label class="col-md-3 text-right" for="org-setting-name">Display Name</label>
+                        <div class="col-md-9">
+                            <input class="form-control" name="display_name" value="{{.Org.FullName}}" title="" id="org-setting-name"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group{{if .Err_Email}} has-error has-feedback{{end}}">
+                        <label class="col-md-3 text-right" for="org-email">Email</label>
+                        <div class="col-md-9">
+                            <input class="form-control" name="email" value="{{.Org.Email}}" title="" id="org-email" type="email"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group{{if .Err_Description}} has-error has-feedback{{end}}">
+                        <label class="col-md-3 text-right" for="org-desc">Description</label>
+                        <div class="col-md-9">
+                            <textarea class="form-control" name="desc" id="org-desc" rows="3">{{.Org.Description}}</textarea>
+                        </div>
+                    </div>
+
+                    <div class="form-group{{if .Err_Website}} has-error has-feedback{{end}}">
+                        <label class="col-md-3 text-right" for="org-site">Official Site</label>
+                        <div class="col-md-9">
+                            <input type="url" class="form-control" name="site" value="{{.Org.Website}}" id="org-site"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group{{if .Err_Location}} has-error has-feedback{{end}}">
+                        <label class="col-md-3 text-right" for="org-location">Location</label>
+                        <div class="col-md-9">
+                            <input class="form-control" name="location" value="{{.Org.Location}}" title="" id="org-location"/>
+                        </div>
+                    </div>
+
+                    <div class="form-group">
+                        <div class="col-md-9 col-md-offset-3">
+                            <button class="btn btn-primary" type="submit">Save Options</button>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </div>
+
+        <div class="panel panel-warning">
+            <div class="panel-heading">
+                Danger Zone
+            </div>
+            <div class="panel-body">
+                <button type="button" class="btn btn-default pull-right" href="#delete-org-modal" data-toggle="modal">
+                    Delete this organization
+                </button>
+                <dd>
+                <dt>Delete this organization</dt>
+                <dl>Once you delete this organization and all repositories in, there is no going back. Please be
+                    certain.
+                </dl>
+                </dd>
+
+                <div class="modal fade" id="delete-org-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
+                     aria-hidden="true">
+                    <div class="modal-dialog">
+                        <form action="/org/{{.Org.Name}}/settings/delete" method="post"
+                              class="modal-content">
+                            {{.CsrfTokenHtml}}
+                            <div class="modal-header">
+                                <button type="button" class="close" data-dismiss="modal"
+                                        aria-hidden="true">&times;</button>
+                                <h4 class="modal-title" id="myModalLabel">Delete organization</h4>
+                            </div>
+
+                            <div class="modal-body">
+                                <div class="form-group">
+                                    <label>Make sure your are owner of this organization. Please enter your password.<strong class="text-danger">*</strong></label>
+                                    <input name="password" class="form-control" type="password" placeholder="Type your account password" required="required">
+                                </div>
+                            </div>
+
+                            <div class="modal-footer">
+                                <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+                                <button class="btn btn-danger btn-lg">I understand the consequences, delete this
+                                    organization
+                                </button>
+                            </div>
+                        </form>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}

+ 71 - 0
templates/org/teams.tmpl

@@ -0,0 +1,71 @@
+{{template "base/head" .}}
+{{template "base/navbar" .}}
+<div id="body-nav" class="org-nav org-nav-auto">
+    <div class="container clearfix">
+        <div id="org-nav-wrapper">
+            <ul class="nav nav-pills pull-right">
+                <li><a href="#"><i class="fa fa-users"></i>Members
+                    <span class="label label-default">5</span></a>
+                </li>
+                <li class="active"><a href="#"><i class="fa fa-tags"></i>Teams
+                    <span class="label label-default">2</span></a>
+                </li>
+            </ul>
+            <img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/>
+            <div id="org-nav-info">
+                <h2 class="org-name">Organization Name</h2>
+            </div>
+        </div>
+    </div>
+</div>
+<div id="body" class="container">
+    <div id="org">
+        <div id="org-teams">
+            <div id="org-teams-action">
+                <div class="col-md-12">
+                    <a href="#"><button class="btn btn-success"><i class="fa fa-plus-square"></i>New Team</button></a>
+                    <hr/>
+                </div>
+            </div>
+            <div class="org-team col-md-6">
+                <div class="panel panel-default">
+                    <h2 class="panel-heading org-team-name"><a href="#"><strong>Team Name</strong></a></h2>
+                    <div class="panel-body">
+                        <p class="org-team-meta">4 members · 10 repositories</p>
+                        <p class="org-team-members">
+                            <a href="#">
+                                <img class="img-thumbnail" src="https://avatars2.githubusercontent.com/u/2946214?s=60" alt=""/>
+                            </a>
+                            <a href="#">
+                                <img class="img-thumbnail" src="https://avatars2.githubusercontent.com/u/2946214?s=60" alt=""/>
+                            </a>
+                        </p>
+                    </div>
+                    <div class="panel-footer">
+                        <button class="pull-right btn btn-default">Join</button>
+                    </div>
+                </div>
+            </div>
+            <div class="org-team col-md-6">
+                <div class="panel panel-default">
+                    <h2 class="panel-heading org-team-name"><a href="#"><strong>Team Name</strong></a></h2>
+                    <div class="panel-body">
+                        <p class="org-team-meta">4 members · 10 repositories</p>
+                        <p class="org-team-members">
+                            <a href="#">
+                                <img class="img-thumbnail" src="https://avatars2.githubusercontent.com/u/2946214?s=60" alt=""/>
+                            </a>
+                            <a href="#">
+                                <img class="img-thumbnail" src="https://avatars2.githubusercontent.com/u/2946214?s=60" alt=""/>
+                            </a>
+                        </p>
+                    </div>
+                    <div class="panel-footer">
+                        <button class="pull-right btn btn-danger">Leave</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{{template "base/footer" .}}

+ 0 - 0
templates/repo/branches.tmpl → templates/repo/branch.tmpl


+ 30 - 2
templates/repo/create.tmpl

@@ -8,9 +8,37 @@
         <div class="form-group">
         <div class="form-group">
             <label class="col-md-2 control-label">Owner<strong class="text-danger">*</strong></label>
             <label class="col-md-2 control-label">Owner<strong class="text-danger">*</strong></label>
             <div class="col-md-8">
             <div class="col-md-8">
-                <p class="form-control-static">{{.SignedUserName}}</p>
-                <input type="hidden" value="{{.SignedUserId}}" name="userId"/>
+                <div class="btn-group" id="repo-owner-switch">
+                    <button type="button" class="btn btn-default" id="repo-owner-current">
+                        <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username" id="repo-owner-avatar">
+                        <span id="repo-owner-name">{{.SignedUser.Name}}</span>
+                    </button>
+                    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+                        <span class="caret"></span>
+                    </button>
+                    <div class="dropdown-menu clone-group-btn no-propagation">
+                        <ul id="dashboard-switch-menu" class="list-unstyled">
+                            <li data-uid="{{.SignedUser.Id}}" class="checked">
+                                <a>
+                                    <i class="fa fa-check"></i>
+                                    <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                                    {{.SignedUser.Name}}
+                                </a>
+                            </li>
+                            {{range .Orgs}}
+                            <li data-uid="{{.Id}}">
+                                <a>
+                                    <i class="fa fa-check"></i>
+                                    <img src="{{.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                                    {{.Name}}
+                                </a>
+                            </li>
+                            {{end}}
+                        </ul>
+                    </div>
+                </div>
             </div>
             </div>
+            <input type="hidden" value="{{.SignedUserId}}" name="uid" id="repo-owner-id"/>
         </div>
         </div>
 
 
         <div class="form-group {{if .Err_RepoName}}has-error has-feedback{{end}}">
         <div class="form-group {{if .Err_RepoName}}has-error has-feedback{{end}}">

+ 0 - 0
templates/repo/hooks_add.tmpl → templates/repo/hook_add.tmpl


+ 0 - 0
templates/repo/hooks_edit.tmpl → templates/repo/hook_edit.tmpl


+ 0 - 0
templates/issue/create.tmpl → templates/repo/issue/create.tmpl


+ 0 - 0
templates/issue/list.tmpl → templates/repo/issue/list.tmpl


+ 0 - 0
templates/issue/milestone.tmpl → templates/repo/issue/milestone.tmpl


+ 0 - 0
templates/issue/milestone_edit.tmpl → templates/repo/issue/milestone_edit.tmpl


+ 0 - 0
templates/issue/milestone_new.tmpl → templates/repo/issue/milestone_new.tmpl


+ 0 - 0
templates/issue/view.tmpl → templates/repo/issue/view.tmpl


+ 30 - 2
templates/repo/migrate.tmpl

@@ -44,9 +44,37 @@
         <div class="form-group">
         <div class="form-group">
             <label class="col-md-2 control-label">Owner<strong class="text-danger">*</strong></label>
             <label class="col-md-2 control-label">Owner<strong class="text-danger">*</strong></label>
             <div class="col-md-8">
             <div class="col-md-8">
-                <p class="form-control-static">{{.SignedUserName}}</p>
-                <input type="hidden" value="{{.SignedUserId}}" name="userId"/>
+                <div class="btn-group" id="repo-owner-switch">
+                    <button type="button" class="btn btn-default" id="repo-owner-current">
+                        <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username" id="repo-owner-avatar">
+                        <span id="repo-owner-name">{{.SignedUser.Name}}</span>
+                    </button>
+                    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+                        <span class="caret"></span>
+                    </button>
+                    <div class="dropdown-menu clone-group-btn no-propagation">
+                        <ul id="dashboard-switch-menu" class="list-unstyled">
+                            <li data-uid="{{.SignedUser.Id}}" class="checked">
+                                <a>
+                                    <i class="fa fa-check"></i>
+                                    <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                                    {{.SignedUser.Name}}
+                                </a>
+                            </li>
+                            {{range .Orgs}}
+                            <li data-uid="{{.Id}}">
+                                <a>
+                                    <i class="fa fa-check"></i>
+                                    <img src="{{.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                                    {{.Name}}
+                                </a>
+                            </li>
+                            {{end}}
+                        </ul>
+                    </div>
+                </div>
             </div>
             </div>
+            <input type="hidden" value="{{.SignedUserId}}" name="uid" id="repo-owner-id"/>
         </div>
         </div>
 
 
         <div class="form-group {{if .Err_RepoName}}has-error has-feedback{{end}}">
         <div class="form-group {{if .Err_RepoName}}has-error has-feedback{{end}}">

+ 0 - 0
templates/release/edit.tmpl → templates/repo/release/edit.tmpl


+ 0 - 0
templates/release/list.tmpl → templates/repo/release/list.tmpl


+ 0 - 0
templates/release/new.tmpl → templates/repo/release/new.tmpl


+ 29 - 8
templates/user/dashboard.tmpl

@@ -4,27 +4,46 @@
     <div class="container">
     <div class="container">
         <div class="btn-group pull-left" id="dashboard-switch">
         <div class="btn-group pull-left" id="dashboard-switch">
             <button type="button" class="btn btn-default">
             <button type="button" class="btn btn-default">
-                <img src="//1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132?s=28" alt="user-avatar" title="username">
-                fuxiaohei
+                <img src="{{.ContextUser.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                {{.ContextUser.Name}}
             </button>
             </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">
                 <span class="caret"></span>
                 <span class="caret"></span>
             </button>
             </button>
             <div class="dropdown-menu clone-group-btn no-propagation">
             <div class="dropdown-menu clone-group-btn no-propagation">
                 <ul id="dashboard-switch-menu" class="list-unstyled">
                 <ul id="dashboard-switch-menu" class="list-unstyled">
-                    <li class="checked"><a href="#"><i class="fa fa-check"></i> gogits/gogs</a></li>
+                    <li{{if not .PageIsOrgDashboard}} class="checked"{{end}}>
+                        <a href="/">
+                            <i class="fa fa-check"></i>
+                            <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                            {{.SignedUser.Name}}
+                        </a>
+                    </li>
+                    {{range .Orgs}}
+                    <li{{if eq $.ContextUser.Id .Id}} class="checked"{{end}}>
+                        <a href="/org/{{.Name}}/dashboard">
+                            <i class="fa fa-check"></i>
+                            <img src="{{.AvatarLink}}?s=28" alt="user-avatar" title="username">
+                            {{.Name}}
+                        </a>
+                    </li>
+                    {{end}}
+                    <li>
+                        <a href="/org/create">Create organization</a>
+                    </li>
                 </ul>
                 </ul>
             </div>
             </div>
         </div>
         </div>
         <ul class="nav nav-pills pull-right">
         <ul class="nav nav-pills pull-right">
-            <li class="active"><a href="/">Feed</a></li>
-            <li><a href="/issues">Issues</a></li>
+            <li class="active"><a href="/{{if .PageIsOrgDashboard}}org/{{.ContextUser.Name}}/dashboard{{end}}">News Feed</a></li>
+            <li><a href="/{{if .PageIsOrgDashboard}}org/{{.ContextUser.Name}}/dashboard/{{end}}issues">Issues</a></li>
+            {{if .PageIsOrgDashboard}}<li><a href="/org/{{.ContextUser.Name}}/settings">Settings</a></li>{{end}}
             <!-- <li><a href="/pulls">Pull Requests</a></li>
             <!-- <li><a href="/pulls">Pull Requests</a></li>
             <li><a href="/stars">Stars</a></li> -->
             <li><a href="/stars">Stars</a></li> -->
         </ul>
         </ul>
-        <h3>News Feed</h3>
     </div>
     </div>
 </div>
 </div>
+
 <div id="body" class="container" data-page="user">
 <div id="body" class="container" data-page="user">
     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
     <div id="feed-left" class="col-md-8">
     <div id="feed-left" class="col-md-8">
@@ -42,7 +61,7 @@
     </div>
     </div>
     <div id="feed-right" class="col-md-4">
     <div id="feed-right" class="col-md-4">
         <div class="panel panel-default repo-panel">
         <div class="panel panel-default repo-panel">
-            <div class="panel-heading">Your Repositories
+            <div class="panel-heading">{{if not .PageIsOrgDashboard}}Your {{end}}Repositories
                 <div class="btn-group pull-right" id="user-dashboard-repo-new">
                 <div class="btn-group pull-right" id="user-dashboard-repo-new">
                     <button type="button" class="btn btn-success btn-sm dropdown-toggle" data-toggle="dropdown"><i class="fa fa-plus-square"></i>New</button>
                     <button type="button" class="btn btn-success btn-sm dropdown-toggle" data-toggle="dropdown"><i class="fa fa-plus-square"></i>New</button>
                     <div class="dropdown-menu dropdown-menu-right">
                     <div class="dropdown-menu dropdown-menu-right">
@@ -64,7 +83,8 @@
                 </ul>
                 </ul>
             </div>
             </div>
         </div>
         </div>
-
+        
+        {{if not .PageIsOrgDashboard}}
         <div class="panel panel-default repo-panel">
         <div class="panel panel-default repo-panel">
             <div class="panel-heading">Collaborative Repositories</div>
             <div class="panel-heading">Collaborative Repositories</div>
             <div class="panel-body">
             <div class="panel-body">
@@ -76,6 +96,7 @@
                 </ul>
                 </ul>
             </div>
             </div>
         </div>
         </div>
+        {{end}}
     </div>
     </div>
 </div>
 </div>
 {{template "base/footer" .}}
 {{template "base/footer" .}}

+ 2 - 1
templates/user/issue.tmpl → templates/user/issues.tmpl

@@ -3,7 +3,7 @@
 <div id="body-nav">
 <div id="body-nav">
     <div class="container">
     <div class="container">
         <ul class="nav nav-pills pull-right">
         <ul class="nav nav-pills pull-right">
-            <li><a href="/">Feed</a></li>
+            <li><a href="/">News Feed</a></li>
             <li class="active"><a href="/issues">Issues</a></li>
             <li class="active"><a href="/issues">Issues</a></li>
             <!-- <li><a href="/pulls">Pull Requests</a></li>
             <!-- <li><a href="/pulls">Pull Requests</a></li>
             <li><a href="/stars">Stars</a></li> -->
             <li><a href="/stars">Stars</a></li> -->
@@ -11,6 +11,7 @@
         <h3>Your Issues</h3>
         <h3>Your Issues</h3>
     </div>
     </div>
 </div>
 </div>
+
 <div id="body" class="container" data-page="user">
 <div id="body" class="container" data-page="user">
     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
     <div id="issue">
     <div id="issue">