Skip to content

Commit 1f40933

Browse files
qwerty287wxiaoguangzeripathGusted6543
authored
Add config options to hide issue events (#17414)
* Add config option to hide issue events Adds a config option `HIDE_ISSUE_EVENTS` to hide most issue events (changed labels, milestones, projects...) on the issue detail page. If this is true, only the following events (comment types) are shown: * plain comments * closed/reopned/merged * reviews * Make configurable using a list * Add docs * Add missing newline * Fix merge issues * Allow changes per user settings * Fix lint * Rm old docs * Apply suggestions from code review * Use bitsets * Rm comment * fmt * Fix lint * Use variable/constant to provide key * fmt * fix lint * refactor * Add a prefix for user setting key * Add license comment * Add license comment * Update services/forms/user_form_hidden_comments.go Co-authored-by: Gusted <[email protected]> * check len == 0 Co-authored-by: wxiaoguang <[email protected]> Co-authored-by: zeripath <[email protected]> Co-authored-by: Gusted <[email protected]> Co-authored-by: 6543 <[email protected]>
1 parent 108f1aa commit 1f40933

File tree

16 files changed

+1086
-769
lines changed

16 files changed

+1086
-769
lines changed

models/issue_comment.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ const (
9999
// 28 merge pull request
100100
CommentTypeMergePull
101101
// 29 push to PR head branch
102-
CommentTypePullPush
102+
CommentTypePullRequestPush
103103
// 30 Project changed
104104
CommentTypeProject
105105
// 31 Project board changed
@@ -725,7 +725,7 @@ func (c *Comment) CodeCommentURL() string {
725725

726726
// LoadPushCommits Load push commits
727727
func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
728-
if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullPush {
728+
if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullRequestPush {
729729
return nil
730730
}
731731

@@ -1325,7 +1325,7 @@ func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *Pul
13251325
}
13261326

13271327
ops := &CreateCommentOptions{
1328-
Type: CommentTypePullPush,
1328+
Type: CommentTypePullRequestPush,
13291329
Doer: pusher,
13301330
Repo: pr.BaseRepo,
13311331
}

models/user/setting.go

+43-11
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ func init() {
3131
db.RegisterModel(new(Setting))
3232
}
3333

34-
// GetSettings returns specific settings from user
35-
func GetSettings(uid int64, keys []string) (map[string]*Setting, error) {
34+
// GetUserSettings returns specific settings from user
35+
func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) {
3636
settings := make([]*Setting, 0, len(keys))
3737
if err := db.GetEngine(db.DefaultContext).
3838
Where("user_id=?", uid).
@@ -62,21 +62,53 @@ func GetUserAllSettings(uid int64) (map[string]*Setting, error) {
6262
return settingsMap, nil
6363
}
6464

65-
// DeleteSetting deletes a specific setting for a user
66-
func DeleteSetting(setting *Setting) error {
67-
_, err := db.GetEngine(db.DefaultContext).Delete(setting)
65+
func validateUserSettingKey(key string) error {
66+
if len(key) == 0 {
67+
return fmt.Errorf("setting key must be set")
68+
}
69+
if strings.ToLower(key) != key {
70+
return fmt.Errorf("setting key should be lowercase")
71+
}
72+
return nil
73+
}
74+
75+
// GetUserSetting gets a specific setting for a user
76+
func GetUserSetting(userID int64, key string, def ...string) (string, error) {
77+
if err := validateUserSettingKey(key); err != nil {
78+
return "", err
79+
}
80+
setting := &Setting{UserID: userID, SettingKey: key}
81+
has, err := db.GetEngine(db.DefaultContext).Get(setting)
82+
if err != nil {
83+
return "", err
84+
}
85+
if !has {
86+
if len(def) == 1 {
87+
return def[0], nil
88+
}
89+
return "", nil
90+
}
91+
return setting.SettingValue, nil
92+
}
93+
94+
// DeleteUserSetting deletes a specific setting for a user
95+
func DeleteUserSetting(userID int64, key string) error {
96+
if err := validateUserSettingKey(key); err != nil {
97+
return err
98+
}
99+
_, err := db.GetEngine(db.DefaultContext).Delete(&Setting{UserID: userID, SettingKey: key})
68100
return err
69101
}
70102

71-
// SetSetting updates a users' setting for a specific key
72-
func SetSetting(setting *Setting) error {
73-
if strings.ToLower(setting.SettingKey) != setting.SettingKey {
74-
return fmt.Errorf("setting key should be lowercase")
103+
// SetUserSetting updates a users' setting for a specific key
104+
func SetUserSetting(userID int64, key, value string) error {
105+
if err := validateUserSettingKey(key); err != nil {
106+
return err
75107
}
76-
return upsertSettingValue(setting.UserID, setting.SettingKey, setting.SettingValue)
108+
return upsertUserSettingValue(userID, key, value)
77109
}
78110

79-
func upsertSettingValue(userID int64, key, value string) error {
111+
func upsertUserSettingValue(userID int64, key, value string) error {
80112
return db.WithTx(func(ctx context.Context) error {
81113
e := db.GetEngine(ctx)
82114

models/user/setting_keys.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package user
6+
7+
const (
8+
// SettingsKeyHiddenCommentTypes is the settings key for hidden comment types
9+
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
10+
)

models/user/setting_test.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,29 @@ func TestSettings(t *testing.T) {
1919
newSetting := &Setting{UserID: 99, SettingKey: keyName, SettingValue: "Gitea User Setting Test"}
2020

2121
// create setting
22-
err := SetSetting(newSetting)
22+
err := SetUserSetting(newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue)
2323
assert.NoError(t, err)
2424
// test about saving unchanged values
25-
err = SetSetting(newSetting)
25+
err = SetUserSetting(newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue)
2626
assert.NoError(t, err)
2727

2828
// get specific setting
29-
settings, err := GetSettings(99, []string{keyName})
29+
settings, err := GetUserSettings(99, []string{keyName})
3030
assert.NoError(t, err)
3131
assert.Len(t, settings, 1)
3232
assert.EqualValues(t, newSetting.SettingValue, settings[keyName].SettingValue)
3333

34+
settingValue, err := GetUserSetting(99, keyName)
35+
assert.NoError(t, err)
36+
assert.EqualValues(t, newSetting.SettingValue, settingValue)
37+
38+
settingValue, err = GetUserSetting(99, "no_such")
39+
assert.NoError(t, err)
40+
assert.EqualValues(t, "", settingValue)
41+
3442
// updated setting
3543
updatedSetting := &Setting{UserID: 99, SettingKey: keyName, SettingValue: "Updated"}
36-
err = SetSetting(updatedSetting)
44+
err = SetUserSetting(updatedSetting.UserID, updatedSetting.SettingKey, updatedSetting.SettingValue)
3745
assert.NoError(t, err)
3846

3947
// get all settings
@@ -43,7 +51,7 @@ func TestSettings(t *testing.T) {
4351
assert.EqualValues(t, updatedSetting.SettingValue, settings[updatedSetting.SettingKey].SettingValue)
4452

4553
// delete setting
46-
err = DeleteSetting(&Setting{UserID: 99, SettingKey: keyName})
54+
err = DeleteUserSetting(99, keyName)
4755
assert.NoError(t, err)
4856
settings, err = GetUserAllSettings(99)
4957
assert.NoError(t, err)

modules/context/form.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ func (ctx *Context) FormInt64(key string) int64 {
4646
return v
4747
}
4848

49-
// FormBool returns true if the value for the provided key in the form is "1" or "true"
49+
// FormBool returns true if the value for the provided key in the form is "1", "true" or "on"
5050
func (ctx *Context) FormBool(key string) bool {
51-
v, _ := strconv.ParseBool(ctx.Req.FormValue(key))
51+
s := ctx.Req.FormValue(key)
52+
v, _ := strconv.ParseBool(s)
53+
v = v || strings.EqualFold(s, "on")
5254
return v
5355
}
5456

@@ -59,6 +61,8 @@ func (ctx *Context) FormOptionalBool(key string) util.OptionalBool {
5961
if len(value) == 0 {
6062
return util.OptionalBoolNone
6163
}
62-
v, _ := strconv.ParseBool(ctx.Req.FormValue(key))
64+
s := ctx.Req.FormValue(key)
65+
v, _ := strconv.ParseBool(s)
66+
v = v || strings.EqualFold(s, "on")
6367
return util.OptionalBoolOf(v)
6468
}

modules/notification/mail/mail.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *rep
4242
act = models.ActionCommentIssue
4343
} else if comment.Type == models.CommentTypeCode {
4444
act = models.ActionCommentIssue
45-
} else if comment.Type == models.CommentTypePullPush {
45+
} else if comment.Type == models.CommentTypePullRequestPush {
4646
act = 0
4747
}
4848

options/locale/locale_en-US.ini

+16
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,22 @@ continue = Continue
549549
cancel = Cancel
550550
language = Language
551551
ui = Theme
552+
hidden_comment_types = Hidden comment types
553+
comment_type_group_reference = Reference
554+
comment_type_group_label = Label
555+
comment_type_group_milestone = Milestone
556+
comment_type_group_assignee = Assignee
557+
comment_type_group_title = Title
558+
comment_type_group_branch = Branch
559+
comment_type_group_time_tracking = Time Tracking
560+
comment_type_group_deadline = Deadline
561+
comment_type_group_dependency = Dependency
562+
comment_type_group_lock = Lock Status
563+
comment_type_group_review_request = Review request
564+
comment_type_group_pull_request_push = Added commits
565+
comment_type_group_project = Project
566+
comment_type_group_issue_ref = Issue reference
567+
saved_successfully = Your settings were saved successfully.
552568
privacy = Privacy
553569
keep_activity_private = Hide the activity from the profile page
554570
keep_activity_private_popup = Makes the activity visible only for you and the admins

routers/web/repo/issue.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"math/big"
1314
"net/http"
1415
"net/url"
1516
"path"
@@ -1465,7 +1466,7 @@ func ViewIssue(ctx *context.Context) {
14651466
ctx.ServerError("LoadResolveDoer", err)
14661467
return
14671468
}
1468-
} else if comment.Type == models.CommentTypePullPush {
1469+
} else if comment.Type == models.CommentTypePullRequestPush {
14691470
participants = addParticipant(comment.Poster, participants)
14701471
if err = comment.LoadPushCommits(ctx); err != nil {
14711472
ctx.ServerError("LoadPushCommits", err)
@@ -1650,6 +1651,20 @@ func ViewIssue(ctx *context.Context) {
16501651
ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
16511652
ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
16521653
ctx.Data["RefEndName"] = git.RefEndName(issue.Ref)
1654+
1655+
var hiddenCommentTypes *big.Int
1656+
if ctx.IsSigned {
1657+
val, err := user_model.GetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes)
1658+
if err != nil {
1659+
ctx.ServerError("GetUserSetting", err)
1660+
return
1661+
}
1662+
hiddenCommentTypes, _ = new(big.Int).SetString(val, 10) // we can safely ignore the failed conversion here
1663+
}
1664+
ctx.Data["ShouldShowCommentType"] = func(commentType models.CommentType) bool {
1665+
return hiddenCommentTypes == nil || hiddenCommentTypes.Bit(int(commentType)) == 0
1666+
}
1667+
16531668
ctx.HTML(http.StatusOK, tplIssueView)
16541669
}
16551670

routers/web/user/setting/profile.go

+26
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"errors"
1010
"fmt"
1111
"io"
12+
"math/big"
1213
"net/http"
1314
"os"
1415
"path/filepath"
@@ -358,6 +359,18 @@ func Appearance(ctx *context.Context) {
358359
ctx.Data["Title"] = ctx.Tr("settings")
359360
ctx.Data["PageIsSettingsAppearance"] = true
360361

362+
var hiddenCommentTypes *big.Int
363+
val, err := user_model.GetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes)
364+
if err != nil {
365+
ctx.ServerError("GetUserSetting", err)
366+
return
367+
}
368+
hiddenCommentTypes, _ = new(big.Int).SetString(val, 10) // we can safely ignore the failed conversion here
369+
370+
ctx.Data["IsCommentTypeGroupChecked"] = func(commentTypeGroup string) bool {
371+
return forms.IsUserHiddenCommentTypeGroupChecked(commentTypeGroup, hiddenCommentTypes)
372+
}
373+
361374
ctx.HTML(http.StatusOK, tplSettingsAppearance)
362375
}
363376

@@ -416,3 +429,16 @@ func UpdateUserLang(ctx *context.Context) {
416429
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_language_success"))
417430
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
418431
}
432+
433+
// UpdateUserHiddenComments update a user's shown comment types
434+
func UpdateUserHiddenComments(ctx *context.Context) {
435+
err := user_model.SetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String())
436+
if err != nil {
437+
ctx.ServerError("SetUserSetting", err)
438+
return
439+
}
440+
441+
log.Trace("User settings updated: %s", ctx.User.Name)
442+
ctx.Flash.Success(ctx.Tr("settings.saved_successfully"))
443+
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
444+
}

routers/web/web.go

+1
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ func RegisterRoutes(m *web.Route) {
323323
m.Group("/appearance", func() {
324324
m.Get("", user_setting.Appearance)
325325
m.Post("/language", bindIgnErr(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang)
326+
m.Post("/hidden_comments", user_setting.UpdateUserHiddenComments)
326327
m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost)
327328
})
328329
m.Group("/security", func() {

0 commit comments

Comments
 (0)