Allow to set organization visibility (public, internal, private) (#1763)
This commit is contained in:
		
							parent
							
								
									ae3a913122
								
							
						
					
					
						commit
						64ce159a6e
					
				
					 27 changed files with 388 additions and 28 deletions
				
			
		| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								modules/structs/org_type.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								modules/structs/org_type.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue