This commit is contained in:
Tim-Niclas Oelschläger 2024-04-26 14:37:32 +03:00 committed by GitHub
commit 26301ef30a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 387 additions and 251 deletions

View File

@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
@ -139,21 +140,22 @@ func (at ActionType) InActions(actions ...string) bool {
// repository. It implemented interface base.Actioner so that can be
// used in template render.
type Action struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"INDEX"` // Receiver user id.
OpType ActionType
ActUserID int64 // Action user id.
ActUser *user_model.User `xorm:"-"`
RepoID int64
Repo *repo_model.Repository `xorm:"-"`
CommentID int64 `xorm:"INDEX"`
Comment *issues_model.Comment `xorm:"-"`
Issue *issues_model.Issue `xorm:"-"` // get the issue id from content
IsDeleted bool `xorm:"NOT NULL DEFAULT false"`
RefName string
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
Content string `xorm:"TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"INDEX"` // Receiver user id.
OpType ActionType
ActUserID int64 // Action user id.
ActUser *user_model.User `xorm:"-"`
RepoID int64
Repo *repo_model.Repository `xorm:"-"`
CommentID int64 `xorm:"INDEX"`
Comment *issues_model.Comment `xorm:"-"`
Issue *issues_model.Issue `xorm:"-"` // get the issue id from content
IsDeleted bool `xorm:"NOT NULL DEFAULT false"`
RefName string
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
IsPrivateView bool `xorm:"-"`
Content string `xorm:"TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
}
func init() {
@ -457,23 +459,57 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
opts.SetDefaultValues()
sess = db.SetSessionPagination(sess, &opts)
actions := make([]*Action, 0, opts.PageSize)
actions := make(ActionList, 0, opts.PageSize)
count, err := sess.Desc("`action`.created_unix").FindAndCount(&actions)
if err != nil {
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
}
if err := ActionList(actions).LoadAttributes(ctx); err != nil {
if err := actions.LoadAttributes(ctx); err != nil {
return nil, 0, fmt.Errorf("LoadAttributes: %w", err)
}
if opts.Actor != nil && opts.RequestedUser != nil {
isPrivateForActor := !opts.Actor.IsAdmin && opts.Actor.ID != opts.RequestedUser.ID
// cache user repo read permissions
canReadRepo := make(map[int64]optional.Option[bool], 0)
for _, action := range actions {
action.IsPrivateView = isPrivateForActor && action.IsPrivate
if action.IsPrivateView && action.Repo.Owner.IsOrganization() {
if !canReadRepo[action.Repo.ID].Has() {
perm, err := access_model.GetUserRepoPermission(ctx, action.Repo, opts.Actor)
if err != nil {
return nil, 0, fmt.Errorf("GetUserRepoPermission: %w", err)
}
canRead := perm.CanRead(unit.TypeCode)
action.IsPrivateView = !canRead
canReadRepo[action.Repo.ID] = optional.Option[bool]{canRead}
}
action.IsPrivateView = !canReadRepo[action.Repo.ID].Value()
}
}
} else {
for _, action := range actions {
action.IsPrivateView = action.IsPrivate
}
}
return actions, count, nil
}
// ActivityReadable return whether doer can read activities of user
func ActivityReadable(user, doer *user_model.User) bool {
return !user.KeepActivityPrivate ||
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
if doer != nil && (doer.IsAdmin || user.ID == doer.ID) {
return true
}
if user.ActivityVisibility.ShowNone() {
return false
}
return true
}
func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
@ -491,14 +527,17 @@ func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
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},
builder.Eq{"visibility": structs.VisibleTypePublic},
).Where(
builder.Neq{"activity_visibility": structs.ActivityVisibilityNone},
).From("`user`"),
))
} else if !opts.Actor.IsAdmin {
uidCond := builder.Select("`user`.id").From("`user`").Where(
builder.Eq{"keep_activity_private": false}.
And(builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))).
Or(builder.Eq{"id": opts.Actor.ID})
builder.Neq{"activity_visibility": structs.ActivityVisibilityNone},
).Where(
builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited),
).Or(builder.Eq{"id": opts.Actor.ID})
if opts.RequestedUser != nil {
if opts.RequestedUser.IsOrganization() {
@ -518,8 +557,9 @@ func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
cond = cond.And(builder.In("act_user_id", uidCond))
}
includePrivateRepos := opts.RequestedUser != nil && opts.RequestedUser.ActivityVisibility.ShowAll()
// check readable repositories by doer/actor
if opts.Actor == nil || !opts.Actor.IsAdmin {
if !includePrivateRepos && (opts.Actor == nil || !opts.Actor.IsAdmin) {
cond = cond.And(builder.In("repo_id", repo_model.AccessibleRepoIDsQuery(opts.Actor)))
}

View File

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
)
@ -165,21 +166,21 @@ func TestActivityReadable(t *testing.T) {
result: true,
}, {
desc: "anon should NOT see activity",
user: &user_model.User{ID: 1, KeepActivityPrivate: true},
user: &user_model.User{ID: 1, ActivityVisibility: structs.ActivityVisibilityNone},
result: false,
}, {
desc: "user should see own activity if private too",
user: &user_model.User{ID: 1, KeepActivityPrivate: true},
user: &user_model.User{ID: 1, ActivityVisibility: structs.ActivityVisibilityNone},
doer: &user_model.User{ID: 1},
result: true,
}, {
desc: "other user should NOT see activity",
user: &user_model.User{ID: 1, KeepActivityPrivate: true},
user: &user_model.User{ID: 1, ActivityVisibility: structs.ActivityVisibilityNone},
doer: &user_model.User{ID: 2},
result: false,
}, {
desc: "admin should see activity",
user: &user_model.User{ID: 1, KeepActivityPrivate: true},
user: &user_model.User{ID: 1, ActivityVisibility: structs.ActivityVisibilityNone},
doer: &user_model.User{ID: 2, IsAdmin: true},
result: true,
}}

View File

@ -35,7 +35,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 2
@ -72,7 +72,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 3
@ -109,7 +109,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 4
@ -146,7 +146,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 5
@ -183,7 +183,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 6
@ -220,7 +220,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 7
@ -257,7 +257,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 8
@ -294,7 +294,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 9
@ -331,7 +331,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 10
@ -368,7 +368,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 11
@ -405,7 +405,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 12
@ -442,7 +442,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 13
@ -479,7 +479,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 14
@ -516,7 +516,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 15
@ -553,7 +553,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 16
@ -590,7 +590,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 17
@ -627,7 +627,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 18
@ -664,7 +664,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 19
@ -701,7 +701,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 20
@ -738,7 +738,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 21
@ -775,7 +775,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 22
@ -812,7 +812,7 @@
visibility: 1
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 23
@ -849,7 +849,7 @@
visibility: 2
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 24
@ -886,7 +886,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 25
@ -923,7 +923,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 26
@ -960,7 +960,7 @@
visibility: 0
repo_admin_change_team_access: true
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 27
@ -997,7 +997,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 28
@ -1034,7 +1034,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 29
@ -1071,7 +1071,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 30
@ -1108,7 +1108,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 31
@ -1145,7 +1145,7 @@
visibility: 2
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 32
@ -1182,7 +1182,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 33
@ -1219,7 +1219,7 @@
visibility: 1
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 34
@ -1257,7 +1257,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 35
@ -1294,7 +1294,7 @@
visibility: 2
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 36
@ -1331,7 +1331,7 @@
visibility: 1
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 37
@ -1368,7 +1368,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 38
@ -1405,7 +1405,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 39
@ -1442,7 +1442,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 40
@ -1479,7 +1479,7 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0
-
id: 41
@ -1516,4 +1516,4 @@
visibility: 0
repo_admin_change_team_access: false
theme: ""
keep_activity_private: false
activity_visibility: 0

View File

@ -143,9 +143,9 @@ type User struct {
RepoAdminChangeTeamAccess bool `xorm:"NOT NULL DEFAULT false"`
// Preferences
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
Theme string `xorm:"NOT NULL DEFAULT ''"`
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
Theme string `xorm:"NOT NULL DEFAULT ''"`
ActivityVisibility structs.ActivityVisibility `xorm:"NOT NULL DEFAULT 0"`
}
func init() {

View File

@ -0,0 +1,50 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package structs
// ActivityVisibility defines the activities shown
type ActivityVisibility int
const (
// ActivityVisibilityPublic show public activities
ActivityVisibilityPublic ActivityVisibility = iota
// ActivityVisibilityAll shows all activities
ActivityVisibilityAll
// ActivityVisibilityNone show no activities
ActivityVisibilityNone
)
// ActivityVisibilities is a map of ActivityVisibility types
var ActivityVisibilities = map[string]ActivityVisibility{
"public": ActivityVisibilityPublic,
"all": ActivityVisibilityAll,
"none": ActivityVisibilityNone,
}
// ShowPublic returns true if ActivityVisibility is public
func (vt ActivityVisibility) ShowPublic() bool {
return vt == ActivityVisibilityPublic
}
// ShowAll returns true if ActivityVisibility is all
func (vt ActivityVisibility) ShowAll() bool {
return vt == ActivityVisibilityAll
}
// ShowNone returns true if ActivityVisibility is none
func (vt ActivityVisibility) ShowNone() bool {
return vt == ActivityVisibilityNone
}
// String provides the mode string of the visibility type (public, all, none)
func (vt ActivityVisibility) String() string {
for k, v := range ActivityVisibilities {
if vt == v {
return k
}
}
return ""
}

View File

@ -78,8 +78,8 @@ type UserSettings struct {
Theme string `json:"theme"`
DiffViewStyle string `json:"diff_view_style"`
// Privacy
HideEmail bool `json:"hide_email"`
HideActivity bool `json:"hide_activity"`
HideEmail bool `json:"hide_email"`
ActivityVisibility ActivityVisibility `json:"activity_visibility"`
}
// UserSettingsOptions represents options to change user settings
@ -93,8 +93,8 @@ type UserSettingsOptions struct {
Theme *string `json:"theme"`
DiffViewStyle *string `json:"diff_view_style"`
// Privacy
HideEmail *bool `json:"hide_email"`
HideActivity *bool `json:"hide_activity"`
HideEmail *bool `json:"hide_email"`
ActivityVisibility *ActivityVisibility `json:"activity_visibility"`
}
// RenameUserOption options when renaming a user

View File

@ -70,6 +70,8 @@ your_starred = Starred
your_settings = Settings
all = All
none = None
public = Public
sources = Sources
mirrors = Mirrors
collaborative = Collaborative
@ -736,8 +738,11 @@ comment_type_group_project = Project
comment_type_group_issue_ref = Issue reference
saved_successfully = Your settings were saved successfully.
privacy = Privacy
keep_activity_private = Hide Activity from profile page
keep_activity_private_popup = Makes the activity visible only for you and the admins
activity_visibility_popup = Specify which activities are visible
activity_visibility = Visible activities
activity_visibility.public_popup = Only activies from repositories which can be accessed by the viewer are visible
activity_visibility.all_popup = All activities are visibile, but activities from repositories which can't be accessed by the viewer are obfuscated and only shows how many activities were performed.
activity_visibility.none_popup = Don't show activities (expect to admins)
lookup_avatar_by_mail = Look Up Avatar by Email Address
federated_avatar_lookup = Federated Avatar Lookup
@ -3353,6 +3358,8 @@ review_dismissed_reason = Reason:
create_branch = created branch <a href="%[2]s">%[3]s</a> in <a href="%[1]s">%[4]s</a>
starred_repo = starred <a href="%[1]s">%[2]s</a>
watched_repo = started watching <a href="%[1]s">%[2]s</a>
performed_1 = performed %d private action
performed_n = performed %d private actions
[tool]
now = now

View File

@ -46,15 +46,15 @@ func UpdateUserSettings(ctx *context.APIContext) {
form := web.GetForm(ctx).(*api.UserSettingsOptions)
opts := &user_service.UpdateOptions{
FullName: optional.FromPtr(form.FullName),
Description: optional.FromPtr(form.Description),
Website: optional.FromPtr(form.Website),
Location: optional.FromPtr(form.Location),
Language: optional.FromPtr(form.Language),
Theme: optional.FromPtr(form.Theme),
DiffViewStyle: optional.FromPtr(form.DiffViewStyle),
KeepEmailPrivate: optional.FromPtr(form.HideEmail),
KeepActivityPrivate: optional.FromPtr(form.HideActivity),
FullName: optional.FromPtr(form.FullName),
Description: optional.FromPtr(form.Description),
Website: optional.FromPtr(form.Website),
Location: optional.FromPtr(form.Location),
Language: optional.FromPtr(form.Language),
Theme: optional.FromPtr(form.Theme),
DiffViewStyle: optional.FromPtr(form.DiffViewStyle),
KeepEmailPrivate: optional.FromPtr(form.HideEmail),
ActivityVisibility: optional.FromPtr(form.ActivityVisibility),
}
if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil {
ctx.InternalServerError(err)

View File

@ -75,14 +75,13 @@ func userProfile(ctx *context.Context) {
profileDbRepo, profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
defer profileClose()
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
prepareUserProfileTabData(ctx, showPrivate, profileDbRepo, profileGitRepo, profileReadmeBlob)
prepareUserProfileTabData(ctx, profileDbRepo, profileGitRepo, profileReadmeBlob)
// call PrepareContextForProfileBigAvatar later to avoid re-querying the NumFollowers & NumFollowing
shared_user.PrepareContextForProfileBigAvatar(ctx)
ctx.HTML(http.StatusOK, tplProfile)
}
func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadme *git.Blob) {
func prepareUserProfileTabData(ctx *context.Context, profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadme *git.Blob) {
// if there is a profile readme, default to "overview" page, otherwise, default to "repositories" page
// if there is not a profile readme, the overview tab should be treated as the repositories tab
tab := ctx.FormString("tab")
@ -190,7 +189,7 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
items, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
RequestedUser: ctx.ContextUser,
Actor: ctx.Doer,
IncludePrivate: showPrivate,
IncludePrivate: true,
OnlyPerformedBy: true,
IncludeDeleted: false,
Date: date,

View File

@ -88,13 +88,13 @@ func ProfilePost(ctx *context.Context) {
}
opts := &user_service.UpdateOptions{
FullName: optional.Some(form.FullName),
KeepEmailPrivate: optional.Some(form.KeepEmailPrivate),
Description: optional.Some(form.Description),
Website: optional.Some(form.Website),
Location: optional.Some(form.Location),
Visibility: optional.Some(form.Visibility),
KeepActivityPrivate: optional.Some(form.KeepActivityPrivate),
FullName: optional.Some(form.FullName),
KeepEmailPrivate: optional.Some(form.KeepEmailPrivate),
Description: optional.Some(form.Description),
Website: optional.Some(form.Website),
Location: optional.Some(form.Location),
Visibility: optional.Some(form.Visibility),
ActivityVisibility: optional.Some(form.ActivityVisibility),
}
if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil {
ctx.ServerError("UpdateUser", err)

View File

@ -87,15 +87,15 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap
// User2UserSettings return UserSettings based on a user
func User2UserSettings(user *user_model.User) api.UserSettings {
return api.UserSettings{
FullName: user.FullName,
Website: user.Website,
Location: user.Location,
Language: user.Language,
Description: user.Description,
Theme: user.Theme,
HideEmail: user.KeepEmailPrivate,
HideActivity: user.KeepActivityPrivate,
DiffViewStyle: user.DiffViewStyle,
FullName: user.FullName,
Website: user.Website,
Location: user.Location,
Language: user.Language,
Description: user.Description,
Theme: user.Theme,
HideEmail: user.KeepEmailPrivate,
ActivityVisibility: user.ActivityVisibility,
DiffViewStyle: user.DiffViewStyle,
}
}

View File

@ -212,14 +212,14 @@ func (f *IntrospectTokenForm) Validate(req *http.Request, errs binding.Errors) b
// UpdateProfileForm form for updating profile
type UpdateProfileForm struct {
Name string `binding:"Username;MaxSize(40)"`
FullName string `binding:"MaxSize(100)"`
KeepEmailPrivate bool
Website string `binding:"ValidSiteUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Description string `binding:"MaxSize(255)"`
Visibility structs.VisibleType
KeepActivityPrivate bool
Name string `binding:"Username;MaxSize(40)"`
FullName string `binding:"MaxSize(100)"`
KeepEmailPrivate bool
Website string `binding:"ValidSiteUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Description string `binding:"MaxSize(255)"`
Visibility structs.VisibleType
ActivityVisibility structs.ActivityVisibility
}
// Validate validates the fields

View File

@ -27,7 +27,7 @@ type UpdateOptions struct {
MaxRepoCreation optional.Option[int]
IsRestricted optional.Option[bool]
Visibility optional.Option[structs.VisibleType]
KeepActivityPrivate optional.Option[bool]
ActivityVisibility optional.Option[structs.ActivityVisibility]
Language optional.Option[string]
Theme optional.Option[string]
DiffViewStyle optional.Option[string]
@ -129,10 +129,10 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er
cols = append(cols, "visibility")
}
if opts.KeepActivityPrivate.Has() {
u.KeepActivityPrivate = opts.KeepActivityPrivate.Value()
if opts.ActivityVisibility.Has() {
u.ActivityVisibility = opts.ActivityVisibility.Value()
cols = append(cols, "keep_activity_private")
cols = append(cols, "activity_visibility")
}
if opts.AllowCreateOrganization.Has() {

View File

@ -40,7 +40,7 @@ func TestUpdateUser(t *testing.T) {
IsActive: optional.Some(false),
IsAdmin: optional.Some(true),
Visibility: optional.Some(structs.VisibleTypePrivate),
KeepActivityPrivate: optional.Some(true),
ActivityVisibility: optional.Some(structs.ActivityVisibilityNone),
Language: optional.Some("lang"),
Theme: optional.Some("theme"),
DiffViewStyle: optional.Some("split"),
@ -62,7 +62,7 @@ func TestUpdateUser(t *testing.T) {
assert.Equal(t, opts.IsActive.Value(), user.IsActive)
assert.Equal(t, opts.IsAdmin.Value(), user.IsAdmin)
assert.Equal(t, opts.Visibility.Value(), user.Visibility)
assert.Equal(t, opts.KeepActivityPrivate.Value(), user.KeepActivityPrivate)
assert.Equal(t, opts.ActivityVisibility.Value(), user.ActivityVisibility)
assert.Equal(t, opts.Language.Value(), user.Language)
assert.Equal(t, opts.Theme.Value(), user.Theme)
assert.Equal(t, opts.DiffViewStyle.Value(), user.DiffViewStyle)
@ -82,7 +82,7 @@ func TestUpdateUser(t *testing.T) {
assert.Equal(t, opts.IsActive.Value(), user.IsActive)
assert.Equal(t, opts.IsAdmin.Value(), user.IsAdmin)
assert.Equal(t, opts.Visibility.Value(), user.Visibility)
assert.Equal(t, opts.KeepActivityPrivate.Value(), user.KeepActivityPrivate)
assert.Equal(t, opts.ActivityVisibility.Value(), user.ActivityVisibility)
assert.Equal(t, opts.Language.Value(), user.Language)
assert.Equal(t, opts.Theme.Value(), user.Theme)
assert.Equal(t, opts.DiffViewStyle.Value(), user.DiffViewStyle)

View File

@ -18006,6 +18006,12 @@
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"ActivityVisibility": {
"description": "ActivityVisibility defines the activities shown",
"type": "integer",
"format": "int64",
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"AddCollaboratorOption": {
"description": "AddCollaboratorOption options when adding a user as a collaborator of a repository",
"type": "object",
@ -24319,6 +24325,9 @@
"description": "UserSettings represents user settings",
"type": "object",
"properties": {
"activity_visibility": {
"$ref": "#/definitions/ActivityVisibility"
},
"description": {
"type": "string",
"x-go-name": "Description"
@ -24331,10 +24340,6 @@
"type": "string",
"x-go-name": "FullName"
},
"hide_activity": {
"type": "boolean",
"x-go-name": "HideActivity"
},
"hide_email": {
"description": "Privacy",
"type": "boolean",
@ -24363,6 +24368,9 @@
"description": "UserSettingsOptions represents options to change user settings",
"type": "object",
"properties": {
"activity_visibility": {
"$ref": "#/definitions/ActivityVisibility"
},
"description": {
"type": "string",
"x-go-name": "Description"
@ -24375,10 +24383,6 @@
"type": "string",
"x-go-name": "FullName"
},
"hide_activity": {
"type": "boolean",
"x-go-name": "HideActivity"
},
"hide_email": {
"description": "Privacy",
"type": "boolean",

View File

@ -5,121 +5,144 @@
{{ctx.AvatarUtils.AvatarByAction .}}
</div>
<div class="flex-item-main tw-gap-2">
<div>
{{if gt .ActUser.ID 0}}
<a href="{{AppSubUrl}}/{{(.GetActUserName ctx) | PathEscape}}" title="{{.GetActDisplayNameTitle ctx}}">{{.GetActDisplayName ctx}}</a>
{{else}}
{{.ShortActUserName ctx}}
{{end}}
{{if .GetOpType.InActions "create_repo"}}
{{ctx.Locale.Tr "action.create_repo" (.GetRepoLink ctx) (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "rename_repo"}}
{{ctx.Locale.Tr "action.rename_repo" .GetContent (.GetRepoLink ctx) (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "commit_repo"}}
{{if .Content}}
{{ctx.Locale.Tr "action.commit_repo" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{if .IsPrivateView}}
<div>
{{if gt .ActUser.ID 0}}
<a href="{{AppSubUrl}}/{{(.GetActUserName ctx) | PathEscape}}" title="{{.GetActDisplayNameTitle ctx}}">{{.GetActDisplayName ctx}}</a>
{{else}}
{{ctx.Locale.Tr "action.create_branch" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{.ShortActUserName ctx}}
{{end}}
{{$pushLength := 1}}
{{if .GetOpType.InActions "commit_repo" "mirror_sync_push"}}
{{$commitLength := (ActionContent2Commits .).Len}}
{{if gt $commitLength $pushLength}}
{{$pushLength = $commitLength}}
{{end}}
{{end}}
{{ctx.Locale.TrN $pushLength "action.performed_1" "action.performed_n" $pushLength}}
{{TimeSince .GetCreate ctx.Locale}}
</div>
{{else}}
<div>
{{if gt .ActUser.ID 0}}
<a href="{{AppSubUrl}}/{{(.GetActUserName ctx) | PathEscape}}" title="{{.GetActDisplayNameTitle ctx}}">{{.GetActDisplayName ctx}}</a>
{{else}}
{{.ShortActUserName ctx}}
{{end}}
{{if .GetOpType.InActions "create_repo"}}
{{ctx.Locale.Tr "action.create_repo" (.GetRepoLink ctx) (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "rename_repo"}}
{{ctx.Locale.Tr "action.rename_repo" .GetContent (.GetRepoLink ctx) (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "commit_repo"}}
{{if .Content}}
{{ctx.Locale.Tr "action.commit_repo" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else}}
{{ctx.Locale.Tr "action.create_branch" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{end}}
{{else if .GetOpType.InActions "create_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.create_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "create_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.create_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "transfer_repo"}}
{{ctx.Locale.Tr "action.transfer_repo" .GetContent (.GetRepoLink ctx) (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "push_tag"}}
{{ctx.Locale.Tr "action.push_tag" (.GetRepoLink ctx) (.GetRefLink ctx) .GetTag (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "comment_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.comment_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "merge_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.merge_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "close_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.close_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "reopen_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.reopen_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "close_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.close_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "reopen_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.reopen_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "delete_tag"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.delete_tag" (.GetRepoLink ctx) .GetTag (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "delete_branch"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.delete_branch" (.GetRepoLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "mirror_sync_push"}}
{{ctx.Locale.Tr "action.mirror_sync_push" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "mirror_sync_create"}}
{{ctx.Locale.Tr "action.mirror_sync_create" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "mirror_sync_delete"}}
{{ctx.Locale.Tr "action.mirror_sync_delete" (.GetRepoLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "approve_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.approve_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "reject_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.reject_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "comment_pull"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.comment_pull" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "publish_release"}}
{{$linkText := .Content | RenderEmoji $.Context}}
{{ctx.Locale.Tr "action.publish_release" (.GetRepoLink ctx) (printf "%s/releases/tag/%s" (.GetRepoLink ctx) .GetTag) (.ShortRepoPath ctx) $linkText}}
{{else if .GetOpType.InActions "review_dismissed"}}
{{$index := index .GetIssueInfos 0}}
{{$reviewer := index .GetIssueInfos 1}}
{{ctx.Locale.Tr "action.review_dismissed" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx) $reviewer}}
{{end}}
{{TimeSince .GetCreate ctx.Locale}}
</div>
{{if .GetOpType.InActions "commit_repo" "mirror_sync_push"}}
{{$push := ActionContent2Commits .}}
{{$repoLink := (.GetRepoLink ctx)}}
{{$repo := .Repo}}
<div class="tw-flex tw-flex-col tw-gap-1">
{{range $push.Commits}}
{{$commitLink := printf "%s/commit/%s" $repoLink .Sha1}}
<div class="flex-text-block">
<img class="ui avatar" src="{{$push.AvatarLink $.Context .AuthorEmail}}" title="{{.AuthorName}}" width="16" height="16">
<a class="ui sha label" href="{{$commitLink}}">{{ShortSha .Sha1}}</a>
<span class="text truncate">
{{RenderCommitMessage $.Context .Message ($repo.ComposeMetas ctx)}}
</span>
</div>
{{end}}
</div>
{{if and (gt $push.Len 1) $push.CompareURL}}
<a href="{{AppSubUrl}}/{{$push.CompareURL}}">{{ctx.Locale.Tr "action.compare_commits" $push.Len}} »</a>
{{end}}
{{else if .GetOpType.InActions "create_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.create_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span>
{{else if .GetOpType.InActions "create_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.create_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "transfer_repo"}}
{{ctx.Locale.Tr "action.transfer_repo" .GetContent (.GetRepoLink ctx) (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "push_tag"}}
{{ctx.Locale.Tr "action.push_tag" (.GetRepoLink ctx) (.GetRefLink ctx) .GetTag (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "comment_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.comment_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "merge_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.merge_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "close_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.close_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "reopen_issue"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.reopen_issue" (printf "%s/issues/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "close_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.close_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "reopen_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.reopen_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "delete_tag"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.delete_tag" (.GetRepoLink ctx) .GetTag (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "delete_branch"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.delete_branch" (.GetRepoLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "mirror_sync_push"}}
{{ctx.Locale.Tr "action.mirror_sync_push" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "mirror_sync_create"}}
{{ctx.Locale.Tr "action.mirror_sync_create" (.GetRepoLink ctx) (.GetRefLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "mirror_sync_delete"}}
{{ctx.Locale.Tr "action.mirror_sync_delete" (.GetRepoLink ctx) .GetBranch (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "approve_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.approve_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "reject_pull_request"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.reject_pull_request" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "comment_pull"}}
{{$index := index .GetIssueInfos 0}}
{{ctx.Locale.Tr "action.comment_pull" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx)}}
{{else if .GetOpType.InActions "publish_release"}}
{{$linkText := .Content | RenderEmoji $.Context}}
{{ctx.Locale.Tr "action.publish_release" (.GetRepoLink ctx) (printf "%s/releases/tag/%s" (.GetRepoLink ctx) .GetTag) (.ShortRepoPath ctx) $linkText}}
{{else if .GetOpType.InActions "review_dismissed"}}
{{$index := index .GetIssueInfos 0}}
{{$reviewer := index .GetIssueInfos 1}}
{{ctx.Locale.Tr "action.review_dismissed" (printf "%s/pulls/%s" (.GetRepoLink ctx) $index) $index (.ShortRepoPath ctx) $reviewer}}
{{end}}
{{TimeSince .GetCreate ctx.Locale}}
</div>
{{if .GetOpType.InActions "commit_repo" "mirror_sync_push"}}
{{$push := ActionContent2Commits .}}
{{$repoLink := (.GetRepoLink ctx)}}
{{$repo := .Repo}}
<div class="tw-flex tw-flex-col tw-gap-1">
{{range $push.Commits}}
{{$commitLink := printf "%s/commit/%s" $repoLink .Sha1}}
<div class="flex-text-block">
<img class="ui avatar" src="{{$push.AvatarLink $.Context .AuthorEmail}}" title="{{.AuthorName}}" width="16" height="16">
<a class="ui sha label" href="{{$commitLink}}">{{ShortSha .Sha1}}</a>
<span class="text truncate">
{{RenderCommitMessage $.Context .Message ($repo.ComposeMetas ctx)}}
</span>
</div>
<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span>
{{else if .GetOpType.InActions "comment_issue" "approve_pull_request" "reject_pull_request" "comment_pull"}}
<a href="{{.GetCommentLink ctx}}" class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</a>
{{$comment := index .GetIssueInfos 1}}
{{if $comment}}
<div class="markup tw-text-14">{{RenderMarkdownToHtml ctx $comment}}</div>
{{end}}
</div>
{{if and (gt $push.Len 1) $push.CompareURL}}
<a href="{{AppSubUrl}}/{{$push.CompareURL}}">{{ctx.Locale.Tr "action.compare_commits" $push.Len}} »</a>
{{else if .GetOpType.InActions "merge_pull_request"}}
<div class="flex-item-body text black">{{index .GetIssueInfos 1}}</div>
{{else if .GetOpType.InActions "close_issue" "reopen_issue" "close_pull_request" "reopen_pull_request"}}
<span class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</span>
{{else if .GetOpType.InActions "pull_review_dismissed"}}
<div class="flex-item-body text black">{{ctx.Locale.Tr "action.review_dismissed_reason"}}</div>
<div class="flex-item-body text black">{{index .GetIssueInfos 2 | RenderEmoji $.Context}}</div>
{{end}}
{{else if .GetOpType.InActions "create_issue"}}
<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span>
{{else if .GetOpType.InActions "create_pull_request"}}
<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span>
{{else if .GetOpType.InActions "comment_issue" "approve_pull_request" "reject_pull_request" "comment_pull"}}
<a href="{{.GetCommentLink ctx}}" class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</a>
{{$comment := index .GetIssueInfos 1}}
{{if $comment}}
<div class="markup tw-text-14">{{RenderMarkdownToHtml ctx $comment}}</div>
{{end}}
{{else if .GetOpType.InActions "merge_pull_request"}}
<div class="flex-item-body text black">{{index .GetIssueInfos 1}}</div>
{{else if .GetOpType.InActions "close_issue" "reopen_issue" "close_pull_request" "reopen_pull_request"}}
<span class="text truncate issue title">{{(.GetIssueTitle ctx) | RenderEmoji $.Context | RenderCodeBlock}}</span>
{{else if .GetOpType.InActions "pull_review_dismissed"}}
<div class="flex-item-body text black">{{ctx.Locale.Tr "action.review_dismissed_reason"}}</div>
<div class="flex-item-body text black">{{index .GetIssueInfos 2 | RenderEmoji $.Context}}</div>
{{end}}
</div>
<div class="flex-item-trailing">
{{svg (printf "octicon-%s" (ActionIcon .GetOpType)) 32 "text grey tw-mr-1"}}
{{if .IsPrivateView}}
{{svg "octicon-lock" 32 "text grey tw-mr-1"}}
{{else}}
{{svg (printf "octicon-%s" (ActionIcon .GetOpType)) 32 "text grey tw-mr-1"}}
{{end}}
</div>
</div>
{{end}}

View File

@ -8,13 +8,14 @@
<div class="ui twelve wide column tw-mb-4">
{{template "user/overview/header" .}}
{{if eq .TabName "activity"}}
{{if .ContextUser.KeepActivityPrivate}}
{{if and .ContextUser.ActivityVisibility.ShowNone (not .IsAdmin) (ne .ContextUser.ID .SignedUserID)}}
<div class="ui info message">
<p>{{ctx.Locale.Tr "user.disabled_public_activity"}}</p>
</div>
{{else}}
{{template "user/heatmap" .}}
{{template "user/dashboard/feeds" .}}
{{end}}
{{template "user/heatmap" .}}
{{template "user/dashboard/feeds" .}}
{{else if eq .TabName "stars"}}
<div class="stars">
{{template "shared/repo_search" .}}

View File

@ -71,17 +71,28 @@
</div>
</div>
<div class="field">
<div class="ui checkbox">
<label data-tooltip-content="{{ctx.Locale.Tr "settings.keep_email_private_popup" .SignedUser.GetPlaceholderEmail}}"><strong>{{ctx.Locale.Tr "settings.keep_email_private"}}</strong></label>
<input name="keep_email_private" type="checkbox" {{if .SignedUser.KeepEmailPrivate}}checked{{end}}>
<div class="inline field">
<span class="inline field" data-tooltip-content="{{ctx.Locale.Tr "settings.activity_visibility_popup"}}"><label>{{ctx.Locale.Tr "settings.activity_visibility"}}</label></span>
<div class="ui selection type dropdown">
<input type="hidden" id="activity_visibility" name="activity_visibility" value="{{printf "%d" .SignedUser.ActivityVisibility}}">
<div class="text">
{{if .SignedUser.ActivityVisibility.ShowPublic}}{{ctx.Locale.Tr "public"}}{{end}}
{{if .SignedUser.ActivityVisibility.ShowAll}}{{ctx.Locale.Tr "all"}}{{end}}
{{if .SignedUser.ActivityVisibility.ShowNone}}{{ctx.Locale.Tr "none"}}{{end}}
</div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item" data-tooltip-content="{{ctx.Locale.Tr "settings.activity_visibility.public_popup"}}" data-value="0">{{ctx.Locale.Tr "public"}}</div>
<div class="item" data-tooltip-content="{{ctx.Locale.Tr "settings.activity_visibility.all_popup"}}" data-value="1">{{ctx.Locale.Tr "all"}}</div>
<div class="item" data-tooltip-content="{{ctx.Locale.Tr "settings.activity_visibility.none_popup"}}" data-value="2">{{ctx.Locale.Tr "none"}}</div>
</div>
</div>
</div>
<div class="field">
<div class="ui checkbox" id="keep-activity-private">
<label data-tooltip-content="{{ctx.Locale.Tr "settings.keep_activity_private_popup"}}"><strong>{{ctx.Locale.Tr "settings.keep_activity_private"}}</strong></label>
<input name="keep_activity_private" type="checkbox" {{if .SignedUser.KeepActivityPrivate}}checked{{end}}>
<div class="ui checkbox">
<label data-tooltip-content="{{ctx.Locale.Tr "settings.keep_email_private_popup" .SignedUser.GetPlaceholderEmail}}"><strong>{{ctx.Locale.Tr "settings.keep_email_private"}}</strong></label>
<input name="keep_email_private" type="checkbox" {{if .SignedUser.KeepEmailPrivate}}checked{{end}}>
</div>
</div>

View File

@ -48,11 +48,11 @@ func testPrivateActivityDoSomethingForActionEntries(t *testing.T) {
func testPrivateActivityHelperEnablePrivateActivity(t *testing.T) {
session := loginUser(t, privateActivityTestUser)
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
"_csrf": GetCSRF(t, session, "/user/settings"),
"name": privateActivityTestUser,
"email": privateActivityTestUser + "@example.com",
"language": "en-US",
"keep_activity_private": "1",
"_csrf": GetCSRF(t, session, "/user/settings"),
"name": privateActivityTestUser,
"email": privateActivityTestUser + "@example.com",
"language": "en-US",
"activity_visibility": fmt.Sprintf("%d", api.ActivityVisibilityNone),
})
session.MakeRequest(t, req, http.StatusSeeOther)
}