@@ -5,7 +5,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra | |||
![](public/img/gogs-large-resize.png) | |||
##### Current version: 0.7.38 Beta | |||
##### Current version: 0.7.39 Beta | |||
| Web | UI | Preview | | |||
|:-------------:|:-------:|:-------:| |
@@ -86,7 +86,7 @@ func checkVersion() { | |||
{"github.com/go-macaron/i18n", i18n.Version, "0.2.0"}, | |||
{"github.com/go-macaron/session", session.Version, "0.1.6"}, | |||
{"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"}, | |||
{"gopkg.in/ini.v1", ini.Version, "1.8.1"}, | |||
{"gopkg.in/ini.v1", ini.Version, "1.8.3"}, | |||
{"gopkg.in/macaron.v1", macaron.Version, "0.8.0"}, | |||
{"github.com/gogits/git-shell", git.Version, "0.1.0"}, | |||
} |
@@ -15,6 +15,8 @@ SCRIPT_TYPE = bash | |||
ANSI_CHARSET = | |||
; Force every new repository to be private | |||
FORCE_PRIVATE = false | |||
; Global maximum creation limit of repository per user, 0 means no limit | |||
MAX_CREATION_LIMIT = 0 | |||
; Patch test queue length, make it as large as possible | |||
PULL_REQUEST_QUEUE_LENGTH = 10000 | |||
@@ -359,6 +359,7 @@ watchers = Watchers | |||
stargazers = Stargazers | |||
forks = Forks | |||
form.reach_limit_of_creation = The owner has reached maximum creation limit of %d repositories. | |||
form.name_reserved = Repository name '%s' is reserved. | |||
form.name_pattern_not_allowed = Repository name pattern '%s' is not allowed. | |||
@@ -855,6 +856,8 @@ users.auth_login_name = Authentication Login Name | |||
users.password_helper = Leave it empty to remain unchanged. | |||
users.update_profile_success = Account profile has been updated successfully. | |||
users.edit_account = Edit Account | |||
users.max_repo_creation = Maximum Repository Creation Limit | |||
users.max_repo_creation_desc = (Set 0 to use gloabl default limit) | |||
users.is_activated = This account is activated | |||
users.is_admin = This account has administrator permissions | |||
users.allow_git_hook = This account has permissions to create Git hooks |
@@ -18,7 +18,7 @@ import ( | |||
"github.com/gogits/gogs/modules/setting" | |||
) | |||
const APP_VER = "0.7.38.1210 Beta" | |||
const APP_VER = "0.7.39.1210 Beta" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -107,6 +107,19 @@ func (err ErrUserHasOrgs) Error() string { | |||
return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) | |||
} | |||
type ErrReachLimitOfRepo struct { | |||
Limit int | |||
} | |||
func IsErrReachLimitOfRepo(err error) bool { | |||
_, ok := err.(ErrReachLimitOfRepo) | |||
return ok | |||
} | |||
func (err ErrReachLimitOfRepo) Error() string { | |||
return fmt.Sprintf("user has reached maximum limit of repositories [limit: %d]", err.Limit) | |||
} | |||
// __ __.__ __ .__ | |||
// / \ / \__| | _|__| | |||
// \ \/\/ / | |/ / | |
@@ -900,6 +900,10 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) { | |||
// CreateRepository creates a repository for given user or organization. | |||
func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error) { | |||
if !u.CanCreateRepo() { | |||
return nil, ErrReachLimitOfRepo{u.MaxRepoCreation} | |||
} | |||
repo := &Repository{ | |||
OwnerID: u.Id, | |||
Owner: u, |
@@ -75,6 +75,8 @@ type User struct { | |||
// Remember visibility choice for convenience, true for private | |||
LastRepoVisibility bool | |||
// Maximum repository creation limit, 0 means use gloabl default | |||
MaxRepoCreation int `xorm:"NOT NULL"` | |||
// Permissions. | |||
IsActive bool | |||
@@ -101,6 +103,12 @@ type User struct { | |||
Members []*User `xorm:"-"` | |||
} | |||
func (u *User) BeforeUpdate() { | |||
if u.MaxRepoCreation < 0 { | |||
u.MaxRepoCreation = 0 | |||
} | |||
} | |||
func (u *User) AfterSet(colName string, _ xorm.Cell) { | |||
switch colName { | |||
case "full_name": | |||
@@ -116,6 +124,20 @@ func (u *User) HasForkedRepo(repoID int64) bool { | |||
return has | |||
} | |||
func (u *User) RepoCreationNum() int { | |||
if u.MaxRepoCreation == 0 { | |||
return setting.Repository.MaxCreationLimit | |||
} | |||
return u.MaxRepoCreation | |||
} | |||
func (u *User) CanCreateRepo() bool { | |||
if u.MaxRepoCreation == 0 { | |||
return u.NumRepos < setting.Repository.MaxCreationLimit | |||
} | |||
return u.NumRepos < u.MaxRepoCreation | |||
} | |||
// CanEditGitHook returns true if user can edit Git hooks. | |||
func (u *User) CanEditGitHook() bool { | |||
return u.IsAdmin || u.AllowGitHook |
@@ -31,6 +31,7 @@ type AdminEditUserForm struct { | |||
Password string `binding:"MaxSize(255)"` | |||
Website string `binding:"MaxSize(50)"` | |||
Location string `binding:"MaxSize(50)"` | |||
MaxRepoCreation int | |||
Active bool | |||
Admin bool | |||
AllowGitHook bool |
@@ -98,6 +98,7 @@ var ( | |||
Repository struct { | |||
AnsiCharset string | |||
ForcePrivate bool | |||
MaxCreationLimit int | |||
PullRequestQueueLength int | |||
} | |||
RepoRootPath string | |||
@@ -379,9 +380,9 @@ func NewContext() { | |||
RepoRootPath = path.Clean(RepoRootPath) | |||
} | |||
ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") | |||
Repository.AnsiCharset = sec.Key("ANSI_CHARSET").String() | |||
Repository.ForcePrivate = sec.Key("FORCE_PRIVATE").MustBool() | |||
Repository.PullRequestQueueLength = sec.Key("PULL_REQUEST_QUEUE_LENGTH").MustInt(10000) | |||
if err = Cfg.Section("repository").MapTo(&Repository); err != nil { | |||
log.Fatal(4, "Fail to map Repository settings: %v", err) | |||
} | |||
// UI settings. | |||
sec = Cfg.Section("ui") |
@@ -210,6 +210,7 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) { | |||
u.Email = form.Email | |||
u.Website = form.Website | |||
u.Location = form.Location | |||
u.MaxRepoCreation = form.MaxRepoCreation | |||
u.IsActive = form.Active | |||
u.IsAdmin = form.Admin | |||
u.AllowGitHook = form.AllowGitHook |
@@ -78,8 +78,10 @@ func Create(ctx *middleware.Context) { | |||
ctx.HTML(200, CREATE) | |||
} | |||
func handleCreateError(ctx *middleware.Context, err error, name string, tpl base.TplName, form interface{}) { | |||
func handleCreateError(ctx *middleware.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) { | |||
switch { | |||
case models.IsErrReachLimitOfRepo(err): | |||
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.RepoCreationNum()), tpl, form) | |||
case models.IsErrRepoAlreadyExist(err): | |||
ctx.Data["Err_RepoName"] = true | |||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form) | |||
@@ -133,7 +135,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
} | |||
} | |||
handleCreateError(ctx, err, "CreatePost", CREATE, &form) | |||
handleCreateError(ctx, ctxUser, err, "CreatePost", CREATE, &form) | |||
} | |||
func Migrate(ctx *middleware.Context) { | |||
@@ -216,7 +218,7 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { | |||
return | |||
} | |||
handleCreateError(ctx, err, "MigratePost", MIGRATE, &form) | |||
handleCreateError(ctx, ctxUser, err, "MigratePost", MIGRATE, &form) | |||
} | |||
func Action(ctx *middleware.Context) { |
@@ -1 +1 @@ | |||
0.7.38.1210 Beta | |||
0.7.39.1210 Beta |
@@ -57,6 +57,16 @@ | |||
<input id="location" name="location" value="{{.User.Location}}"> | |||
</div> | |||
<div class="ui divider"></div> | |||
<div class="inline field {{if .Err_MaxRepoCreation}}error{{end}}"> | |||
<label for="max_repo_creation">{{.i18n.Tr "admin.users.max_repo_creation"}}</label> | |||
<input id="max_repo_creation" name="max_repo_creation" type="number" value="{{.User.MaxRepoCreation}}"> | |||
<p class="help">{{.i18n.Tr "admin.users.max_repo_creation_desc"}}</p> | |||
</div> | |||
<div class="ui divider"></div> | |||
<div class="inline field"> | |||
<div class="ui checkbox"> | |||
<label><strong>{{.i18n.Tr "admin.users.is_activated"}}</strong></label> |