Files
SkinbaseNova/app/Services/Moderation/ContentModerationSourceService.php

352 lines
16 KiB
PHP

<?php
namespace App\Services\Moderation;
use App\Enums\ModerationContentType;
use App\Models\Collection;
use App\Models\NovaCard;
use App\Models\Story;
use App\Models\Artwork;
use App\Models\ArtworkComment;
use App\Models\ContentModerationFinding;
use App\Models\UserProfile;
use App\Models\UserSocialLink;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
class ContentModerationSourceService
{
public function queryForType(ModerationContentType $type): EloquentBuilder
{
return match ($type) {
ModerationContentType::ArtworkComment => ArtworkComment::query()
->with('artwork:id,title,slug,user_id')
->whereNull('deleted_at')
->where(function (EloquentBuilder $query): void {
$query->whereNotNull('raw_content')->where('raw_content', '!=', '')
->orWhere(function (EloquentBuilder $fallback): void {
$fallback->whereNotNull('content')->where('content', '!=', '');
});
})
->orderBy('id'),
ModerationContentType::ArtworkDescription => Artwork::query()
->whereNotNull('description')
->where('description', '!=', '')
->orderBy('id'),
ModerationContentType::ArtworkTitle => Artwork::query()
->whereNotNull('title')
->where('title', '!=', '')
->orderBy('id'),
ModerationContentType::UserBio => UserProfile::query()
->with('user:id,username,name')
->where(function (EloquentBuilder $query): void {
$query->whereNotNull('about')->where('about', '!=', '')
->orWhere(function (EloquentBuilder $fallback): void {
$fallback->whereNotNull('description')->where('description', '!=', '');
});
})
->orderBy('user_id'),
ModerationContentType::UserProfileLink => UserSocialLink::query()
->with('user:id,username,name')
->whereNotNull('url')
->where('url', '!=', '')
->orderBy('id'),
ModerationContentType::CollectionTitle => Collection::query()
->with('user:id,username,name')
->whereNotNull('title')
->where('title', '!=', '')
->orderBy('id'),
ModerationContentType::CollectionDescription => Collection::query()
->with('user:id,username,name')
->whereNotNull('description')
->where('description', '!=', '')
->orderBy('id'),
ModerationContentType::StoryTitle => Story::query()
->with('creator:id,username,name')
->whereNotNull('title')
->where('title', '!=', '')
->orderBy('id'),
ModerationContentType::StoryContent => Story::query()
->with('creator:id,username,name')
->whereNotNull('content')
->where('content', '!=', '')
->orderBy('id'),
ModerationContentType::CardTitle => NovaCard::query()
->with('user:id,username,name')
->whereNotNull('title')
->where('title', '!=', '')
->orderBy('id'),
ModerationContentType::CardText => NovaCard::query()
->with('user:id,username,name')
->where(function (EloquentBuilder $query): void {
$query->whereNotNull('quote_text')->where('quote_text', '!=', '')
->orWhere(function (EloquentBuilder $description): void {
$description->whereNotNull('description')->where('description', '!=', '');
});
})
->orderBy('id'),
default => throw new \InvalidArgumentException('Unsupported moderation content type: ' . $type->value),
};
}
/**
* @param Artwork|ArtworkComment|Collection|Story|NovaCard|UserProfile|UserSocialLink $row
* @return array<string, mixed>
*/
public function buildContext(ModerationContentType $type, object $row): array
{
return match ($type) {
ModerationContentType::ArtworkComment => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'artwork_comment',
'content_target_id' => (int) $row->id,
'artwork_id' => (int) $row->artwork_id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => (string) ($row->raw_content ?: $row->content),
'is_publicly_exposed' => true,
],
ModerationContentType::ArtworkDescription => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'artwork',
'content_target_id' => (int) $row->id,
'artwork_id' => (int) $row->id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => (string) ($row->description ?? ''),
'is_publicly_exposed' => (bool) ($row->is_public ?? false),
],
ModerationContentType::ArtworkTitle => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'artwork',
'content_target_id' => (int) $row->id,
'artwork_id' => (int) $row->id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => (string) ($row->title ?? ''),
'is_publicly_exposed' => (bool) ($row->is_public ?? false),
],
ModerationContentType::UserBio => [
'content_type' => $type->value,
'content_id' => (int) $row->user_id,
'content_target_type' => 'user_profile',
'content_target_id' => (int) $row->user_id,
'user_id' => (int) $row->user_id,
'content_snapshot' => trim((string) ($row->about ?: $row->description ?: '')),
'is_publicly_exposed' => true,
],
ModerationContentType::UserProfileLink => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'user_social_link',
'content_target_id' => (int) $row->id,
'user_id' => (int) $row->user_id,
'content_snapshot' => trim((string) ($row->url ?? '')),
'is_publicly_exposed' => true,
],
ModerationContentType::CollectionTitle => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'collection',
'content_target_id' => (int) $row->id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => (string) ($row->title ?? ''),
'is_publicly_exposed' => in_array((string) ($row->visibility ?? ''), ['public', 'unlisted'], true),
],
ModerationContentType::CollectionDescription => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'collection',
'content_target_id' => (int) $row->id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => (string) ($row->description ?? ''),
'is_publicly_exposed' => in_array((string) ($row->visibility ?? ''), ['public', 'unlisted'], true),
],
ModerationContentType::StoryTitle => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'story',
'content_target_id' => (int) $row->id,
'user_id' => $row->creator_id ? (int) $row->creator_id : null,
'content_snapshot' => (string) ($row->title ?? ''),
'is_publicly_exposed' => in_array((string) ($row->status ?? ''), ['published', 'scheduled'], true),
],
ModerationContentType::StoryContent => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'story',
'content_target_id' => (int) $row->id,
'user_id' => $row->creator_id ? (int) $row->creator_id : null,
'content_snapshot' => (string) ($row->content ?? ''),
'is_publicly_exposed' => in_array((string) ($row->status ?? ''), ['published', 'scheduled'], true),
],
ModerationContentType::CardTitle => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'nova_card',
'content_target_id' => (int) $row->id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => (string) ($row->title ?? ''),
'is_publicly_exposed' => in_array((string) ($row->visibility ?? ''), ['public', 'unlisted'], true),
],
ModerationContentType::CardText => [
'content_type' => $type->value,
'content_id' => (int) $row->id,
'content_target_type' => 'nova_card',
'content_target_id' => (int) $row->id,
'user_id' => $row->user_id ? (int) $row->user_id : null,
'content_snapshot' => trim(implode("\n", array_filter([
(string) ($row->quote_text ?? ''),
(string) ($row->description ?? ''),
(string) ($row->quote_author ?? ''),
(string) ($row->quote_source ?? ''),
]))),
'is_publicly_exposed' => in_array((string) ($row->visibility ?? ''), ['public', 'unlisted'], true),
],
default => throw new \InvalidArgumentException('Unsupported moderation content type: ' . $type->value),
};
}
/**
* @return array{context:array<string, mixed>|null, type:ModerationContentType|null}
*/
public function contextForFinding(ContentModerationFinding $finding): array
{
return match ($finding->content_type) {
ModerationContentType::ArtworkComment => $this->commentContextForFinding($finding),
ModerationContentType::ArtworkDescription => $this->descriptionContextForFinding($finding),
ModerationContentType::ArtworkTitle => $this->artworkTitleContextForFinding($finding),
ModerationContentType::UserBio => $this->userBioContextForFinding($finding),
ModerationContentType::UserProfileLink => $this->userProfileLinkContextForFinding($finding),
ModerationContentType::CollectionTitle => $this->collectionTitleContextForFinding($finding),
ModerationContentType::CollectionDescription => $this->collectionDescriptionContextForFinding($finding),
ModerationContentType::StoryTitle => $this->storyTitleContextForFinding($finding),
ModerationContentType::StoryContent => $this->storyContentContextForFinding($finding),
ModerationContentType::CardTitle => $this->cardTitleContextForFinding($finding),
ModerationContentType::CardText => $this->cardTextContextForFinding($finding),
default => ['context' => null, 'type' => null],
};
}
/**
* @return array{context:array<string, mixed>|null, type:ModerationContentType|null}
*/
private function commentContextForFinding(ContentModerationFinding $finding): array
{
$comment = ArtworkComment::query()->find($finding->content_id);
if (! $comment) {
return ['context' => null, 'type' => null];
}
return [
'context' => $this->buildContext(ModerationContentType::ArtworkComment, $comment),
'type' => ModerationContentType::ArtworkComment,
];
}
/**
* @return array{context:array<string, mixed>|null, type:ModerationContentType|null}
*/
private function descriptionContextForFinding(ContentModerationFinding $finding): array
{
$artworkId = (int) ($finding->artwork_id ?? $finding->content_id);
$artwork = Artwork::query()->find($artworkId);
if (! $artwork) {
return ['context' => null, 'type' => null];
}
return [
'context' => $this->buildContext(ModerationContentType::ArtworkDescription, $artwork),
'type' => ModerationContentType::ArtworkDescription,
];
}
private function artworkTitleContextForFinding(ContentModerationFinding $finding): array
{
$artwork = Artwork::query()->find((int) ($finding->artwork_id ?? $finding->content_id));
if (! $artwork) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::ArtworkTitle, $artwork), 'type' => ModerationContentType::ArtworkTitle];
}
private function userBioContextForFinding(ContentModerationFinding $finding): array
{
$profile = UserProfile::query()->find($finding->content_id);
if (! $profile) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::UserBio, $profile), 'type' => ModerationContentType::UserBio];
}
private function userProfileLinkContextForFinding(ContentModerationFinding $finding): array
{
$link = UserSocialLink::query()->find($finding->content_id);
if (! $link) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::UserProfileLink, $link), 'type' => ModerationContentType::UserProfileLink];
}
private function collectionTitleContextForFinding(ContentModerationFinding $finding): array
{
$collection = Collection::query()->find($finding->content_id);
if (! $collection) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::CollectionTitle, $collection), 'type' => ModerationContentType::CollectionTitle];
}
private function collectionDescriptionContextForFinding(ContentModerationFinding $finding): array
{
$collection = Collection::query()->find($finding->content_id);
if (! $collection) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::CollectionDescription, $collection), 'type' => ModerationContentType::CollectionDescription];
}
private function storyTitleContextForFinding(ContentModerationFinding $finding): array
{
$story = Story::query()->find($finding->content_id);
if (! $story) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::StoryTitle, $story), 'type' => ModerationContentType::StoryTitle];
}
private function storyContentContextForFinding(ContentModerationFinding $finding): array
{
$story = Story::query()->find($finding->content_id);
if (! $story) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::StoryContent, $story), 'type' => ModerationContentType::StoryContent];
}
private function cardTitleContextForFinding(ContentModerationFinding $finding): array
{
$card = NovaCard::query()->find($finding->content_id);
if (! $card) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::CardTitle, $card), 'type' => ModerationContentType::CardTitle];
}
private function cardTextContextForFinding(ContentModerationFinding $finding): array
{
$card = NovaCard::query()->find($finding->content_id);
if (! $card) {
return ['context' => null, 'type' => null];
}
return ['context' => $this->buildContext(ModerationContentType::CardText, $card), 'type' => ModerationContentType::CardText];
}
}