Add Visible modes function from Organisation to Users too (#16069)
You can limit or hide organisations. This pull make it also posible for users - new strings to translte - add checkbox to user profile form - add checkbox to admin user.edit form - filter explore page user search - filter api admin and public user searches - allow admins view "hidden" users - add app option DEFAULT_USER_VISIBILITY - rewrite many files to use Visibility field - check for teams intersection - fix context output - right fake 404 if not visible Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
parent
19ac575d57
commit
22a0636544
32 changed files with 440 additions and 68 deletions
|
@ -508,7 +508,6 @@
|
|||
num_repos: 0
|
||||
is_active: true
|
||||
|
||||
|
||||
-
|
||||
id: 30
|
||||
lower_name: user30
|
||||
|
@ -525,3 +524,20 @@
|
|||
avatar_email: user30@example.com
|
||||
num_repos: 2
|
||||
is_active: true
|
||||
|
||||
-
|
||||
id: 31
|
||||
lower_name: user31
|
||||
name: user31
|
||||
full_name: "user31"
|
||||
email: user31@example.com
|
||||
passwd_hash_algo: argon2
|
||||
passwd: a3d5fcd92bae586c2e3dbe72daea7a0d27833a8d0227aa1704f4bbd775c1f3b03535b76dd93b0d4d8d22a519dca47df1547b # password
|
||||
type: 0 # individual
|
||||
salt: ZogKvWdyEx
|
||||
is_admin: false
|
||||
visibility: 2
|
||||
avatar: avatar31
|
||||
avatar_email: user31@example.com
|
||||
num_repos: 0
|
||||
is_active: true
|
||||
|
|
|
@ -455,22 +455,22 @@ 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) bool {
|
||||
return hasOrgVisible(x, org, user)
|
||||
// HasOrgOrUserVisible tells if the given user can see the given org or user
|
||||
func HasOrgOrUserVisible(org, user *User) bool {
|
||||
return hasOrgOrUserVisible(x, org, user)
|
||||
}
|
||||
|
||||
func hasOrgVisible(e Engine, org, user *User) bool {
|
||||
func hasOrgOrUserVisible(e Engine, orgOrUser, user *User) bool {
|
||||
// Not SignedUser
|
||||
if user == nil {
|
||||
return org.Visibility == structs.VisibleTypePublic
|
||||
return orgOrUser.Visibility == structs.VisibleTypePublic
|
||||
}
|
||||
|
||||
if user.IsAdmin {
|
||||
if user.IsAdmin || orgOrUser.ID == user.ID {
|
||||
return true
|
||||
}
|
||||
|
||||
if (org.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !org.hasMemberWithUserID(e, user.ID) {
|
||||
if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !orgOrUser.hasMemberWithUserID(e, user.ID) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -483,7 +483,7 @@ func HasOrgsVisible(orgs []*User, user *User) bool {
|
|||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
if HasOrgVisible(org, user) {
|
||||
if HasOrgOrUserVisible(org, user) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -586,9 +586,9 @@ func TestHasOrgVisibleTypePublic(t *testing.T) {
|
|||
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)
|
||||
test1 := HasOrgOrUserVisible(org, owner)
|
||||
test2 := HasOrgOrUserVisible(org, user3)
|
||||
test3 := HasOrgOrUserVisible(org, nil)
|
||||
assert.True(t, test1) // owner of org
|
||||
assert.True(t, test2) // user not a part of org
|
||||
assert.True(t, test3) // logged out user
|
||||
|
@ -609,9 +609,9 @@ func TestHasOrgVisibleTypeLimited(t *testing.T) {
|
|||
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)
|
||||
test1 := HasOrgOrUserVisible(org, owner)
|
||||
test2 := HasOrgOrUserVisible(org, user3)
|
||||
test3 := HasOrgOrUserVisible(org, nil)
|
||||
assert.True(t, test1) // owner of org
|
||||
assert.True(t, test2) // user not a part of org
|
||||
assert.False(t, test3) // logged out user
|
||||
|
@ -632,9 +632,9 @@ func TestHasOrgVisibleTypePrivate(t *testing.T) {
|
|||
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)
|
||||
test1 := HasOrgOrUserVisible(org, owner)
|
||||
test2 := HasOrgOrUserVisible(org, user3)
|
||||
test3 := HasOrgOrUserVisible(org, nil)
|
||||
assert.True(t, test1) // owner of org
|
||||
assert.False(t, test2) // user not a part of org
|
||||
assert.False(t, test3) // logged out user
|
||||
|
|
|
@ -585,8 +585,7 @@ func (repo *Repository) getReviewers(e Engine, doerID, posterID int64) ([]*User,
|
|||
|
||||
var users []*User
|
||||
|
||||
if repo.IsPrivate ||
|
||||
(repo.Owner.IsOrganization() && repo.Owner.Visibility == api.VisibleTypePrivate) {
|
||||
if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate {
|
||||
// This a private repository:
|
||||
// Anyone who can read the repository is a requestable reviewer
|
||||
if err := e.
|
||||
|
|
|
@ -176,9 +176,9 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
|
|||
return
|
||||
}
|
||||
|
||||
// Prevent strangers from checking out public repo of private orginization
|
||||
// Allow user if they are collaborator of a repo within a private orginization but not a member of the orginization itself
|
||||
if repo.Owner.IsOrganization() && !hasOrgVisible(e, repo.Owner, user) && !isCollaborator {
|
||||
// Prevent strangers from checking out public repo of private orginization/users
|
||||
// Allow user if they are collaborator of a repo within a private user or a private organization but not a member of the organization itself
|
||||
if !hasOrgOrUserVisible(e, repo.Owner, user) && !isCollaborator {
|
||||
perm.AccessMode = AccessModeNone
|
||||
return
|
||||
}
|
||||
|
|
105
models/user.go
105
models/user.go
|
@ -432,6 +432,62 @@ func (u *User) IsPasswordSet() bool {
|
|||
return len(u.Passwd) != 0
|
||||
}
|
||||
|
||||
// IsVisibleToUser check if viewer is able to see user profile
|
||||
func (u *User) IsVisibleToUser(viewer *User) bool {
|
||||
return u.isVisibleToUser(x, viewer)
|
||||
}
|
||||
|
||||
func (u *User) isVisibleToUser(e Engine, viewer *User) bool {
|
||||
if viewer != nil && viewer.IsAdmin {
|
||||
return true
|
||||
}
|
||||
|
||||
switch u.Visibility {
|
||||
case structs.VisibleTypePublic:
|
||||
return true
|
||||
case structs.VisibleTypeLimited:
|
||||
if viewer == nil || viewer.IsRestricted {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
case structs.VisibleTypePrivate:
|
||||
if viewer == nil || viewer.IsRestricted {
|
||||
return false
|
||||
}
|
||||
|
||||
// If they follow - they see each over
|
||||
follower := IsFollowing(u.ID, viewer.ID)
|
||||
if follower {
|
||||
return true
|
||||
}
|
||||
|
||||
// Now we need to check if they in some organization together
|
||||
count, err := x.Table("team_user").
|
||||
Where(
|
||||
builder.And(
|
||||
builder.Eq{"uid": viewer.ID},
|
||||
builder.Or(
|
||||
builder.Eq{"org_id": u.ID},
|
||||
builder.In("org_id",
|
||||
builder.Select("org_id").
|
||||
From("team_user", "t2").
|
||||
Where(builder.Eq{"uid": u.ID}))))).
|
||||
Count(new(TeamUser))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if count < 0 {
|
||||
// No common organization
|
||||
return false
|
||||
}
|
||||
|
||||
// they are in an organization together
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsOrganization returns true if user is actually a organization.
|
||||
func (u *User) IsOrganization() bool {
|
||||
return u.Type == UserTypeOrganization
|
||||
|
@ -796,8 +852,13 @@ func IsUsableUsername(name string) error {
|
|||
return isUsableName(reservedUsernames, reservedUserPatterns, name)
|
||||
}
|
||||
|
||||
// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
|
||||
type CreateUserOverwriteOptions struct {
|
||||
Visibility structs.VisibleType
|
||||
}
|
||||
|
||||
// CreateUser creates record of a new user.
|
||||
func CreateUser(u *User) (err error) {
|
||||
func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
|
||||
if err = IsUsableUsername(u.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -831,8 +892,6 @@ func CreateUser(u *User) (err error) {
|
|||
return ErrEmailAlreadyUsed{u.Email}
|
||||
}
|
||||
|
||||
u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
|
||||
|
||||
u.LowerName = strings.ToLower(u.Name)
|
||||
u.AvatarEmail = u.Email
|
||||
if u.Rands, err = GetUserSalt(); err != nil {
|
||||
|
@ -841,10 +900,18 @@ func CreateUser(u *User) (err error) {
|
|||
if err = u.SetPassword(u.Passwd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set system defaults
|
||||
u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
|
||||
u.Visibility = setting.Service.DefaultUserVisibilityMode
|
||||
u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation
|
||||
u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
|
||||
u.MaxRepoCreation = -1
|
||||
u.Theme = setting.UI.DefaultTheme
|
||||
// overwrite defaults if set
|
||||
if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
|
||||
u.Visibility = overwriteDefault[0].Visibility
|
||||
}
|
||||
|
||||
if _, err = sess.Insert(u); err != nil {
|
||||
return err
|
||||
|
@ -1527,10 +1594,9 @@ func (opts *SearchUserOptions) toConds() builder.Cond {
|
|||
cond = cond.And(keywordCond)
|
||||
}
|
||||
|
||||
// If visibility filtered
|
||||
if len(opts.Visible) > 0 {
|
||||
cond = cond.And(builder.In("visibility", opts.Visible))
|
||||
} else {
|
||||
cond = cond.And(builder.In("visibility", structs.VisibleTypePublic))
|
||||
}
|
||||
|
||||
if opts.Actor != nil {
|
||||
|
@ -1543,16 +1609,27 @@ func (opts *SearchUserOptions) toConds() builder.Cond {
|
|||
exprCond = builder.Expr("org_user.org_id = \"user\".id")
|
||||
}
|
||||
|
||||
var accessCond builder.Cond
|
||||
if !opts.Actor.IsRestricted {
|
||||
accessCond = builder.Or(
|
||||
builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
|
||||
builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
|
||||
} else {
|
||||
// restricted users only see orgs they are a member of
|
||||
accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID})))
|
||||
// If Admin - they see all users!
|
||||
if !opts.Actor.IsAdmin {
|
||||
// Force visiblity for privacy
|
||||
var accessCond builder.Cond
|
||||
if !opts.Actor.IsRestricted {
|
||||
accessCond = builder.Or(
|
||||
builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
|
||||
builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
|
||||
} else {
|
||||
// restricted users only see orgs they are a member of
|
||||
accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID})))
|
||||
}
|
||||
// Don't forget about self
|
||||
accessCond = accessCond.Or(builder.Eq{"id": opts.Actor.ID})
|
||||
cond = cond.And(accessCond)
|
||||
}
|
||||
cond = cond.And(accessCond)
|
||||
|
||||
} else {
|
||||
// Force visiblity for privacy
|
||||
// Not logged in - only public users
|
||||
cond = cond.And(builder.In("visibility", structs.VisibleTypePublic))
|
||||
}
|
||||
|
||||
if opts.UID > 0 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue