2025-05-18 08:05:16 +00:00
|
|
|
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
package moderation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"forgejo.org/models/db"
|
|
|
|
"forgejo.org/modules/log"
|
|
|
|
"forgejo.org/modules/timeutil"
|
|
|
|
|
|
|
|
"xorm.io/builder"
|
|
|
|
)
|
|
|
|
|
|
|
|
type AbuseReportShadowCopy struct {
|
|
|
|
ID int64 `xorm:"pk autoincr"`
|
2025-06-27 15:47:58 +02:00
|
|
|
RawValue string `xorm:"LONGTEXT NOT NULL"` // A JSON with relevant fields from user, repository, issue or comment table.
|
2025-05-18 08:05:16 +00:00
|
|
|
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the ID encapsulated in a sql.NullInt64 struct.
|
|
|
|
func (sc AbuseReportShadowCopy) NullableID() sql.NullInt64 {
|
|
|
|
return sql.NullInt64{Int64: sc.ID, Valid: sc.ID > 0}
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
// RegisterModel will create the table if does not already exist
|
|
|
|
// or any missing columns if the table was previously created.
|
|
|
|
// It will not drop or rename existing columns (when struct has changed).
|
|
|
|
db.RegisterModel(new(AbuseReportShadowCopy))
|
|
|
|
}
|
|
|
|
|
|
|
|
func CreateShadowCopyForUser(ctx context.Context, userID int64, content string) error {
|
|
|
|
return createShadowCopy(ctx, ReportedContentTypeUser, userID, content)
|
|
|
|
}
|
|
|
|
|
|
|
|
func CreateShadowCopyForRepository(ctx context.Context, repoID int64, content string) error {
|
|
|
|
return createShadowCopy(ctx, ReportedContentTypeRepository, repoID, content)
|
|
|
|
}
|
|
|
|
|
|
|
|
func CreateShadowCopyForIssue(ctx context.Context, issueID int64, content string) error {
|
|
|
|
return createShadowCopy(ctx, ReportedContentTypeIssue, issueID, content)
|
|
|
|
}
|
|
|
|
|
|
|
|
func CreateShadowCopyForComment(ctx context.Context, commentID int64, content string) error {
|
|
|
|
return createShadowCopy(ctx, ReportedContentTypeComment, commentID, content)
|
|
|
|
}
|
|
|
|
|
|
|
|
func createShadowCopy(ctx context.Context, contentType ReportedContentType, contentID int64, content string) error {
|
|
|
|
err := db.WithTx(ctx, func(ctx context.Context) error {
|
|
|
|
sess := db.GetEngine(ctx)
|
|
|
|
|
|
|
|
shadowCopy := &AbuseReportShadowCopy{RawValue: content}
|
|
|
|
affected, err := sess.Insert(shadowCopy)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
} else if affected == 0 {
|
|
|
|
log.Warn("Something went wrong while trying to create the shadow copy for reported content with type %d and ID %d.", contentType, contentID)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = sess.Where(builder.Eq{
|
|
|
|
"content_type": contentType,
|
|
|
|
"content_id": contentID,
|
|
|
|
}).And(builder.IsNull{"shadow_copy_id"}).Update(&AbuseReport{ShadowCopyID: shadowCopy.NullableID()})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not link the shadow copy (%d) to reported content with type %d and ID %d - %w", shadowCopy.ID, contentType, contentID, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|