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
|
@ -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})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue