Skip to content

Commit 540c3f0

Browse files
committed
DATABASE
1 parent 7a635dd commit 540c3f0

File tree

9 files changed

+276
-0
lines changed

9 files changed

+276
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
- user_id: 1
2+
actions: failureonly
3+
- user_id: 2
4+
actions: failureonly
5+
- user_id: 3
6+
actions: failureonly
7+
- user_id: 4
8+
actions: failureonly
9+
- user_id: 5
10+
actions: failureonly
11+
- user_id: 6
12+
actions: failureonly
13+
- user_id: 7
14+
actions: failureonly
15+
- user_id: 8
16+
actions: failureonly
17+
- user_id: 9
18+
actions: failureonly
19+
- user_id: 10
20+
actions: failureonly
21+
- user_id: 11
22+
actions: failureonly
23+
- user_id: 12
24+
actions: failureonly
25+
- user_id: 13
26+
actions: failureonly
27+
- user_id: 14
28+
actions: failureonly
29+
- user_id: 15
30+
actions: failureonly
31+
- user_id: 16
32+
actions: failureonly
33+
- user_id: 17
34+
actions: failureonly
35+
- user_id: 18
36+
actions: failureonly
37+
- user_id: 19
38+
actions: failureonly
39+
- user_id: 20
40+
actions: failureonly
41+
- user_id: 21
42+
actions: failureonly
43+
- user_id: 22
44+
actions: failureonly
45+
- user_id: 23
46+
actions: failureonly
47+
- user_id: 24
48+
actions: failureonly
49+
- user_id: 25
50+
actions: failureonly
51+
- user_id: 26
52+
actions: failureonly
53+
- user_id: 27
54+
actions: failureonly
55+
- user_id: 28
56+
actions: failureonly
57+
- user_id: 29
58+
actions: failureonly
59+
- user_id: 30
60+
actions: failureonly
61+
- user_id: 31
62+
actions: failureonly
63+
- user_id: 32
64+
actions: failureonly
65+
- user_id: 33
66+
actions: failureonly
67+
- user_id: 34
68+
actions: failureonly
69+
- user_id: 35
70+
actions: failureonly
71+
- user_id: 36
72+
actions: failureonly
73+
- user_id: 37
74+
actions: failureonly
75+
- user_id: 38
76+
actions: failureonly
77+
- user_id: 39
78+
actions: failureonly
79+
- user_id: 40
80+
actions: failureonly
81+
- user_id: 41
82+
actions: failureonly
83+
- user_id: 42
84+
actions: failureonly

models/migrations/migrations.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ func prepareMigrationTasks() []*migration {
382382
newMigration(318, "Add anonymous_access_mode for repo_unit", v1_24.AddRepoUnitAnonymousAccessMode),
383383
newMigration(319, "Add ExclusiveOrder to Label table", v1_24.AddExclusiveOrderColumnToLabelTable),
384384
newMigration(320, "Migrate two_factor_policy to login_source table", v1_24.MigrateSkipTwoFactor),
385+
newMigration(321, "Add new table for fine-grained notification settings", v1_24.AddFineGrainedActionsNotificationSettings),
385386
}
386387
return preparedMigrations
387388
}

models/migrations/v1_24/v321.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24
5+
6+
import (
7+
"context"
8+
9+
"code.gitea.io/gitea/models/db"
10+
user_model "code.gitea.io/gitea/models/user"
11+
12+
"xorm.io/xorm"
13+
)
14+
15+
type NotificationSettings struct {
16+
UserID int64 `xorm:"pk"`
17+
Actions string `xorm:"NOT NULL DEFAULT 'failureonly'"`
18+
}
19+
20+
func (*NotificationSettings) TableName() string {
21+
return "user_notification_settings"
22+
}
23+
24+
func AddFineGrainedActionsNotificationSettings(x *xorm.Engine) error {
25+
if err := x.Sync(&NotificationSettings{}); err != nil {
26+
return err
27+
}
28+
29+
settings := make([]NotificationSettings, 0, 100)
30+
31+
type User struct {
32+
ID int64 `xorm:"pk autoincr"`
33+
}
34+
35+
if err := db.Iterate(context.Background(), nil, func(ctx context.Context, user *User) error {
36+
settings = append(settings, NotificationSettings{
37+
UserID: user.ID,
38+
Actions: user_model.NotificationActionsFailureOnly,
39+
})
40+
if len(settings) >= 100 {
41+
_, err := x.Insert(&settings)
42+
if err != nil {
43+
return err
44+
}
45+
settings = settings[:0]
46+
}
47+
return nil
48+
}); err != nil {
49+
return err
50+
}
51+
52+
if len(settings) > 0 {
53+
if _, err := x.Insert(&settings); err != nil {
54+
return err
55+
}
56+
}
57+
58+
return nil
59+
}

models/user/user.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,12 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o
798798
return err
799799
}
800800

801+
if err := db.Insert(ctx, &NotificationSettings{
802+
UserID: u.ID,
803+
}); err != nil {
804+
return err
805+
}
806+
801807
return committer.Commit()
802808
}
803809

