@@ -351,6 +351,11 @@ DEFAULT_KEEP_EMAIL_PRIVATE = false | |||
; Default value for AllowCreateOrganization | |||
; Every new user will have rights set to create organizations depending on this setting | |||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true | |||
; Either "public", "limited" or "private", default is "public" | |||
; Limited is for signed user only | |||
; Private is only for member of the organization | |||
; Public is for everyone | |||
DEFAULT_ORG_VISIBILITY = public | |||
; Default value for EnableDependencies | |||
; Repositories will use dependencies by default depending on this setting | |||
DEFAULT_ENABLE_DEPENDENCIES = true |
@@ -147,7 +147,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. | |||
- `PATH`: **data/gitea.db**: For SQLite3 only, the database file path. | |||
- `LOG_SQL`: **true**: Log the executed SQL. | |||
- `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed. | |||
- `DB_RETRY_BACKOFF`: **3s*: time.Duration to wait before trying another ORM init / DB connect attempt, if failure occured. | |||
- `DB_RETRY_BACKOFF`: **3s**: time.Duration to wait before trying another ORM init / DB connect attempt, if failure occured. | |||
## Indexer (`indexer`) | |||
@@ -203,12 +203,13 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. | |||
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\] | |||
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. | |||
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. | |||
- `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default. | |||
- `ENABLE_USER_HEATMAP`: **true** Enable this to display the heatmap on users profiles. | |||
- `DEFAULT_ENABLE_DEPENDENCIES`: **true**: Enable this to have dependencies enabled by default. | |||
- `ENABLE_USER_HEATMAP`: **true**: Enable this to display the heatmap on users profiles. | |||
- `EMAIL_DOMAIN_WHITELIST`: **\<empty\>**: If non-empty, list of domain names that can only be used to register | |||
on this instance. | |||
- `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button | |||
- `AUTO_WATCH_NEW_REPOS`: **true** Enable this to let all organisation users watch new repos when they are created | |||
- `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created | |||
- `DEFAULT_ORG_VISIBILITY`: **public**: Set default visibility mode for organisations, either "public", "limited" or "private". | |||
## Webhook (`webhook`) | |||
@@ -1,4 +1,5 @@ | |||
// Copyright 2015 The Gogs Authors. All rights reserved. | |||
// Copyright 2017 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -1,4 +1,5 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -11,6 +12,7 @@ import ( | |||
"strings" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/structs" | |||
"github.com/Unknwon/com" | |||
"github.com/go-xorm/builder" | |||
@@ -366,6 +368,40 @@ func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) { | |||
Find(&orgs) | |||
} | |||
// HasOrgVisible tells if the given user can see the given org | |||
func HasOrgVisible(org *User, user *User) bool { | |||
// Not SignedUser | |||
if user == nil { | |||
if org.Visibility == structs.VisibleTypePublic { | |||
return true | |||
} | |||
return false | |||
} | |||
if user.IsAdmin { | |||
return true | |||
} | |||
if org.Visibility == structs.VisibleTypePrivate && !org.IsUserPartOfOrg(user.ID) { | |||
return false | |||
} | |||
return true | |||
} | |||
// HasOrgsVisible tells if the given user can see at least one of the orgs provided | |||
func HasOrgsVisible(orgs []*User, user *User) bool { | |||
if len(orgs) == 0 { | |||
return false | |||
} | |||
for _, org := range orgs { | |||
if HasOrgVisible(org, user) { | |||
return true | |||
} | |||
} | |||
return false | |||
} | |||
// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID. | |||
func GetOwnedOrgsByUserID(userID int64) ([]*User, error) { | |||
sess := x.NewSession() |
@@ -7,6 +7,8 @@ package models | |||
import ( | |||
"testing" | |||
"code.gitea.io/gitea/modules/structs" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
@@ -545,3 +547,72 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) { | |||
testSuccess(2, []int64{5}) | |||
testSuccess(4, []int64{}) | |||
} | |||
func TestHasOrgVisibleTypePublic(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
owner := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | |||
user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) | |||
const newOrgName = "test-org-public" | |||
org := &User{ | |||
Name: newOrgName, | |||
Visibility: structs.VisibleTypePublic, | |||
} | |||
AssertNotExistsBean(t, &User{Name: org.Name, Type: UserTypeOrganization}) | |||
assert.NoError(t, CreateOrganization(org, owner)) | |||
org = AssertExistsAndLoadBean(t, | |||
&User{Name: org.Name, Type: UserTypeOrganization}).(*User) | |||
test1 := HasOrgVisible(org, owner) | |||
test2 := HasOrgVisible(org, user3) | |||
test3 := HasOrgVisible(org, nil) | |||
assert.Equal(t, test1, true) // owner of org | |||
assert.Equal(t, test2, true) // user not a part of org | |||
assert.Equal(t, test3, true) // logged out user | |||
} | |||
func TestHasOrgVisibleTypeLimited(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
owner := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | |||
user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) | |||
const newOrgName = "test-org-limited" | |||
org := &User{ | |||
Name: newOrgName, | |||
Visibility: structs.VisibleTypeLimited, | |||
} | |||
AssertNotExistsBean(t, &User{Name: org.Name, Type: UserTypeOrganization}) | |||
assert.NoError(t, CreateOrganization(org, owner)) | |||
org = AssertExistsAndLoadBean(t, | |||
&User{Name: org.Name, Type: UserTypeOrganization}).(*User) | |||
test1 := HasOrgVisible(org, owner) | |||
test2 := HasOrgVisible(org, user3) | |||
test3 := HasOrgVisible(org, nil) | |||
assert.Equal(t, test1, true) // owner of org | |||
assert.Equal(t, test2, true) // user not a part of org | |||
assert.Equal(t, test3, false) // logged out user | |||
} | |||
func TestHasOrgVisibleTypePrivate(t *testing.T) { | |||
assert.NoError(t, PrepareTestDatabase()) | |||
owner := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | |||
user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) | |||
const newOrgName = "test-org-private" | |||
org := &User{ | |||
Name: newOrgName, | |||
Visibility: structs.VisibleTypePrivate, | |||
} | |||
AssertNotExistsBean(t, &User{Name: org.Name, Type: UserTypeOrganization}) | |||
assert.NoError(t, CreateOrganization(org, owner)) | |||
org = AssertExistsAndLoadBean(t, | |||
&User{Name: org.Name, Type: UserTypeOrganization}).(*User) | |||
test1 := HasOrgVisible(org, owner) | |||
test2 := HasOrgVisible(org, user3) | |||
test3 := HasOrgVisible(org, nil) | |||
assert.Equal(t, test1, true) // owner of org | |||
assert.Equal(t, test2, false) // user not a part of org | |||
assert.Equal(t, test3, false) // logged out user | |||
} |
@@ -8,9 +8,11 @@ import ( | |||
"fmt" | |||
"strings" | |||
"code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/util" | |||
"github.com/go-xorm/builder" | |||
"github.com/go-xorm/core" | |||
) | |||
// RepositoryListDefaultPageSize is the default number of repositories | |||
@@ -171,6 +173,10 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err | |||
if !opts.Private { | |||
cond = cond.And(builder.Eq{"is_private": false}) | |||
accessCond := builder.Or( | |||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), | |||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization}))) | |||
cond = cond.And(accessCond) | |||
} | |||
if opts.OwnerID > 0 { | |||
@@ -193,6 +199,35 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err | |||
accessCond = accessCond.Or(collaborateCond) | |||
} | |||
var exprCond builder.Cond | |||
if DbCfg.Type == core.POSTGRES { | |||
exprCond = builder.Expr("org_user.org_id = \"user\".id") | |||
} else if DbCfg.Type == core.MSSQL { | |||
exprCond = builder.Expr("org_user.org_id = [user].id") | |||
} else { | |||
exprCond = builder.Eq{"org_user.org_id": "user.id"} | |||
} | |||
visibilityCond := builder.Or( | |||
builder.In("owner_id", | |||
builder.Select("org_id").From("org_user"). | |||
LeftJoin("`user`", exprCond). | |||
Where( | |||
builder.And( | |||
builder.Eq{"uid": opts.OwnerID}, | |||
builder.Eq{"visibility": structs.VisibleTypePrivate})), | |||
), | |||
builder.In("owner_id", | |||
builder.Select("id").From("`user`"). | |||
Where( | |||
builder.Or( | |||
builder.Eq{"visibility": structs.VisibleTypePublic}, | |||
builder.Eq{"visibility": structs.VisibleTypeLimited})), | |||
), | |||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})), | |||
) | |||
cond = cond.And(visibilityCond) | |||
if opts.AllPublic { | |||
accessCond = accessCond.Or(builder.Eq{"is_private": false}) | |||
} |
@@ -25,22 +25,23 @@ import ( | |||
"time" | |||
"unicode/utf8" | |||
"github.com/Unknwon/com" | |||
"github.com/go-xorm/builder" | |||
"github.com/go-xorm/xorm" | |||
"github.com/nfnt/resize" | |||
"golang.org/x/crypto/pbkdf2" | |||
"golang.org/x/crypto/ssh" | |||
"code.gitea.io/git" | |||
api "code.gitea.io/sdk/gitea" | |||
"code.gitea.io/gitea/modules/avatar" | |||
"code.gitea.io/gitea/modules/base" | |||
"code.gitea.io/gitea/modules/generate" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/util" | |||
api "code.gitea.io/sdk/gitea" | |||
"github.com/Unknwon/com" | |||
"github.com/go-xorm/builder" | |||
"github.com/go-xorm/core" | |||
"github.com/go-xorm/xorm" | |||
"github.com/nfnt/resize" | |||
"golang.org/x/crypto/pbkdf2" | |||
"golang.org/x/crypto/ssh" | |||
) | |||
// UserType defines the user type | |||
@@ -136,8 +137,9 @@ type User struct { | |||
Description string | |||
NumTeams int | |||
NumMembers int | |||
Teams []*Team `xorm:"-"` | |||
Members []*User `xorm:"-"` | |||
Teams []*Team `xorm:"-"` | |||
Members []*User `xorm:"-"` | |||
Visibility structs.VisibleType `xorm:"NOT NULL DEFAULT 0"` | |||
// Preferences | |||
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` | |||
@@ -526,6 +528,16 @@ func (u *User) IsUserOrgOwner(orgID int64) bool { | |||
return isOwner | |||
} | |||
// IsUserPartOfOrg returns true if user with userID is part of the u organisation. | |||
func (u *User) IsUserPartOfOrg(userID int64) bool { | |||
isMember, err := IsOrganizationMember(u.ID, userID) | |||
if err != nil { | |||
log.Error(4, "IsOrganizationMember: %v", err) | |||
return false | |||
} | |||
return isMember | |||
} | |||
// IsPublicMember returns true if user public his/her membership in given organization. | |||
func (u *User) IsPublicMember(orgID int64) bool { | |||
isMember, err := IsPublicMembership(orgID, u.ID) | |||
@@ -1341,13 +1353,18 @@ type SearchUserOptions struct { | |||
UID int64 | |||
OrderBy SearchOrderBy | |||
Page int | |||
PageSize int // Can be smaller than or equal to setting.UI.ExplorePagingNum | |||
Private bool // Include private orgs in search | |||
OwnerID int64 // id of user for visibility calculation | |||
PageSize int // Can be smaller than or equal to setting.UI.ExplorePagingNum | |||
IsActive util.OptionalBool | |||
SearchByEmail bool // Search by email as well as username/full name | |||
} | |||
func (opts *SearchUserOptions) toConds() builder.Cond { | |||
var cond builder.Cond = builder.Eq{"type": opts.Type} | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Eq{"type": opts.Type}) | |||
if len(opts.Keyword) > 0 { | |||
lowerKeyword := strings.ToLower(opts.Keyword) | |||
keywordCond := builder.Or( | |||
@@ -1361,6 +1378,27 @@ func (opts *SearchUserOptions) toConds() builder.Cond { | |||
cond = cond.And(keywordCond) | |||
} | |||
if !opts.Private { | |||
// user not logged in and so they won't be allowed to see non-public orgs | |||
cond = cond.And(builder.In("visibility", structs.VisibleTypePublic)) | |||
} | |||
if opts.OwnerID > 0 { | |||
var exprCond builder.Cond | |||
if DbCfg.Type == core.MYSQL { | |||
exprCond = builder.Expr("org_user.org_id = user.id") | |||
} else if DbCfg.Type == core.MSSQL { | |||
exprCond = builder.Expr("org_user.org_id = [user].id") | |||
} else { | |||
exprCond = builder.Expr("org_user.org_id = \"user\".id") | |||
} | |||
var accessCond = builder.NewCond() | |||
accessCond = builder.Or( | |||
builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.OwnerID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))), | |||
builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited)) | |||
cond = cond.And(accessCond) | |||
} | |||
if opts.UID > 0 { | |||
cond = cond.And(builder.Eq{"id": opts.UID}) | |||
} |
@@ -1,4 +1,5 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -6,6 +7,7 @@ package auth | |||
import ( | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/structs" | |||
"github.com/go-macaron/binding" | |||
"gopkg.in/macaron.v1" | |||
@@ -20,7 +22,8 @@ import ( | |||
// CreateOrgForm form for creating organization | |||
type CreateOrgForm struct { | |||
OrgName string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"` | |||
OrgName string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"` | |||
Visibility structs.VisibleType | |||
} | |||
// Validate validates the fields | |||
@@ -35,6 +38,7 @@ type UpdateOrgSettingForm struct { | |||
Description string `binding:"MaxSize(255)"` | |||
Website string `binding:"ValidUrl;MaxSize(255)"` | |||
Location string `binding:"MaxSize(50)"` | |||
Visibility structs.VisibleType | |||
MaxRepoCreation int | |||
} | |||
@@ -4,10 +4,16 @@ | |||
package setting | |||
import "regexp" | |||
import ( | |||
"regexp" | |||
"code.gitea.io/gitea/modules/structs" | |||
) | |||
// Service settings | |||
var Service struct { | |||
DefaultOrgVisibility string | |||
DefaultOrgVisibilityMode structs.VisibleType | |||
ActiveCodeLives int | |||
ResetPwdCodeLives int | |||
RegisterEmailConfirm bool | |||
@@ -68,6 +74,8 @@ func newService() { | |||
Service.NoReplyAddress = sec.Key("NO_REPLY_ADDRESS").MustString("noreply.example.org") | |||
Service.EnableUserHeatmap = sec.Key("ENABLE_USER_HEATMAP").MustBool(true) | |||
Service.AutoWatchNewRepos = sec.Key("AUTO_WATCH_NEW_REPOS").MustBool(true) | |||
Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes)) | |||
Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility] | |||
sec = Cfg.Section("openid") | |||
Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock) |
@@ -0,0 +1,49 @@ | |||
// Copyright 2019 The Gitea 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 structs | |||
// VisibleType defines the visibility (Organization only) | |||
type VisibleType int | |||
const ( | |||
// VisibleTypePublic Visible for everyone | |||
VisibleTypePublic VisibleType = iota | |||
// VisibleTypeLimited Visible for every connected user | |||
VisibleTypeLimited | |||
// VisibleTypePrivate Visible only for organization's members | |||
VisibleTypePrivate | |||
) | |||
// VisibilityModes is a map of org Visibility types | |||
var VisibilityModes = map[string]VisibleType{ | |||
"public": VisibleTypePublic, | |||
"limited": VisibleTypeLimited, | |||
"private": VisibleTypePrivate, | |||
} | |||
// IsPublic returns true if VisibleType is public | |||
func (vt VisibleType) IsPublic() bool { | |||
return vt == VisibleTypePublic | |||
} | |||
// IsLimited returns true if VisibleType is limited | |||
func (vt VisibleType) IsLimited() bool { | |||
return vt == VisibleTypeLimited | |||
} | |||
// IsPrivate returns true if VisibleType is private | |||
func (vt VisibleType) IsPrivate() bool { | |||
return vt == VisibleTypePrivate | |||
} | |||
// ExtractKeysFromMapString provides a slice of keys from map | |||
func ExtractKeysFromMapString(in map[string]VisibleType) (keys []string) { | |||
for k := range in { | |||
keys = append(keys, k) | |||
} | |||
return | |||
} |
@@ -1314,6 +1314,11 @@ settings.options = Organization | |||
settings.full_name = Full Name | |||
settings.website = Website | |||
settings.location = Location | |||
settings.visibility = Visibility | |||
settings.visibility.public = Public | |||
settings.visibility.limited = Limited (Visible to logged in users only) | |||
settings.visibility.private = Private (Visible only to organization members) | |||
settings.update_settings = Update Settings | |||
settings.update_setting_success = Organization settings have been updated. | |||
settings.change_orgname_prompt = Note: changing the organization name also changes the organization's URL. | |||
@@ -1617,6 +1622,7 @@ config.enable_timetracking = Enable Time Tracking | |||
config.default_enable_timetracking = Enable Time Tracking by Default | |||
config.default_allow_only_contributors_to_track_time = Let Only Contributors Track Time | |||
config.no_reply_address = Hidden Email Domain | |||
config.default_visibility_organization = Default visibility for new Organizations | |||
config.default_enable_dependencies = Enable Issue Dependencies by Default | |||
config.webhook_config = Webhook Configuration |
@@ -129,6 +129,10 @@ func Get(ctx *context.APIContext) { | |||
// responses: | |||
// "200": | |||
// "$ref": "#/responses/Organization" | |||
if !models.HasOrgVisible(ctx.Org.Organization, ctx.User) { | |||
ctx.NotFound("HasOrgVisible", nil) | |||
return | |||
} | |||
ctx.JSON(200, convert.ToOrganization(ctx.Org.Organization)) | |||
} | |||
@@ -302,6 +302,11 @@ func CreateOrgRepo(ctx *context.APIContext, opt api.CreateRepoOption) { | |||
return | |||
} | |||
if !models.HasOrgVisible(org, ctx.User) { | |||
ctx.NotFound("HasOrgVisible", nil) | |||
return | |||
} | |||
if !ctx.User.IsAdmin { | |||
isOwner, err := org.IsOwnedBy(ctx.User.ID) | |||
if err != nil { |
@@ -1,4 +1,5 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -230,6 +231,7 @@ func ExploreUsers(ctx *context.Context) { | |||
Type: models.UserTypeIndividual, | |||
PageSize: setting.UI.ExplorePagingNum, | |||
IsActive: util.OptionalBoolTrue, | |||
Private: true, | |||
}, tplExploreUsers) | |||
} | |||
@@ -240,9 +242,16 @@ func ExploreOrganizations(ctx *context.Context) { | |||
ctx.Data["PageIsExploreOrganizations"] = true | |||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled | |||
var ownerID int64 | |||
if ctx.User != nil && !ctx.User.IsAdmin { | |||
ownerID = ctx.User.ID | |||
} | |||
RenderUserSearch(ctx, &models.SearchUserOptions{ | |||
Type: models.UserTypeOrganization, | |||
PageSize: setting.UI.ExplorePagingNum, | |||
Private: ctx.User != nil, | |||
OwnerID: ownerID, | |||
}, tplExploreOrganizations) | |||
} | |||
@@ -1,4 +1,5 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Copyright 2018 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -23,6 +24,7 @@ const ( | |||
// Create render the page for create organization | |||
func Create(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("new_org") | |||
ctx.Data["DefaultOrgVisibilityMode"] = setting.Service.DefaultOrgVisibilityMode | |||
if !ctx.User.CanCreateOrganization() { | |||
ctx.ServerError("Not allowed", errors.New(ctx.Tr("org.form.create_org_not_allowed"))) | |||
return | |||
@@ -45,9 +47,10 @@ func CreatePost(ctx *context.Context, form auth.CreateOrgForm) { | |||
} | |||
org := &models.User{ | |||
Name: form.OrgName, | |||
IsActive: true, | |||
Type: models.UserTypeOrganization, | |||
Name: form.OrgName, | |||
IsActive: true, | |||
Type: models.UserTypeOrganization, | |||
Visibility: form.Visibility, | |||
} | |||
if err := models.CreateOrganization(org, ctx.User); err != nil { |
@@ -1,4 +1,5 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -13,6 +14,7 @@ import ( | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/structs" | |||
userSetting "code.gitea.io/gitea/routers/user/setting" | |||
) | |||
@@ -29,6 +31,7 @@ const ( | |||
func Settings(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("org.settings") | |||
ctx.Data["PageIsSettingsOptions"] = true | |||
ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility) | |||
ctx.HTML(200, tplSettingsOptions) | |||
} | |||
@@ -79,6 +82,7 @@ func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) { | |||
org.Description = form.Description | |||
org.Website = form.Website | |||
org.Location = form.Location | |||
org.Visibility = form.Visibility | |||
if err := models.UpdateUser(org); err != nil { | |||
ctx.ServerError("UpdateUser", err) | |||
return |
@@ -303,6 +303,11 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st | |||
// Home render repository home page | |||
func Home(ctx *context.Context) { | |||
if !models.HasOrgVisible(ctx.Repo.Repository.Owner, ctx.User) { | |||
ctx.NotFound("HasOrgVisible", nil) | |||
return | |||
} | |||
if len(ctx.Repo.Units) > 0 { | |||
var firstUnit *models.Unit | |||
for _, repoUnit := range ctx.Repo.Units { |
@@ -386,6 +386,12 @@ func showOrgProfile(ctx *context.Context) { | |||
} | |||
org := ctx.Org.Organization | |||
if !models.HasOrgVisible(org, ctx.User) { | |||
ctx.NotFound("HasOrgVisible", nil) | |||
return | |||
} | |||
ctx.Data["Title"] = org.DisplayName() | |||
var orderBy models.SearchOrderBy |
@@ -1,4 +1,5 @@ | |||
// Copyright 2015 The Gogs Authors. All rights reserved. | |||
// Copyright 2019 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
@@ -98,6 +99,7 @@ func Profile(ctx *context.Context) { | |||
} | |||
ctx.Data["Orgs"] = orgs | |||
ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User) | |||
tab := ctx.Query("tab") | |||
ctx.Data["TabName"] = tab |
@@ -148,6 +148,9 @@ | |||
<dt>{{.i18n.Tr "admin.config.default_allow_only_contributors_to_track_time"}}</dt> | |||
<dd><i class="fa fa{{if .Service.DefaultAllowOnlyContributorsToTrackTime}}-check{{end}}-square-o"></i></dd> | |||
{{end}} | |||
<dt>{{.i18n.Tr "admin.config.default_visibility_organization"}}</dt> | |||
<dd>{{.Service.DefaultOrgVisibility}}</dd> | |||
<dt>{{.i18n.Tr "admin.config.no_reply_address"}}</dt> | |||
<dd>{{if .Service.NoReplyAddress}}{{.Service.NoReplyAddress}}{{else}}-{{end}}</dd> | |||
<dt>{{.i18n.Tr "admin.config.default_enable_dependencies"}}</dt> |
@@ -29,7 +29,12 @@ | |||
{{range .Users}} | |||
<tr> | |||
<td>{{.ID}}</td> | |||
<td><a href="{{.HomeLink}}">{{.Name}}</a></td> | |||
<td> | |||
<a href="{{.HomeLink}}">{{.Name}}</a> | |||
{{if .Visibility.IsPrivate}} | |||
<span class="text gold"><i class="octicon octicon-lock"></i></span> | |||
{{end}} | |||
</td> | |||
<td>{{.NumTeams}}</td> | |||
<td>{{.NumMembers}}</td> | |||
<td>{{.NumRepos}}</td> |
@@ -30,7 +30,12 @@ | |||
{{range .Repos}} | |||
<tr> | |||
<td>{{.ID}}</td> | |||
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a></td> | |||
<td> | |||
<a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a> | |||
{{if .Owner.Visibility.IsPrivate}} | |||
<span class="text gold"><i class="octicon octicon-lock"></i></span> | |||
{{end}} | |||
</td> | |||
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a></td> | |||
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td> | |||
<td>{{.NumWatches}}</td> |
@@ -9,7 +9,12 @@ | |||
<div class="item"> | |||
<img class="ui avatar image" src="{{.RelAvatarLink}}"> | |||
<div class="content"> | |||
<span class="header"><a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}</span> | |||
<span class="header"> | |||
<a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}} | |||
{{if .Visibility.IsPrivate}} | |||
<span class="text gold"><i class="octicon octicon-lock"></i></span> | |||
{{end}} | |||
</span> | |||
<div class="description"> | |||
{{if .Location}} | |||
<i class="octicon octicon-location"></i> {{.Location}} |
@@ -12,8 +12,11 @@ | |||
<span><i class="octicon octicon-repo-forked"></i></span> | |||
{{else if .IsMirror}} | |||
<span><i class="octicon octicon-repo-clone"></i></span> | |||
{{else if .Owner}} | |||
{{if .Owner.Visibility.IsPrivate}} | |||
<span class="text gold"><i class="octicon octicon-lock"></i></span> | |||
{{end}} | |||
{{end}} | |||
<div class="ui right metas"> | |||
<span class="text grey"><i class="octicon octicon-star"></i> {{.NumStars}}</span> | |||
<span class="text grey"><i class="octicon octicon-git-branch"></i> {{.NumForks}}</span> |
@@ -15,6 +15,28 @@ | |||
<span class="help">{{.i18n.Tr "org.org_name_helper"}}</span> | |||
</div> | |||
<div class="inline required field {{if .Err_OrgVisibility}}error{{end}}"> | |||
<label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/> | |||
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/> | |||
<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/> | |||
<label>{{.i18n.Tr "org.settings.visibility.private"}}</label> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="inline field"> | |||
<label></label> | |||
<button class="ui green button"> |
@@ -33,6 +33,29 @@ | |||
<input id="location" name="location" value="{{.Org.Location}}"> | |||
</div> | |||
<div class="ui divider"></div> | |||
<div class="field" id="visibility_box"> | |||
<label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if eq .CurrentVisibility 0}}checked{{end}}/> | |||
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if eq .CurrentVisibility 1}}checked{{end}}/> | |||
<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if eq .CurrentVisibility 2}}checked{{end}}/> | |||
<label>{{.i18n.Tr "org.settings.visibility.private"}}</label> | |||
</div> | |||
</div> | |||
</div> | |||
{{if .SignedUser.IsAdmin}} | |||
<div class="ui divider"></div> | |||
@@ -61,10 +61,12 @@ | |||
</a> | |||
</li> | |||
*/}} | |||
{{if .Orgs}} | |||
{{if and .Orgs .HasOrgsVisible}} | |||
<li> | |||
{{range .Orgs}} | |||
<a href="{{.HomeLink}}"><img class="ui mini image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||
{{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} | |||
<a href="{{.HomeLink}}"><img class="ui mini image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||
{{end}} | |||
{{end}} | |||
</li> | |||
{{end}} |