0
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-07-19 23:38:29 +02:00
This commit is contained in:
NorthRealm 2025-07-11 16:09:54 +08:00
parent 7a635ddf97
commit 540c3f00eb
9 changed files with 276 additions and 0 deletions

View File

@ -0,0 +1,84 @@
- user_id: 1
actions: failureonly
- user_id: 2
actions: failureonly
- user_id: 3
actions: failureonly
- user_id: 4
actions: failureonly
- user_id: 5
actions: failureonly
- user_id: 6
actions: failureonly
- user_id: 7
actions: failureonly
- user_id: 8
actions: failureonly
- user_id: 9
actions: failureonly
- user_id: 10
actions: failureonly
- user_id: 11
actions: failureonly
- user_id: 12
actions: failureonly
- user_id: 13
actions: failureonly
- user_id: 14
actions: failureonly
- user_id: 15
actions: failureonly
- user_id: 16
actions: failureonly
- user_id: 17
actions: failureonly
- user_id: 18
actions: failureonly
- user_id: 19
actions: failureonly
- user_id: 20
actions: failureonly
- user_id: 21
actions: failureonly
- user_id: 22
actions: failureonly
- user_id: 23
actions: failureonly
- user_id: 24
actions: failureonly
- user_id: 25
actions: failureonly
- user_id: 26
actions: failureonly
- user_id: 27
actions: failureonly
- user_id: 28
actions: failureonly
- user_id: 29
actions: failureonly
- user_id: 30
actions: failureonly
- user_id: 31
actions: failureonly
- user_id: 32
actions: failureonly
- user_id: 33
actions: failureonly
- user_id: 34
actions: failureonly
- user_id: 35
actions: failureonly
- user_id: 36
actions: failureonly
- user_id: 37
actions: failureonly
- user_id: 38
actions: failureonly
- user_id: 39
actions: failureonly
- user_id: 40
actions: failureonly
- user_id: 41
actions: failureonly
- user_id: 42
actions: failureonly

View File

@ -382,6 +382,7 @@ func prepareMigrationTasks() []*migration {
newMigration(318, "Add anonymous_access_mode for repo_unit", v1_24.AddRepoUnitAnonymousAccessMode), newMigration(318, "Add anonymous_access_mode for repo_unit", v1_24.AddRepoUnitAnonymousAccessMode),
newMigration(319, "Add ExclusiveOrder to Label table", v1_24.AddExclusiveOrderColumnToLabelTable), newMigration(319, "Add ExclusiveOrder to Label table", v1_24.AddExclusiveOrderColumnToLabelTable),
newMigration(320, "Migrate two_factor_policy to login_source table", v1_24.MigrateSkipTwoFactor), newMigration(320, "Migrate two_factor_policy to login_source table", v1_24.MigrateSkipTwoFactor),
newMigration(321, "Add new table for fine-grained notification settings", v1_24.AddFineGrainedActionsNotificationSettings),
} }
return preparedMigrations return preparedMigrations
} }

View File

@ -0,0 +1,59 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_24
import (
"context"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"xorm.io/xorm"
)
type NotificationSettings struct {
UserID int64 `xorm:"pk"`
Actions string `xorm:"NOT NULL DEFAULT 'failureonly'"`
}
func (*NotificationSettings) TableName() string {
return "user_notification_settings"
}
func AddFineGrainedActionsNotificationSettings(x *xorm.Engine) error {
if err := x.Sync(&NotificationSettings{}); err != nil {
return err
}
settings := make([]NotificationSettings, 0, 100)
type User struct {
ID int64 `xorm:"pk autoincr"`
}
if err := db.Iterate(context.Background(), nil, func(ctx context.Context, user *User) error {
settings = append(settings, NotificationSettings{
UserID: user.ID,
Actions: user_model.NotificationActionsFailureOnly,
})
if len(settings) >= 100 {
_, err := x.Insert(&settings)
if err != nil {
return err
}
settings = settings[:0]
}
return nil
}); err != nil {
return err
}
if len(settings) > 0 {
if _, err := x.Insert(&settings); err != nil {
return err
}
}
return nil
}

View File

@ -798,6 +798,12 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o
return err return err
} }
if err := db.Insert(ctx, &NotificationSettings{
UserID: u.ID,
}); err != nil {
return err
}
return committer.Commit() return committer.Commit()
} }

View File

