Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only show users that the doer has access to #20169

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 74 additions & 17 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,37 +316,94 @@ func (u *User) GenerateEmailActivateCode(email string) string {
}

// GetUserFollowers returns range of user's followers.
func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) {
sess := db.GetEngine(db.DefaultContext).
Where("follow.follow_id=?", u.ID).
func GetUserFollowers(ctx context.Context, opts GetUserFollowOptions) ([]*User, int64, error) {
sess := db.GetEngine(ctx).Where(opts.toCond(true)).
Join("LEFT", "follow", "`user`.id=follow.user_id")

if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions)
if opts.Page != 0 {
sess = db.SetSessionPagination(sess, &opts.ListOptions)

users := make([]*User, 0, listOptions.PageSize)
return users, sess.Find(&users)
users := make([]*User, 0, opts.PageSize)
count, err := sess.FindAndCount(&users)
return users, count, err
}

users := make([]*User, 0, 8)
return users, sess.Find(&users)
count, err := sess.FindAndCount(&users)
return users, count, err
}

// GetFeedsOptions options for getting the user's followers or followings.
type GetUserFollowOptions struct {
db.ListOptions
Actor *User // the user viewing the followings
RequestedUser *User // the user we want followings for
}

func (opts GetUserFollowOptions) toCond(checkFollowers bool) builder.Cond {
cond := builder.NewCond()

if checkFollowers {
cond = cond.And(builder.Eq{"`follow`.follow_id": opts.RequestedUser.ID})
} else {
cond = cond.And(builder.Eq{"`follow`.user_id": opts.RequestedUser.ID})
}

// If the actor is not signed in. Only show users that have their visibility
// set to public.
if opts.Actor == nil {
return cond.And(builder.Eq{"`user`.visibility": structs.VisibleTypePublic})
}

// Fast path for admins.
if opts.Actor.IsAdmin {
return cond
}

// If the actor is signed in, then we allow all limited & public accounts to be seen.
// However the actor can also see private accounts if they have are in the same organisation
// as that user.
cond = cond.And(
builder.Or(
// Include all limited & public accounts.
builder.Lte{"`user`.visibility": structs.VisibleTypeLimited},
// Check which private users can be included.
// Get the actor's orginisations and check if the private
// users are in those orgs.
builder.And(
// Specify all private users.
builder.Eq{"`user`.visibility": structs.VisibleTypePrivate},
// Is the user's id in the organisation that the actor is in?
builder.In("`user`.id",
builder.Select("uid").From("org_user").Where(
builder.In("org_id",
// Get the actor's orginaisations.
builder.Select("org_id").From("org_user").Where(builder.Eq{"uid": opts.Actor.ID})),
)),
),
),
)

return cond
}

// GetUserFollowing returns range of user's following.
func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) {
sess := db.GetEngine(db.DefaultContext).
Where("follow.user_id=?", u.ID).
Join("LEFT", "follow", "`user`.id=follow.follow_id")
func GetUserFollowing(ctx context.Context, opts GetUserFollowOptions) ([]*User, int64, error) {
sess := db.GetEngine(ctx).
Join("LEFT", "follow", "`user`.id=follow.follow_id").
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these be INNER JOINs instead of LEFT JOINs? In this case it does not change the result because of the WHERE clause.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just copying the previous code. I really don't want to make any more changes that doesn't cover the scope of the PR. It just leads to regressions and problems and arguments that I don't feel like fighting. But yeah it seems you're right we should only target followers that correspond to a existent user in the database, do you want to make a separate pull request for it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will create a PR.

Where(opts.toCond(false))

if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions)
if opts.Page != 0 {
sess = db.SetSessionPagination(sess, &opts.ListOptions)

users := make([]*User, 0, listOptions.PageSize)
return users, sess.Find(&users)
users := make([]*User, 0, opts.PageSize)
count, err := sess.FindAndCount(&users)
return users, count, err
}

users := make([]*User, 0, 8)
return users, sess.Find(&users)
count, err := sess.FindAndCount(&users)
return users, count, err
}

// NewGitSig generates and returns the signature of given user.
Expand Down
16 changes: 12 additions & 4 deletions routers/api/v1/user/follower.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) {
}

func listUserFollowers(ctx *context.APIContext, u *user_model.User) {
users, err := user_model.GetUserFollowers(u, utils.GetListOptions(ctx))
users, total, err := user_model.GetUserFollowers(ctx, user_model.GetUserFollowOptions{
RequestedUser: u,
Actor: ctx.Doer,
ListOptions: utils.GetListOptions(ctx),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
return
}

ctx.SetTotalCountHeader(int64(u.NumFollowers))
ctx.SetTotalCountHeader(total)
responseAPIUsers(ctx, users)
}

Expand Down Expand Up @@ -86,13 +90,17 @@ func ListFollowers(ctx *context.APIContext) {
}

func listUserFollowing(ctx *context.APIContext, u *user_model.User) {
users, err := user_model.GetUserFollowing(u, utils.GetListOptions(ctx))
users, total, err := user_model.GetUserFollowing(ctx, user_model.GetUserFollowOptions{
Actor: ctx.Doer,
RequestedUser: u,
ListOptions: utils.GetListOptions(ctx),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err)
return
}

ctx.SetTotalCountHeader(int64(u.NumFollowing))
ctx.SetTotalCountHeader(total)
responseAPIUsers(ctx, users)
}

Expand Down
18 changes: 10 additions & 8 deletions routers/web/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,29 +157,31 @@ func Profile(ctx *context.Context) {

switch tab {
case "followers":
items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
items, amountFollowers, err := user_model.GetUserFollowers(ctx, user_model.GetUserFollowOptions{
RequestedUser: ctx.ContextUser,
Actor: ctx.Doer,
ListOptions: db.ListOptions{PageSize: setting.UI.User.RepoPagingNum, Page: page},
})
if err != nil {
ctx.ServerError("GetUserFollowers", err)
return
}
ctx.Data["Cards"] = items

total = ctx.ContextUser.NumFollowers
total = int(amountFollowers)
case "following":
items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{
PageSize: setting.UI.User.RepoPagingNum,
Page: page,
items, amountFollowings, err := user_model.GetUserFollowing(ctx, user_model.GetUserFollowOptions{
Actor: ctx.Doer,
RequestedUser: ctx.ContextUser,
ListOptions: db.ListOptions{PageSize: setting.UI.User.RepoPagingNum, Page: page},
})
if err != nil {
ctx.ServerError("GetUserFollowing", err)
return
}
ctx.Data["Cards"] = items

total = ctx.ContextUser.NumFollowing
total = int(amountFollowings)
case "activity":
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctx.ContextUser,
Expand Down