feat: moderation
This commit is contained in:
@@ -11,6 +11,8 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class MealPosts extends Model
|
||||
@@ -31,6 +33,9 @@ class MealPosts extends Model
|
||||
'type',
|
||||
'ai_generated',
|
||||
'diet_type',
|
||||
'hidden_at',
|
||||
'hidden_by',
|
||||
'hidden_reason',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
@@ -60,6 +65,26 @@ class MealPosts extends Model
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function reports(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Report::class, 'reportable');
|
||||
}
|
||||
|
||||
public function moderationCase(): MorphOne
|
||||
{
|
||||
return $this->morphOne(ModerationCase::class, 'caseable');
|
||||
}
|
||||
|
||||
public function hiddenBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'hidden_by');
|
||||
}
|
||||
|
||||
public function isHidden(): bool
|
||||
{
|
||||
return $this->hidden_at !== null;
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
@@ -68,6 +93,7 @@ class MealPosts extends Model
|
||||
'type' => MealPostType::class,
|
||||
'diet_type' => DietType::class,
|
||||
'ai_generated' => 'boolean',
|
||||
'hidden_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\ModerationCaseStatus;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
class ModerationCase extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\ModerationCaseFactory> */
|
||||
use HasFactory, HasUlids;
|
||||
|
||||
protected $fillable = [
|
||||
'caseable_type',
|
||||
'caseable_id',
|
||||
'status',
|
||||
'reports_count',
|
||||
'threshold',
|
||||
'threshold_notified_at',
|
||||
'assigned_to',
|
||||
'resolved_by',
|
||||
'resolved_at',
|
||||
'resolution_note',
|
||||
];
|
||||
|
||||
public function caseable(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function reports(): HasMany
|
||||
{
|
||||
return $this->hasMany(Report::class);
|
||||
}
|
||||
|
||||
public function assignedTo(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'assigned_to');
|
||||
}
|
||||
|
||||
public function resolvedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'resolved_by');
|
||||
}
|
||||
|
||||
public function targetType(): string
|
||||
{
|
||||
return match ($this->caseable_type) {
|
||||
MealPosts::class => 'meal_post',
|
||||
User::class => 'user',
|
||||
default => 'unknown',
|
||||
};
|
||||
}
|
||||
|
||||
public function targetLabel(): string
|
||||
{
|
||||
return match ($this->caseable_type) {
|
||||
MealPosts::class => __('admin.moderation_cases.targets.meal_post'),
|
||||
User::class => __('admin.moderation_cases.targets.user'),
|
||||
default => __('admin.moderation_cases.targets.unknown'),
|
||||
};
|
||||
}
|
||||
|
||||
public function targetTitle(): string
|
||||
{
|
||||
$target = $this->caseable;
|
||||
|
||||
return match (true) {
|
||||
$target instanceof MealPosts => $target->title,
|
||||
$target instanceof User => $target->name,
|
||||
default => (string) $this->caseable_id,
|
||||
};
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'status' => ModerationCaseStatus::class,
|
||||
'reports_count' => 'integer',
|
||||
'threshold' => 'integer',
|
||||
'threshold_notified_at' => 'datetime',
|
||||
'resolved_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\ReportReason;
|
||||
use App\Enums\ReportStatus;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
class Report extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\ReportFactory> */
|
||||
use HasFactory, HasUlids;
|
||||
|
||||
protected $fillable = [
|
||||
'moderation_case_id',
|
||||
'reporter_id',
|
||||
'reportable_type',
|
||||
'reportable_id',
|
||||
'reason',
|
||||
'details',
|
||||
'status',
|
||||
'reviewed_by',
|
||||
'reviewed_at',
|
||||
];
|
||||
|
||||
public function moderationCase(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ModerationCase::class);
|
||||
}
|
||||
|
||||
public function reporter(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'reporter_id');
|
||||
}
|
||||
|
||||
public function reviewedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'reviewed_by');
|
||||
}
|
||||
|
||||
public function reportable(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'reason' => ReportReason::class,
|
||||
'status' => ReportStatus::class,
|
||||
'reviewed_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,11 @@ use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Contracts\Translation\HasLocalePreference;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@@ -50,6 +53,9 @@ class User extends Authenticatable implements FilamentUser, HasLocalePreference,
|
||||
'pace_preference',
|
||||
'sex',
|
||||
'date_of_birth',
|
||||
'suspended_at',
|
||||
'suspended_by',
|
||||
'suspended_reason',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -83,6 +89,7 @@ class User extends Authenticatable implements FilamentUser, HasLocalePreference,
|
||||
'sex' => UserSex::class,
|
||||
'role' => UserRole::class,
|
||||
'date_of_birth' => 'immutable_date',
|
||||
'suspended_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -106,6 +113,41 @@ class User extends Authenticatable implements FilamentUser, HasLocalePreference,
|
||||
return $this->hasOne(StravaConnection::class);
|
||||
}
|
||||
|
||||
public function reportsMade(): HasMany
|
||||
{
|
||||
return $this->hasMany(Report::class, 'reporter_id');
|
||||
}
|
||||
|
||||
public function receivedReports(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Report::class, 'reportable');
|
||||
}
|
||||
|
||||
public function moderationCase(): MorphOne
|
||||
{
|
||||
return $this->morphOne(ModerationCase::class, 'caseable');
|
||||
}
|
||||
|
||||
public function assignedModerationCases(): HasMany
|
||||
{
|
||||
return $this->hasMany(ModerationCase::class, 'assigned_to');
|
||||
}
|
||||
|
||||
public function resolvedModerationCases(): HasMany
|
||||
{
|
||||
return $this->hasMany(ModerationCase::class, 'resolved_by');
|
||||
}
|
||||
|
||||
public function suspendedBy(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(self::class, 'suspended_by');
|
||||
}
|
||||
|
||||
public function isSuspended(): bool
|
||||
{
|
||||
return $this->suspended_at !== null;
|
||||
}
|
||||
|
||||
public function routeNotificationForExpoPush(): array
|
||||
{
|
||||
return $this->deviceTokens()
|
||||
|
||||
Reference in New Issue
Block a user