models/user/user_notification.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package user
5+
6+
import (
7+
"context"
8+
9+
"code.gitea.io/gitea/models/db"
10+
)
11+
12+
const (
13+
NotificationActionsAll = "all"
14+
NotificationActionsFailureOnly = "failureonly"
15+
NotificationActionsDisabled = "disabled"
16+
)
17+
18+
type NotificationSettings struct {
19+
UserID int64 `xorm:"pk"`
20+
User *User `xorm:"-"`
21+
Actions string `xorm:"NOT NULL DEFAULT 'failureonly'"`
22+
}
23+
24+
func (NotificationSettings) TableName() string {
25+
return "user_notification_settings"
26+
}
27+
28+
func init() {
29+
db.RegisterModel(new(NotificationSettings))
30+
}
31+
32+
// GetUserNotificationSettings returns a user's fine-grained notification preference
33+
func GetUserNotificationSettings(ctx context.Context, userID int64) (*NotificationSettings, error) {
34+
settings := &NotificationSettings{}
35+
if has, err := db.GetEngine(ctx).Where("user_id=?", userID).Get(settings); err != nil {
36+
return nil, err
37+
} else if !has {
38+
return nil, nil
39+
}
40+
user, err := GetUserByID(ctx, userID)
41+
if err != nil {
42+
return nil, err
43+
}
44+
settings.User = user
45+
return settings, nil
46+
}
47+
48+
func UpdateUserNotificationSettings(ctx context.Context, settings *NotificationSettings) error {
49+
_, err := db.GetEngine(ctx).Where("user_id = ?", settings.UserID).
50+
Update(&NotificationSettings{
51+
Actions: settings.Actions,
52+
})
53+
return err
54+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package user
5+
6+
import (
7+
"testing"
8+
9+
"code.gitea.io/gitea/models/db"
10+
"code.gitea.io/gitea/models/unittest"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestUserNotificationSettings(t *testing.T) {
16+
assert.NoError(t, unittest.PrepareTestDatabase())
17+
18+
settings, err := GetUserNotificationSettings(db.DefaultContext, 1)
19+
assert.NoError(t, err)
20+
assert.Equal(t, NotificationActionsFailureOnly, settings.Actions)
21+
22+
assert.NoError(t, UpdateUserNotificationSettings(db.DefaultContext, &NotificationSettings{
23+
UserID: 1,
24+
Actions: NotificationActionsAll,
25+
}))
26+
settings, err = GetUserNotificationSettings(db.DefaultContext, 1)
27+
assert.NoError(t, err)
28+
assert.Equal(t, NotificationActionsAll, settings.Actions)
29+
30+
assert.NoError(t, UpdateUserNotificationSettings(db.DefaultContext, &NotificationSettings{
31+
UserID: 1,
32+
Actions: NotificationActionsDisabled,
33+
}))
34+
settings, err = GetUserNotificationSettings(db.DefaultContext, 1)
35+
assert.NoError(t, err)
36+
assert.Equal(t, NotificationActionsDisabled, settings.Actions)
37+
}

services/user/delete.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
9595
&user_model.Blocking{BlockerID: u.ID},
9696
&user_model.Blocking{BlockeeID: u.ID},
9797
&actions_model.ActionRunnerToken{OwnerID: u.ID},
98+
&user_model.NotificationSettings{UserID: u.ID},
9899
); err != nil {
99100
return fmt.Errorf("deleteBeans: %w", err)
100101
}

services/user/update.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,15 @@ func UpdateAuth(ctx context.Context, u *user_model.User, opts *UpdateAuthOptions
244244
}
245245
return nil
246246
}
247+
248+
type UpdateNotificationSettingsOptions struct {
249+
Actions optional.Option[string]
250+
}
251+
252+
func UpdateNotificationSettings(ctx context.Context, settings *user_model.NotificationSettings, opts *UpdateNotificationSettingsOptions) error {
253+
if opts.Actions.Has() {
254+
settings.Actions = opts.Actions.Value()
255+
}
256+
257+
return user_model.UpdateUserNotificationSettings(ctx, settings)
258+
}

services/user/update_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,25 @@ func TestUpdateAuth(t *testing.T) {
122122
Password: optional.Some("aaaa"),
123123
}), password_module.ErrMinLength)
124124
}
125+
126+
func TestUpdateNotificationSettings(t *testing.T) {
127+
assert.NoError(t, unittest.PrepareTestDatabase())
128+
129+
settings := &user_model.NotificationSettings{UserID: 2}
130+
exists, err := db.GetEngine(db.DefaultContext).Get(settings)
131+
assert.NoError(t, err)
132+
assert.True(t, exists)
133+
settingsCopy := *settings
134+
135+
assert.NoError(t, UpdateNotificationSettings(db.DefaultContext, settings, &UpdateNotificationSettingsOptions{
136+
Actions: optional.Some(user_model.NotificationActionsAll),
137+
}))
138+
assert.Equal(t, user_model.NotificationActionsAll, settings.Actions)
139+
assert.NotEqual(t, settingsCopy.Actions, settings.Actions)
140+
141+
assert.NoError(t, UpdateNotificationSettings(db.DefaultContext, settings, &UpdateNotificationSettingsOptions{
142+
Actions: optional.Some(user_model.NotificationActionsDisabled),
143+
}))
144+
assert.Equal(t, user_model.NotificationActionsDisabled, settings.Actions)
145+
assert.NotEqual(t, settingsCopy.Actions, settings.Actions)
146+
}

0 commit comments

Comments
 (0)