1
0
Fork 0
forked from forgejo/forgejo

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:
Sergey Dryabzhinsky 2021-06-26 22:53:14 +03:00 committed by GitHub
parent 19ac575d57
commit 22a0636544
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 440 additions and 68 deletions

View file

@ -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 {