mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-04-23 03:21:35 +02:00
For updates a shadow copy should be created only when relevant user fields are altered.
This commit is contained in:
parent
a472176686
commit
39565a6b9d
2 changed files with 72 additions and 31 deletions
|
@ -5,25 +5,33 @@ package user
|
|||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"code.gitea.io/gitea/models/moderation"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm/names"
|
||||
)
|
||||
|
||||
// UserData represents a trimmed down user that is used for preserving only the fields needed for abusive content reports.
|
||||
// UserData represents a trimmed down user that is used for preserving
|
||||
// only the fields needed for abusive content reports (mainly string fields).
|
||||
type UserData struct {
|
||||
Name string
|
||||
FullName string
|
||||
Email string
|
||||
LoginName string
|
||||
Location string
|
||||
Website string
|
||||
Pronouns string
|
||||
Description string
|
||||
CreatedUnix timeutil.TimeStamp
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
LastLoginUnix timeutil.TimeStamp
|
||||
Name string
|
||||
FullName string
|
||||
Email string
|
||||
LoginName string
|
||||
Location string
|
||||
Website string
|
||||
Pronouns string
|
||||
Description string
|
||||
CreatedUnix timeutil.TimeStamp
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
// This field was intentionally renamed so that is not the same with the one from User struct.
|
||||
// If we keep it the same as in User, during login it might trigger the creation of a shadow copy.
|
||||
// TODO: Should we decide that this field is not that relevant for abuse reporting purposes, better remove it.
|
||||
LastLogin timeutil.TimeStamp `json:"LastLoginUnix"`
|
||||
Avatar string
|
||||
AvatarEmail string
|
||||
NormalizedFederatedURI string
|
||||
|
@ -33,29 +41,59 @@ type UserData struct {
|
|||
// (keeping only the fields relevant for moderation purposes)
|
||||
func newUserData(user *User) UserData {
|
||||
return UserData{
|
||||
Name: user.Name,
|
||||
FullName: user.FullName,
|
||||
Email: user.Email,
|
||||
LoginName: user.LoginName,
|
||||
Location: user.Location,
|
||||
Website: user.Website,
|
||||
Pronouns: user.Pronouns,
|
||||
Description: user.Description,
|
||||
CreatedUnix: user.CreatedUnix,
|
||||
UpdatedUnix: user.UpdatedUnix,
|
||||
LastLoginUnix: user.LastLoginUnix,
|
||||
Avatar: user.Avatar,
|
||||
AvatarEmail: user.AvatarEmail,
|
||||
Name: user.Name,
|
||||
FullName: user.FullName,
|
||||
Email: user.Email,
|
||||
LoginName: user.LoginName,
|
||||
Location: user.Location,
|
||||
Website: user.Website,
|
||||
Pronouns: user.Pronouns,
|
||||
Description: user.Description,
|
||||
CreatedUnix: user.CreatedUnix,
|
||||
UpdatedUnix: user.UpdatedUnix,
|
||||
LastLogin: user.LastLoginUnix,
|
||||
Avatar: user.Avatar,
|
||||
AvatarEmail: user.AvatarEmail,
|
||||
NormalizedFederatedURI: user.NormalizedFederatedURI,
|
||||
}
|
||||
}
|
||||
|
||||
// IfNeededCreateShadowCopyForUser checks if for the given user there are any reports of abusive content submitted
|
||||
// and if found a shadow copy of relevant user fields will be stored into DB and linked to the above report(s).
|
||||
// This function should be called when a user is deleted or updated.
|
||||
func IfNeededCreateShadowCopyForUser(ctx context.Context, user *User) error {
|
||||
if moderation.IsReported(ctx, moderation.ReportedContentTypeUser, user.ID) {
|
||||
userContent := newUserData(user)
|
||||
content, _ := json.Marshal(userContent)
|
||||
//
|
||||
// For deletions alteredCols argument must be omitted.
|
||||
//
|
||||
// In case of updates it will first checks whether any of the columns being updated (alteredCols argument)
|
||||
// is relevant for moderation purposes (i.e. included in the UserData struct).
|
||||
func IfNeededCreateShadowCopyForUser(ctx context.Context, user *User, alteredCols ...string) error {
|
||||
// TODO: this can be triggered quite often (e.g. by routers/web/repo/middlewares.go SetDiffViewStyle())
|
||||
|
||||
shouldCheckIfReported := len(alteredCols) == 0 // no columns being updated, therefore a deletion
|
||||
if !shouldCheckIfReported {
|
||||
// for updates we need to go further only if certain column are being changed
|
||||
mapper := new(names.GonicMapper)
|
||||
ucType := reflect.TypeOf(UserData{})
|
||||
|
||||
for i := 0; i < ucType.NumField(); i++ {
|
||||
field := ucType.Field(i)
|
||||
// get the corresponding column name for a field name (e.g. FieldName -> field_name).
|
||||
colName := mapper.Obj2Table(field.Name)
|
||||
if shouldCheckIfReported = slices.Contains(alteredCols, colName); shouldCheckIfReported {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Maybe it is better (faster) to first check the result of moderation.IsReported()
|
||||
// and only when true to check if any of the columns being updated is relevant in the context of shadow copying.
|
||||
|
||||
if shouldCheckIfReported && moderation.IsReported(ctx, moderation.ReportedContentTypeUser, user.ID) {
|
||||
userData := newUserData(user)
|
||||
content, err := json.Marshal(userData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return moderation.CreateShadowCopyForUser(ctx, user.ID, string(content))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// Copyright 2024-2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package user
|
||||
|
@ -156,6 +156,9 @@ type User struct {
|
|||
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
KeepPronounsPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableRepoUnitHints bool `xorm:"NOT NULL DEFAULT true"`
|
||||
|
||||
// If you add new fields that might be used to store abusive content (mainly string fields),
|
||||
// please also add them in the UserData struct and the corresponding constructor.
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -935,7 +938,7 @@ func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := IfNeededCreateShadowCopyForUser(ctx, u); err != nil {
|
||||
if err := IfNeededCreateShadowCopyForUser(ctx, u, cols...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue