mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Only show Followers that current user can access (#20220)
Users who are following or being followed by a user should only be displayed if the viewing user can see them. Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		| @@ -316,37 +316,45 @@ func (u *User) GenerateEmailActivateCode(email string) string { | |||||||
| } | } | ||||||
|  |  | ||||||
| // GetUserFollowers returns range of user's followers. | // GetUserFollowers returns range of user's followers. | ||||||
| func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) { | func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { | ||||||
| 	sess := db.GetEngine(db.DefaultContext). | 	sess := db.GetEngine(ctx). | ||||||
|  | 		Select("`user`.*"). | ||||||
|  | 		Join("LEFT", "follow", "`user`.id=follow.user_id"). | ||||||
| 		Where("follow.follow_id=?", u.ID). | 		Where("follow.follow_id=?", u.ID). | ||||||
| 		Join("LEFT", "follow", "`user`.id=follow.user_id") | 		And(isUserVisibleToViewerCond(viewer)) | ||||||
|  |  | ||||||
| 	if listOptions.Page != 0 { | 	if listOptions.Page != 0 { | ||||||
| 		sess = db.SetSessionPagination(sess, &listOptions) | 		sess = db.SetSessionPagination(sess, &listOptions) | ||||||
|  |  | ||||||
| 		users := make([]*User, 0, listOptions.PageSize) | 		users := make([]*User, 0, listOptions.PageSize) | ||||||
| 		return users, sess.Find(&users) | 		count, err := sess.FindAndCount(&users) | ||||||
|  | 		return users, count, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	users := make([]*User, 0, 8) | 	users := make([]*User, 0, 8) | ||||||
| 	return users, sess.Find(&users) | 	count, err := sess.FindAndCount(&users) | ||||||
|  | 	return users, count, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetUserFollowing returns range of user's following. | // GetUserFollowing returns range of user's following. | ||||||
| func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) { | func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { | ||||||
| 	sess := db.GetEngine(db.DefaultContext). | 	sess := db.GetEngine(db.DefaultContext). | ||||||
|  | 		Select("`user`.*"). | ||||||
|  | 		Join("LEFT", "follow", "`user`.id=follow.follow_id"). | ||||||
| 		Where("follow.user_id=?", u.ID). | 		Where("follow.user_id=?", u.ID). | ||||||
| 		Join("LEFT", "follow", "`user`.id=follow.follow_id") | 		And(isUserVisibleToViewerCond(viewer)) | ||||||
|  |  | ||||||
| 	if listOptions.Page != 0 { | 	if listOptions.Page != 0 { | ||||||
| 		sess = db.SetSessionPagination(sess, &listOptions) | 		sess = db.SetSessionPagination(sess, &listOptions) | ||||||
|  |  | ||||||
| 		users := make([]*User, 0, listOptions.PageSize) | 		users := make([]*User, 0, listOptions.PageSize) | ||||||
| 		return users, sess.Find(&users) | 		count, err := sess.FindAndCount(&users) | ||||||
|  | 		return users, count, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	users := make([]*User, 0, 8) | 	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. | // NewGitSig generates and returns the signature of given user. | ||||||
| @@ -1222,6 +1230,39 @@ func GetAdminUser() (*User, error) { | |||||||
| 	return &admin, nil | 	return &admin, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func isUserVisibleToViewerCond(viewer *User) builder.Cond { | ||||||
|  | 	if viewer != nil && viewer.IsAdmin { | ||||||
|  | 		return builder.NewCond() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if viewer == nil || viewer.IsRestricted { | ||||||
|  | 		return builder.Eq{ | ||||||
|  | 			"`user`.visibility": structs.VisibleTypePublic, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return builder.Neq{ | ||||||
|  | 		"`user`.visibility": structs.VisibleTypePrivate, | ||||||
|  | 	}.Or( | ||||||
|  | 		builder.In("`user`.id", | ||||||
|  | 			builder. | ||||||
|  | 				Select("`follow`.user_id"). | ||||||
|  | 				From("follow"). | ||||||
|  | 				Where(builder.Eq{"`follow`.follow_id": viewer.ID})), | ||||||
|  | 		builder.In("`user`.id", | ||||||
|  | 			builder. | ||||||
|  | 				Select("`team_user`.uid"). | ||||||
|  | 				From("team_user"). | ||||||
|  | 				Join("INNER", "`team_user` AS t2", "`team_user`.id = `t2`.id"). | ||||||
|  | 				Where(builder.Eq{"`t2`.uid": viewer.ID})), | ||||||
|  | 		builder.In("`user`.id", | ||||||
|  | 			builder. | ||||||
|  | 				Select("`team_user`.uid"). | ||||||
|  | 				From("team_user"). | ||||||
|  | 				Join("INNER", "`team_user` AS t2", "`team_user`.org_id = `t2`.org_id"). | ||||||
|  | 				Where(builder.Eq{"`t2`.uid": viewer.ID}))) | ||||||
|  | } | ||||||
|  |  | ||||||
| // IsUserVisibleToViewer check if viewer is able to see user profile | // IsUserVisibleToViewer check if viewer is able to see user profile | ||||||
| func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { | func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { | ||||||
| 	if viewer != nil && viewer.IsAdmin { | 	if viewer != nil && viewer.IsAdmin { | ||||||
|   | |||||||
| @@ -24,13 +24,13 @@ func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func listUserFollowers(ctx *context.APIContext, u *user_model.User) { | func listUserFollowers(ctx *context.APIContext, u *user_model.User) { | ||||||
| 	users, err := user_model.GetUserFollowers(u, utils.GetListOptions(ctx)) | 	users, count, err := user_model.GetUserFollowers(ctx, u, ctx.Doer, utils.GetListOptions(ctx)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err) | 		ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx.SetTotalCountHeader(int64(u.NumFollowers)) | 	ctx.SetTotalCountHeader(count) | ||||||
| 	responseAPIUsers(ctx, users) | 	responseAPIUsers(ctx, users) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -86,13 +86,13 @@ func ListFollowers(ctx *context.APIContext) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func listUserFollowing(ctx *context.APIContext, u *user_model.User) { | func listUserFollowing(ctx *context.APIContext, u *user_model.User) { | ||||||
| 	users, err := user_model.GetUserFollowing(u, utils.GetListOptions(ctx)) | 	users, count, err := user_model.GetUserFollowing(ctx, u, ctx.Doer, utils.GetListOptions(ctx)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err) | 		ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx.SetTotalCountHeader(int64(u.NumFollowing)) | 	ctx.SetTotalCountHeader(count) | ||||||
| 	responseAPIUsers(ctx, users) | 	responseAPIUsers(ctx, users) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -157,7 +157,7 @@ func Profile(ctx *context.Context) { | |||||||
|  |  | ||||||
| 	switch tab { | 	switch tab { | ||||||
| 	case "followers": | 	case "followers": | ||||||
| 		items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{ | 		items, count, err := user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{ | ||||||
| 			PageSize: setting.UI.User.RepoPagingNum, | 			PageSize: setting.UI.User.RepoPagingNum, | ||||||
| 			Page:     page, | 			Page:     page, | ||||||
| 		}) | 		}) | ||||||
| @@ -167,9 +167,9 @@ func Profile(ctx *context.Context) { | |||||||
| 		} | 		} | ||||||
| 		ctx.Data["Cards"] = items | 		ctx.Data["Cards"] = items | ||||||
|  |  | ||||||
| 		total = ctx.ContextUser.NumFollowers | 		total = int(count) | ||||||
| 	case "following": | 	case "following": | ||||||
| 		items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{ | 		items, count, err := user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{ | ||||||
| 			PageSize: setting.UI.User.RepoPagingNum, | 			PageSize: setting.UI.User.RepoPagingNum, | ||||||
| 			Page:     page, | 			Page:     page, | ||||||
| 		}) | 		}) | ||||||
| @@ -179,7 +179,7 @@ func Profile(ctx *context.Context) { | |||||||
| 		} | 		} | ||||||
| 		ctx.Data["Cards"] = items | 		ctx.Data["Cards"] = items | ||||||
|  |  | ||||||
| 		total = ctx.ContextUser.NumFollowing | 		total = int(count) | ||||||
| 	case "activity": | 	case "activity": | ||||||
| 		ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{ | 		ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{ | ||||||
| 			RequestedUser:   ctx.ContextUser, | 			RequestedUser:   ctx.ContextUser, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user