|
|
@ -22,6 +22,7 @@ import ( |
|
|
|
"code.gitea.io/gitea/modules/git" |
|
|
|
"code.gitea.io/gitea/modules/git" |
|
|
|
"code.gitea.io/gitea/modules/log" |
|
|
|
"code.gitea.io/gitea/modules/log" |
|
|
|
"code.gitea.io/gitea/modules/setting" |
|
|
|
"code.gitea.io/gitea/modules/setting" |
|
|
|
|
|
|
|
"code.gitea.io/gitea/modules/structs" |
|
|
|
"code.gitea.io/gitea/modules/timeutil" |
|
|
|
"code.gitea.io/gitea/modules/timeutil" |
|
|
|
"code.gitea.io/gitea/modules/util" |
|
|
|
"code.gitea.io/gitea/modules/util" |
|
|
|
|
|
|
|
|
|
|
@ -315,8 +316,10 @@ func (a *Action) GetIssueContent() string { |
|
|
|
|
|
|
|
|
|
|
|
// GetFeedsOptions options for retrieving feeds
|
|
|
|
// GetFeedsOptions options for retrieving feeds
|
|
|
|
type GetFeedsOptions struct { |
|
|
|
type GetFeedsOptions struct { |
|
|
|
|
|
|
|
db.ListOptions |
|
|
|
RequestedUser *user_model.User // the user we want activity for
|
|
|
|
RequestedUser *user_model.User // the user we want activity for
|
|
|
|
RequestedTeam *Team // the team we want activity for
|
|
|
|
RequestedTeam *Team // the team we want activity for
|
|
|
|
|
|
|
|
RequestedRepo *repo_model.Repository // the repo we want activity for
|
|
|
|
Actor *user_model.User // the user viewing the activity
|
|
|
|
Actor *user_model.User // the user viewing the activity
|
|
|
|
IncludePrivate bool // include private actions
|
|
|
|
IncludePrivate bool // include private actions
|
|
|
|
OnlyPerformedBy bool // only actions performed by requested user
|
|
|
|
OnlyPerformedBy bool // only actions performed by requested user
|
|
|
@ -326,8 +329,8 @@ type GetFeedsOptions struct { |
|
|
|
|
|
|
|
|
|
|
|
// GetFeeds returns actions according to the provided options
|
|
|
|
// GetFeeds returns actions according to the provided options
|
|
|
|
func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { |
|
|
|
func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { |
|
|
|
if !activityReadable(opts.RequestedUser, opts.Actor) { |
|
|
|
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil { |
|
|
|
return make([]*Action, 0), nil |
|
|
|
return nil, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cond, err := activityQueryCondition(opts) |
|
|
|
cond, err := activityQueryCondition(opts) |
|
|
@ -335,9 +338,14 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
actions := make([]*Action, 0, setting.UI.FeedPagingNum) |
|
|
|
sess := db.GetEngine(db.DefaultContext).Where(cond) |
|
|
|
|
|
|
|
|
|
|
|
if err := db.GetEngine(db.DefaultContext).Limit(setting.UI.FeedPagingNum).Desc("created_unix").Where(cond).Find(&actions); err != nil { |
|
|
|
opts.SetDefaultValues() |
|
|
|
|
|
|
|
sess = db.SetSessionPagination(sess, &opts) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
actions := make([]*Action, 0, opts.PageSize) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err := sess.Desc("created_unix").Find(&actions); err != nil { |
|
|
|
return nil, fmt.Errorf("Find: %v", err) |
|
|
|
return nil, fmt.Errorf("Find: %v", err) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -349,41 +357,44 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func activityReadable(user, doer *user_model.User) bool { |
|
|
|
func activityReadable(user, doer *user_model.User) bool { |
|
|
|
var doerID int64 |
|
|
|
return !user.KeepActivityPrivate || |
|
|
|
if doer != nil { |
|
|
|
doer != nil && (doer.IsAdmin || user.ID == doer.ID) |
|
|
|
doerID = doer.ID |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if doer == nil || !doer.IsAdmin { |
|
|
|
|
|
|
|
if user.KeepActivityPrivate && doerID != user.ID { |
|
|
|
|
|
|
|
return false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { |
|
|
|
func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { |
|
|
|
cond := builder.NewCond() |
|
|
|
cond := builder.NewCond() |
|
|
|
|
|
|
|
|
|
|
|
var repoIDs []int64 |
|
|
|
if opts.RequestedTeam != nil && opts.RequestedUser == nil { |
|
|
|
var actorID int64 |
|
|
|
org, err := user_model.GetUserByID(opts.RequestedTeam.OrgID) |
|
|
|
if opts.Actor != nil { |
|
|
|
if err != nil { |
|
|
|
actorID = opts.Actor.ID |
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
opts.RequestedUser = org |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check activity visibility for actor ( similar to activityReadable() )
|
|
|
|
|
|
|
|
if opts.Actor == nil { |
|
|
|
|
|
|
|
cond = cond.And(builder.In("act_user_id", |
|
|
|
|
|
|
|
builder.Select("`user`.id").Where( |
|
|
|
|
|
|
|
builder.Eq{"keep_activity_private": false, "visibility": structs.VisibleTypePublic}, |
|
|
|
|
|
|
|
).From("`user`"), |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
} else if !opts.Actor.IsAdmin { |
|
|
|
|
|
|
|
cond = cond.And(builder.In("act_user_id", |
|
|
|
|
|
|
|
builder.Select("`user`.id").Where( |
|
|
|
|
|
|
|
builder.Eq{"keep_activity_private": false}. |
|
|
|
|
|
|
|
And(builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))). |
|
|
|
|
|
|
|
Or(builder.Eq{"id": opts.Actor.ID}).From("`user`"), |
|
|
|
|
|
|
|
)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// check readable repositories by doer/actor
|
|
|
|
// check readable repositories by doer/actor
|
|
|
|
if opts.Actor == nil || !opts.Actor.IsAdmin { |
|
|
|
if opts.Actor == nil || !opts.Actor.IsAdmin { |
|
|
|
if opts.RequestedUser.IsOrganization() { |
|
|
|
|
|
|
|
env, err := OrgFromUser(opts.RequestedUser).AccessibleReposEnv(actorID) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, fmt.Errorf("AccessibleReposEnv: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if repoIDs, err = env.RepoIDs(1, opts.RequestedUser.NumRepos); err != nil { |
|
|
|
|
|
|
|
return nil, fmt.Errorf("GetUserRepositories: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cond = cond.And(builder.In("repo_id", repoIDs)) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor))) |
|
|
|
cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if opts.RequestedRepo != nil { |
|
|
|
|
|
|
|
cond = cond.And(builder.Eq{"repo_id": opts.RequestedRepo.ID}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if opts.RequestedTeam != nil { |
|
|
|
if opts.RequestedTeam != nil { |
|
|
@ -395,11 +406,14 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { |
|
|
|
cond = cond.And(builder.In("repo_id", teamRepoIDs)) |
|
|
|
cond = cond.And(builder.In("repo_id", teamRepoIDs)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if opts.RequestedUser != nil { |
|
|
|
cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID}) |
|
|
|
cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID}) |
|
|
|
|
|
|
|
|
|
|
|
if opts.OnlyPerformedBy { |
|
|
|
if opts.OnlyPerformedBy { |
|
|
|
cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID}) |
|
|
|
cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !opts.IncludePrivate { |
|
|
|
if !opts.IncludePrivate { |
|
|
|
cond = cond.And(builder.Eq{"is_private": false}) |
|
|
|
cond = cond.And(builder.Eq{"is_private": false}) |
|
|
|
} |
|
|
|
} |
|
|
|