Add create organization
This commit is contained in:
parent
b2801a2e98
commit
e0f9c628c5
24 changed files with 438 additions and 197 deletions
20
cmd/serve.go
20
cmd/serve.go
|
@ -56,19 +56,19 @@ func parseCmd(cmd string) (string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
COMMANDS_READONLY = map[string]int{
|
COMMANDS_READONLY = map[string]models.AccessType{
|
||||||
"git-upload-pack": models.AU_WRITABLE,
|
"git-upload-pack": models.WRITABLE,
|
||||||
"git upload-pack": models.AU_WRITABLE,
|
"git upload-pack": models.WRITABLE,
|
||||||
"git-upload-archive": models.AU_WRITABLE,
|
"git-upload-archive": models.WRITABLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMANDS_WRITE = map[string]int{
|
COMMANDS_WRITE = map[string]models.AccessType{
|
||||||
"git-receive-pack": models.AU_READABLE,
|
"git-receive-pack": models.READABLE,
|
||||||
"git receive-pack": models.AU_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)
|
||||||
|
|
|
@ -188,14 +188,15 @@ 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.Get("/create", org.New)
|
||||||
|
r.Post("/create", bindIgnErr(auth.CreateOrganizationForm{}), org.NewPost)
|
||||||
r.Get("/:org", org.Organization)
|
r.Get("/:org", org.Organization)
|
||||||
r.Get("/:org/dashboard", org.Dashboard)
|
r.Get("/:org/dashboard", org.Dashboard)
|
||||||
r.Get("/:org/members", org.Members)
|
r.Get("/:org/members", org.Members)
|
||||||
r.Get("/:org/teams", org.Teams)
|
r.Get("/:org/teams", org.Teams)
|
||||||
r.Get("/:org/setting", org.Setting)
|
r.Get("/:org/setting", org.Setting)
|
||||||
})
|
}, 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
gogs.go
2
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.0624 Alpha"
|
const APP_VER = "0.4.5.0625 Alpha"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
|
@ -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
|
READABLE AccessType = iota + 1
|
||||||
AU_WRITABLE
|
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)"`
|
UserName string `xorm:"unique(s)"`
|
||||||
RepoName string `xorm:"unique(s)"` // <user name>/<repo name>
|
RepoName string `xorm:"unique(s)"` // <user name>/<repo name>
|
||||||
Mode int `xorm:"unique(s)"`
|
Mode AccessType `xorm:"unique(s)"`
|
||||||
Created time.Time `xorm:"created"`
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
69
models/org.go
Normal file
69
models/org.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
type AuthorizeType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ORG_READABLE AuthorizeType = iota + 1
|
||||||
|
ORG_WRITABLE
|
||||||
|
ORG_ADMIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// Team represents a organization team.
|
||||||
|
type Team struct {
|
||||||
|
Id int64
|
||||||
|
OrgId int64 `xorm:"INDEX"`
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
Authorize AuthorizeType
|
||||||
|
NumMembers int
|
||||||
|
NumRepos int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTeam creates a record of new team.
|
||||||
|
func NewTeam(t *Team) error {
|
||||||
|
_, err := x.Insert(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// ___________ ____ ___
|
||||||
|
// \__ ___/___ _____ _____ | | \______ ___________
|
||||||
|
// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
|
||||||
|
// | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
|
||||||
|
// |____| \___ >____ /__|_| /______//____ >\___ >__|
|
||||||
|
// \/ \/ \/ \/ \/
|
||||||
|
|
||||||
|
// TeamUser represents an team-user relation.
|
||||||
|
type TeamUser struct {
|
||||||
|
Id int64
|
||||||
|
Uid int64
|
||||||
|
OrgId int64 `xorm:"INDEX"`
|
||||||
|
TeamId int64
|
||||||
|
}
|
|
@ -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"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -483,7 +483,9 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
sess.Begin()
|
if err = sess.Begin(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.Insert(repo); err != nil {
|
if _, err = sess.Insert(repo); err != nil {
|
||||||
if err2 := os.RemoveAll(repoPath); err2 != nil {
|
if err2 := os.RemoveAll(repoPath); err2 != nil {
|
||||||
|
@ -495,9 +497,9 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mode := AU_WRITABLE
|
mode := WRITABLE
|
||||||
if mirror {
|
if mirror {
|
||||||
mode = AU_READABLE
|
mode = READABLE
|
||||||
}
|
}
|
||||||
access := Access{
|
access := Access{
|
||||||
UserName: user.LowerName,
|
UserName: user.LowerName,
|
||||||
|
|
190
models/user.go
190
models/user.go
|
@ -21,10 +21,11 @@ import (
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User types.
|
type UserType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UT_INDIVIDUAL = iota + 1
|
INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
|
||||||
UT_ORGANIZATION
|
ORGANIZATION
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -50,7 +51,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,36 +67,60 @@ 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.
|
||||||
|
NumTeams int
|
||||||
|
NumMembers int
|
||||||
}
|
}
|
||||||
|
|
||||||
// HomeLink returns the user home page link.
|
// HomeLink returns the user home page link.
|
||||||
func (user *User) HomeLink() string {
|
func (u *User) HomeLink() string {
|
||||||
return "/user/" + user.Name
|
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,
|
Name: u.Name,
|
||||||
Email: user.Email,
|
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() {
|
func (u *User) EncodePasswd() {
|
||||||
newPasswd := base.PBKDF2([]byte(user.Passwd), []byte(user.Salt), 10000, 50, sha256.New)
|
newPasswd := base.PBKDF2([]byte(u.Passwd), []byte(u.Salt), 10000, 50, sha256.New)
|
||||||
user.Passwd = fmt.Sprintf("%x", newPasswd)
|
u.Passwd = fmt.Sprintf("%x", newPasswd)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Member represents user is member of organization.
|
// Member represents user is member of organization.
|
||||||
|
@ -126,49 +152,135 @@ func GetUserSalt() string {
|
||||||
return base.GetRandomString(10)
|
return base.GetRandomString(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterUser creates record of a new user.
|
// CreateUser creates record of a new user.
|
||||||
func RegisterUser(user *User) (*User, error) {
|
func CreateUser(u *User) (*User, error) {
|
||||||
|
if !IsLegalName(u.Name) {
|
||||||
if !IsLegalName(user.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)
|
u.LowerName = strings.ToLower(u.Name)
|
||||||
user.Avatar = base.EncodeMd5(user.Email)
|
u.Avatar = base.EncodeMd5(u.Email)
|
||||||
user.AvatarEmail = user.Email
|
u.AvatarEmail = u.Email
|
||||||
user.Rands = GetUserSalt()
|
u.Rands = GetUserSalt()
|
||||||
user.Salt = GetUserSalt()
|
u.Salt = GetUserSalt()
|
||||||
user.EncodePasswd()
|
u.EncodePasswd()
|
||||||
if _, err = x.Insert(user); err != nil {
|
|
||||||
return nil, err
|
sess := x.NewSession()
|
||||||
} else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil {
|
defer sess.Close()
|
||||||
if _, err := x.Id(user.Id).Delete(&User{}); err != nil {
|
if err = sess.Begin(); err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf(
|
|
||||||
"both create userpath %s and delete table record faild: %v", user.Name, err))
|
|
||||||
}
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Id == 1 {
|
if _, err = sess.Insert(u); err != nil {
|
||||||
user.IsAdmin = true
|
sess.Rollback()
|
||||||
user.IsActive = true
|
return nil, err
|
||||||
_, err = x.Id(user.Id).UseBool().Update(user)
|
|
||||||
}
|
}
|
||||||
return user, err
|
|
||||||
|
if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = sess.Commit(); err != nil {
|
||||||
|
return nil, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.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",
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsers returns given number of user objects with offset.
|
// GetUsers returns given number of user objects with offset.
|
||||||
|
|
33
modules/auth/org.go
Normal file
33
modules/auth/org.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// 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 CreateOrganizationForm struct {
|
||||||
|
OrgName string `form:"orgname" binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||||
|
Email string `form:"email" binding:"Required;Email;MaxSize(50)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CreateOrganizationForm) Name(field string) string {
|
||||||
|
names := map[string]string{
|
||||||
|
"OrgName": "Organization name",
|
||||||
|
"Email": "E-mail address",
|
||||||
|
}
|
||||||
|
return names[field]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CreateOrganizationForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) {
|
||||||
|
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
|
||||||
|
validate(errs, data, f)
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -67,7 +67,7 @@ func NewUserPost(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.RenderWithErr("Username has been already taken", USER_NEW, &form)
|
ctx.RenderWithErr("Username has been already taken", USER_NEW, &form)
|
||||||
|
@ -76,7 +76,7 @@ func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) {
|
||||||
case models.ErrUserNameIllegal:
|
case models.ErrUserNameIllegal:
|
||||||
ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), USER_NEW, &form)
|
ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), USER_NEW, &form)
|
||||||
default:
|
default:
|
||||||
ctx.Handle(500, "admin.user.NewUser(RegisterUser)", err)
|
ctx.Handle(500, "admin.user.NewUser(CreateUser)", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,7 +227,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
|
||||||
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
|
||||||
|
|
|
@ -1,33 +1,117 @@
|
||||||
|
// 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Organization(ctx *middleware.Context, params martini.Params) {
|
func Organization(ctx *middleware.Context, params martini.Params) {
|
||||||
ctx.Data["Title"] = "Organization "+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) {
|
func Members(ctx *middleware.Context, params martini.Params) {
|
||||||
ctx.Data["Title"] = "Organization "+params["org"]+" Members"
|
ctx.Data["Title"] = "Organization " + params["org"] + " Members"
|
||||||
ctx.HTML(200, "org/members")
|
ctx.HTML(200, "org/members")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Teams(ctx *middleware.Context, params martini.Params) {
|
func Teams(ctx *middleware.Context, params martini.Params) {
|
||||||
ctx.Data["Title"] = "Organization "+params["org"]+" Teams"
|
ctx.Data["Title"] = "Organization " + params["org"] + " Teams"
|
||||||
ctx.HTML(200, "org/teams")
|
ctx.HTML(200, "org/teams")
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx *middleware.Context) {
|
func New(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = "Create an Organization"
|
ctx.Data["Title"] = "Create An Organization"
|
||||||
ctx.HTML(200, "org/new")
|
ctx.HTML(200, NEW)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPost(ctx *middleware.Context, form auth.CreateOrganizationForm) {
|
||||||
|
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) {
|
func Dashboard(ctx *middleware.Context, params martini.Params) {
|
||||||
ctx.Data["Title"] = "Dashboard"
|
ctx.Data["Title"] = "Dashboard"
|
||||||
ctx.HTML(200, "org/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 Setting(ctx *middleware.Context, param martini.Params) {
|
func Setting(ctx *middleware.Context, param martini.Params) {
|
||||||
|
|
|
@ -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 {
|
if tp == models.READABLE {
|
||||||
has, err = models.HasAccess(authUsername, username+"/"+reponame, models.AU_WRITABLE)
|
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
|
||||||
|
|
|
@ -175,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
|
||||||
|
@ -196,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
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
const (
|
const (
|
||||||
DASHBOARD base.TplName = "user/dashboard"
|
DASHBOARD base.TplName = "user/dashboard"
|
||||||
PROFILE base.TplName = "user/profile"
|
PROFILE base.TplName = "user/profile"
|
||||||
ISSUES base.TplName = "user/issue"
|
ISSUES base.TplName = "user/issues"
|
||||||
PULLS base.TplName = "user/pulls"
|
PULLS base.TplName = "user/pulls"
|
||||||
STARS base.TplName = "user/stars"
|
STARS base.TplName = "user/stars"
|
||||||
)
|
)
|
||||||
|
@ -29,6 +29,13 @@ 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 {
|
||||||
|
@ -53,7 +60,7 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ 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
|
||||||
|
@ -235,13 +235,14 @@ func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) {
|
||||||
ctx.Data["Err_Email"] = true
|
ctx.Data["Err_Email"] = true
|
||||||
ctx.RenderWithErr("E-mail address has been already used", SIGNUP, &form)
|
ctx.RenderWithErr("E-mail address has been already used", SIGNUP, &form)
|
||||||
case models.ErrUserNameIllegal:
|
case models.ErrUserNameIllegal:
|
||||||
|
ctx.Data["Err_UserName"] = true
|
||||||
ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), SIGNUP, &form)
|
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 {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.4.5.0624 Alpha
|
0.4.5.0625 Alpha
|
|
@ -1,73 +0,0 @@
|
||||||
{{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="//1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132?s=28" alt="user-avatar" title="username">
|
|
||||||
gogits
|
|
||||||
</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 class="checked"><a href="#"><i class="fa fa-check"></i>
|
|
||||||
<img src="//1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132?s=28" alt="user-avatar" title="username">
|
|
||||||
gogits/gogs</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ul class="nav nav-pills pull-right">
|
|
||||||
<li class="active"><a href="/">Feed</a></li>
|
|
||||||
<li><a href="/issues">Issues</a></li>
|
|
||||||
<li><a href="#">Setting</a></li>
|
|
||||||
<!-- <li><a href="/pulls">Pull Requests</a></li>
|
|
||||||
<li><a href="/stars">Stars</a></li> -->
|
|
||||||
</ul>
|
|
||||||
<h3>News Feed</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body" class="container" data-page="user">
|
|
||||||
{{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}}
|
|
||||||
<div id="feed-left" class="col-md-8">
|
|
||||||
<ul class="list-unstyled activity-list">
|
|
||||||
{{range .Feeds}}
|
|
||||||
<li>
|
|
||||||
<i class="icon fa fa-{{ActionIcon .OpType}}"></i>
|
|
||||||
<div class="info"><span class="meta">{{TimeSince .Created}}</span><br>{{ActionDesc . | str2html}}</div>
|
|
||||||
<span class="clearfix"></span>
|
|
||||||
</li>
|
|
||||||
{{else}}
|
|
||||||
<li>Oh. Looks like there isn't any activity here yet. Get Busy!</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div id="feed-right" class="col-md-4">
|
|
||||||
<div class="panel panel-default repo-panel">
|
|
||||||
<div class="panel-heading">Repositories
|
|
||||||
<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>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right">
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li><a href="/repo/create"><i class="fa fa-book"></i>Repository</a></li>
|
|
||||||
<li><a href="/repo/migrate"><i class="fa fa-clipboard"></i>Migration</a></li>
|
|
||||||
<!-- <li><a href="#"><i class="fa fa-users"></i>Organization</a></li> -->
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-body">
|
|
||||||
<ul class="list-group">{{range .MyRepos}}
|
|
||||||
<li class="list-group-item"><a href="/{{$.SignedUserName}}/{{.Name}}">
|
|
||||||
<!-- <span class="stars pull-right"><i class="fa fa-star"></i>{{.NumStars}}</span> -->
|
|
||||||
<i class="fa fa-book"></i>{{.Name}}{{if .IsPrivate}} <span class="label label-default">Private</span>{{end}}</a>
|
|
||||||
</li>{{end}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{template "base/footer" .}}
|
|
|
@ -1,22 +1,14 @@
|
||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
{{template "base/navbar" .}}
|
{{template "base/navbar" .}}
|
||||||
<div class="container" id="body">
|
<div class="container" id="body">
|
||||||
<form action="/repo/create" method="post" class="form-horizontal card" id="org-create">
|
<form action="/org/create" method="post" class="form-horizontal card" id="org-create">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<h3>Create New Organization</h3>
|
<h3>Create New Organization</h3>
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<div class="form-group">
|
<div class="form-group {{if .Err_OrgName}}has-error has-feedback{{end}}">
|
||||||
<label class="col-md-2 control-label">Owner<strong class="text-danger">*</strong></label>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<p class="form-control-static">{{.SignedUserName}}</p>
|
|
||||||
<input type="hidden" value="{{.SignedUserId}}" name="userId"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group {{if .Err_RepoName}}has-error has-feedback{{end}}">
|
|
||||||
<label class="col-md-2 control-label">Organization<strong class="text-danger">*</strong></label>
|
<label class="col-md-2 control-label">Organization<strong class="text-danger">*</strong></label>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<input name="repo" type="text" class="form-control" placeholder="Type your repository name" value="{{.repo}}" required="required">
|
<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>
|
<span class="help-block">Great organization names are short and memorable. </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,18 +16,10 @@
|
||||||
<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}">
|
<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>
|
<label class="col-md-2 control-label">Email<strong class="text-danger">*</strong></label>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<input name="email" type="text" class="form-control" placeholder="Type organization's email" value="" required="required">
|
<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>
|
<span class="help-block">Organization's Email receives all notifications and confirmations.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-md-2 control-label">Owners<strong class="text-danger">*</strong></label>
|
|
||||||
<div class="col-md-8">
|
|
||||||
owners
|
|
||||||
</div>
|
|
||||||
</div>-->
|
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-offset-2 col-md-8">
|
<div class="col-md-offset-2 col-md-8">
|
||||||
|
|
|
@ -4,29 +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">
|
<img src="{{.ContextUser.AvatarLink}}?s=28" alt="user-avatar" title="username">
|
||||||
fuxiaohei
|
{{.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>
|
<li{{if not .PageIsOrgDashboard}} class="checked"{{end}}>
|
||||||
<img src="//1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132?s=28" alt="user-avatar" title="username">
|
<a href="/">
|
||||||
gogits/gogs</a></li>
|
<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 class="active"><a href="/{{if .PageIsOrgDashboard}}org/{{.ContextUser.Name}}/dashboard{{end}}">News Feed</a></li>
|
||||||
<li><a href="/issues">Issues</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">
|
||||||
|
@ -44,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">
|
||||||
|
@ -66,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">
|
||||||
|
@ -78,6 +96,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Reference in a new issue