feat: add safety reporting APIs
This commit is contained in:
@@ -1520,6 +1520,95 @@ func (devicePushTokenMapper) Upsert(tenantID types.TenantID, token *types.Device
|
||||
return tenantAdp.TenantDevicePushTokenUpsert(tenantID, token)
|
||||
}
|
||||
|
||||
type SafetyPersistenceInterface interface {
|
||||
CreateRiskChallenge(tenantID types.TenantID, challenge *types.RiskChallenge) (*types.RiskChallenge, error)
|
||||
ConfirmRiskChallenge(tenantID types.TenantID, uid types.Uid, challengeID, decision, actionTokenID string, now time.Time) (*types.RiskChallenge, error)
|
||||
AbuseReasons(tenantID types.TenantID, targetType string) ([]types.AbuseReason, error)
|
||||
CreateAbuseReport(tenantID types.TenantID, report *types.AbuseReport, idempotencyKey string) (*types.AbuseReport, error)
|
||||
FeedbackConfig(tenantID types.TenantID, uid types.Uid) (*types.FeedbackConfig, error)
|
||||
CreateFeedback(tenantID types.TenantID, feedback *types.FeedbackSubmission, idempotencyKey string) (*types.FeedbackSubmission, error)
|
||||
}
|
||||
|
||||
type safetyMapper struct{}
|
||||
|
||||
var Safety SafetyPersistenceInterface
|
||||
|
||||
func (safetyMapper) CreateRiskChallenge(tenantID types.TenantID, challenge *types.RiskChallenge) (*types.RiskChallenge, error) {
|
||||
if challenge == nil || challenge.UserID.IsZero() || strings.TrimSpace(challenge.ChallengeID) == "" ||
|
||||
strings.TrimSpace(challenge.Action) == "" || challenge.ExpiresAt.IsZero() {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantRiskChallengeCreate(tenantID, challenge)
|
||||
}
|
||||
|
||||
func (safetyMapper) ConfirmRiskChallenge(tenantID types.TenantID, uid types.Uid, challengeID, decision, actionTokenID string, now time.Time) (*types.RiskChallenge, error) {
|
||||
decision = strings.ToLower(strings.TrimSpace(decision))
|
||||
if uid.IsZero() || strings.TrimSpace(challengeID) == "" || (decision != "continue" && decision != "cancel") {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantRiskChallengeConfirm(tenantID, uid, strings.TrimSpace(challengeID), decision, strings.TrimSpace(actionTokenID), now)
|
||||
}
|
||||
|
||||
func (safetyMapper) AbuseReasons(tenantID types.TenantID, targetType string) ([]types.AbuseReason, error) {
|
||||
targetType = strings.ToLower(strings.TrimSpace(targetType))
|
||||
if targetType == "" {
|
||||
targetType = "message"
|
||||
}
|
||||
if targetType != "user" && targetType != "group" && targetType != "message" {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantAbuseReasons(tenantID, targetType)
|
||||
}
|
||||
|
||||
func (safetyMapper) CreateAbuseReport(tenantID types.TenantID, report *types.AbuseReport, idempotencyKey string) (*types.AbuseReport, error) {
|
||||
if report == nil || report.ReporterID.IsZero() || strings.TrimSpace(report.ReportID) == "" ||
|
||||
strings.TrimSpace(report.TargetType) == "" || strings.TrimSpace(report.ReasonCode) == "" ||
|
||||
strings.TrimSpace(idempotencyKey) == "" {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantAbuseReportCreate(tenantID, report, strings.TrimSpace(idempotencyKey))
|
||||
}
|
||||
|
||||
func (safetyMapper) FeedbackConfig(tenantID types.TenantID, uid types.Uid) (*types.FeedbackConfig, error) {
|
||||
if uid.IsZero() {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantFeedbackConfigGet(tenantID, uid)
|
||||
}
|
||||
|
||||
func (safetyMapper) CreateFeedback(tenantID types.TenantID, feedback *types.FeedbackSubmission, idempotencyKey string) (*types.FeedbackSubmission, error) {
|
||||
if feedback == nil || feedback.UserID.IsZero() || strings.TrimSpace(feedback.FeedbackID) == "" ||
|
||||
strings.TrimSpace(feedback.Category) == "" || strings.TrimSpace(feedback.Content) == "" ||
|
||||
strings.TrimSpace(idempotencyKey) == "" {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
tenantAdp, err := tenantBusinessAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tenantAdp.TenantFeedbackCreate(tenantID, feedback, strings.TrimSpace(idempotencyKey))
|
||||
}
|
||||
|
||||
func (profileMapper) Get(tenantID types.TenantID, uid types.Uid) (*types.UserProfile, error) {
|
||||
if uid.IsZero() {
|
||||
return nil, types.ErrMalformed
|
||||
@@ -2781,6 +2870,7 @@ func init() {
|
||||
Profiles = profileMapper{}
|
||||
AppReleases = appReleaseMapper{}
|
||||
DevicePushTokens = devicePushTokenMapper{}
|
||||
Safety = safetyMapper{}
|
||||
Devices = deviceMapper{}
|
||||
Files = fileMapper{}
|
||||
PCache = pcacheMapper{}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
RiskChallengeStatePending = "pending"
|
||||
RiskChallengeStateContinued = "continued"
|
||||
RiskChallengeStateCanceled = "canceled"
|
||||
RiskChallengeStateExpired = "expired"
|
||||
|
||||
AbuseReportStatusReceived = "received"
|
||||
FeedbackStatusReceived = "received"
|
||||
)
|
||||
|
||||
type RiskChallenge struct {
|
||||
ID int64
|
||||
ChallengeID string
|
||||
UserID Uid
|
||||
Action string
|
||||
Level string
|
||||
NoticeCode string
|
||||
NoticeParams map[string]any
|
||||
State string
|
||||
ExpiresAt time.Time
|
||||
Decision string
|
||||
ActionTokenID string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type AbuseReason struct {
|
||||
TargetType string
|
||||
ReasonCode string
|
||||
Label string
|
||||
RequiresDescription bool
|
||||
AllowsEvidence bool
|
||||
SortOrder int
|
||||
}
|
||||
|
||||
type AbuseTarget struct {
|
||||
Type string `json:"type"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
Topic string `json:"topic,omitempty"`
|
||||
Seq string `json:"seq,omitempty"`
|
||||
}
|
||||
|
||||
type AbuseReport struct {
|
||||
ID int64
|
||||
ReportID string
|
||||
ReporterID Uid
|
||||
TargetType string
|
||||
TargetUserID Uid
|
||||
TargetTopic string
|
||||
TargetSeq int
|
||||
ReasonCode string
|
||||
Description string
|
||||
EvidenceFileIDs []string
|
||||
Snapshot map[string]any
|
||||
Status string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type FeedbackConfig struct {
|
||||
Categories []string
|
||||
MaxLength int
|
||||
AttachmentPolicy map[string]any
|
||||
AllowContact bool
|
||||
DiagnosticsNotice string
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type FeedbackSubmission struct {
|
||||
ID int64
|
||||
FeedbackID string
|
||||
UserID Uid
|
||||
Category string
|
||||
Content string
|
||||
Contact string
|
||||
AttachmentFileIDs []string
|
||||
ClientContext map[string]any
|
||||
IncludeDiagnostics bool
|
||||
Status string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
Reference in New Issue
Block a user