Tim-Niclas Oelschläger 1 week ago
parent
commit
26301ef30a
No account linked to committer's email address

+ 64
- 24
models/activities/action.go 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)))
}


+ 5
- 4
models/activities/action_test.go 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,
}}

+ 41
- 41
models/fixtures/user.yml 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

+ 3
- 3
models/user/user.go 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() {

+ 50
- 0
modules/structs/activity_visibility.go 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 ""
}

+ 4
- 4
modules/structs/user.go 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

+ 9
- 2
options/locale/locale_en-US.ini 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

+ 9
- 9
routers/api/v1/user/settings.go 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)

+ 3
- 4
routers/web/user/profile.go 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,

+ 7
- 7
routers/web/user/setting/profile.go 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)

+ 9
- 9
services/convert/user.go 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,
}
}


+ 8
- 8
services/forms/user_form.go 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

+ 4
- 4
services/user/update.go 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() {

+ 3
- 3
services/user/update_test.go 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)

+ 12
- 8
templates/swagger/v1_json.tmpl 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",

+ 129
- 106
templates/user/dashboard/feeds.tmpl 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>
{{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>
{{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 "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}}

+ 4
- 3
templates/user/profile.tmpl 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" .}}

+ 18
- 7
templates/user/settings/profile.tmpl 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>


+ 5
- 5
tests/integration/privateactivity_test.go 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)
}

Loading…
Cancel
Save