@ -0,0 +1,54 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"context"
"code.gitea.io/gitea/models/db"
)
const (
NotificationActionsAll = "all"
NotificationActionsFailureOnly = "failureonly"
NotificationActionsDisabled = "disabled"
)
type NotificationSettings struct {
UserID int64 `xorm:"pk"`
User *User `xorm:"-"`
Actions string `xorm:"NOT NULL DEFAULT 'failureonly'"`
}
func (NotificationSettings) TableName() string {
return "user_notification_settings"
}
func init() {
db.RegisterModel(new(NotificationSettings))
}
// GetUserNotificationSettings returns a user's fine-grained notification preference
func GetUserNotificationSettings(ctx context.Context, userID int64) (*NotificationSettings, error) {
settings := &NotificationSettings{}
if has, err := db.GetEngine(ctx).Where("user_id=?", userID).Get(settings); err != nil {
return nil, err
} else if !has {
return nil, nil
}
user, err := GetUserByID(ctx, userID)
if err != nil {
return nil, err
}
settings.User = user
return settings, nil
}
func UpdateUserNotificationSettings(ctx context.Context, settings *NotificationSettings) error {
_, err := db.GetEngine(ctx).Where("user_id = ?", settings.UserID).
Update(&NotificationSettings{
Actions: settings.Actions,
})
return err
}

View File

@ -0,0 +1,37 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"github.com/stretchr/testify/assert"
)
func TestUserNotificationSettings(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
settings, err := GetUserNotificationSettings(db.DefaultContext, 1)
assert.NoError(t, err)
assert.Equal(t, NotificationActionsFailureOnly, settings.Actions)
assert.NoError(t, UpdateUserNotificationSettings(db.DefaultContext, &NotificationSettings{
UserID: 1,
Actions: NotificationActionsAll,
}))
settings, err = GetUserNotificationSettings(db.DefaultContext, 1)
assert.NoError(t, err)
assert.Equal(t, NotificationActionsAll, settings.Actions)
assert.NoError(t, UpdateUserNotificationSettings(db.DefaultContext, &NotificationSettings{
UserID: 1,
Actions: NotificationActionsDisabled,
}))
settings, err = GetUserNotificationSettings(db.DefaultContext, 1)
assert.NoError(t, err)
assert.Equal(t, NotificationActionsDisabled, settings.Actions)
}

View File

@ -95,6 +95,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
&user_model.Blocking{BlockerID: u.ID}, &user_model.Blocking{BlockerID: u.ID},
&user_model.Blocking{BlockeeID: u.ID}, &user_model.Blocking{BlockeeID: u.ID},
&actions_model.ActionRunnerToken{OwnerID: u.ID}, &actions_model.ActionRunnerToken{OwnerID: u.ID},
&user_model.NotificationSettings{UserID: u.ID},
); err != nil { ); err != nil {
return fmt.Errorf("deleteBeans: %w", err) return fmt.Errorf("deleteBeans: %w", err)
} }

View File

@ -244,3 +244,15 @@ func UpdateAuth(ctx context.Context, u *user_model.User, opts *UpdateAuthOptions
} }
return nil return nil
} }
type UpdateNotificationSettingsOptions struct {
Actions optional.Option[string]
}
func UpdateNotificationSettings(ctx context.Context, settings *user_model.NotificationSettings, opts *UpdateNotificationSettingsOptions) error {
if opts.Actions.Has() {
settings.Actions = opts.Actions.Value()
}
return user_model.UpdateUserNotificationSettings(ctx, settings)
}

View File

@ -122,3 +122,25 @@ func TestUpdateAuth(t *testing.T) {
Password: optional.Some("aaaa"), Password: optional.Some("aaaa"),
}), password_module.ErrMinLength) }), password_module.ErrMinLength)
} }
func TestUpdateNotificationSettings(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
settings := &user_model.NotificationSettings{UserID: 2}
exists, err := db.GetEngine(db.DefaultContext).Get(settings)
assert.NoError(t, err)
assert.True(t, exists)
settingsCopy := *settings
assert.NoError(t, UpdateNotificationSettings(db.DefaultContext, settings, &UpdateNotificationSettingsOptions{
Actions: optional.Some(user_model.NotificationActionsAll),
}))
assert.Equal(t, user_model.NotificationActionsAll, settings.Actions)
assert.NotEqual(t, settingsCopy.Actions, settings.Actions)
assert.NoError(t, UpdateNotificationSettings(db.DefaultContext, settings, &UpdateNotificationSettingsOptions{
Actions: optional.Some(user_model.NotificationActionsDisabled),
}))
assert.Equal(t, user_model.NotificationActionsDisabled, settings.Actions)
assert.NotEqual(t, settingsCopy.Actions, settings.Actions)
}