118 lines
3.6 KiB
PHP
118 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\GameAccountUser;
|
|
use App\Models\LoginScreenNews;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Str;
|
|
|
|
class LoginScreenNewsService
|
|
{
|
|
public const FEED_HEADER = 'SERVERALERT:';
|
|
|
|
public const SECTION_SEPARATOR = '----------------------------------------------------------';
|
|
|
|
public const EMPTY_MESSAGE = '|cFFB7C1CFСкоро здесь появятся новости сервера.|r';
|
|
|
|
/**
|
|
* @return \Illuminate\Support\Collection<int, \App\Models\LoginScreenNews>
|
|
*/
|
|
public function listForAdmin(): Collection
|
|
{
|
|
return LoginScreenNews::query()
|
|
->ordered()
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* @return array{total: int, published: int, draft: int}
|
|
*/
|
|
public function stats(): array
|
|
{
|
|
$total = LoginScreenNews::query()->count();
|
|
$published = LoginScreenNews::query()->published()->count();
|
|
|
|
return [
|
|
'total' => $total,
|
|
'published' => $published,
|
|
'draft' => $total - $published,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array{title: string, body: string, sort_order: int, is_published?: bool} $attributes
|
|
*/
|
|
public function create(array $attributes, ?GameAccountUser $actor): LoginScreenNews
|
|
{
|
|
return LoginScreenNews::query()->create([
|
|
...$this->normalizeAttributes($attributes),
|
|
'created_by_account_id' => $actor?->id,
|
|
'created_by_username' => $actor?->username,
|
|
'updated_by_account_id' => $actor?->id,
|
|
'updated_by_username' => $actor?->username,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @param array{title: string, body: string, sort_order: int, is_published?: bool} $attributes
|
|
*/
|
|
public function update(LoginScreenNews $newsItem, array $attributes, ?GameAccountUser $actor): LoginScreenNews
|
|
{
|
|
$newsItem->forceFill([
|
|
...$this->normalizeAttributes($attributes),
|
|
'updated_by_account_id' => $actor?->id,
|
|
'updated_by_username' => $actor?->username,
|
|
])->save();
|
|
|
|
return $newsItem->refresh();
|
|
}
|
|
|
|
public function delete(LoginScreenNews $newsItem): void
|
|
{
|
|
$newsItem->delete();
|
|
}
|
|
|
|
public function renderFeed(): string
|
|
{
|
|
$sections = LoginScreenNews::query()
|
|
->published()
|
|
->ordered()
|
|
->pluck('body')
|
|
->map(fn (mixed $body): string => $this->normalizeBody((string) $body))
|
|
->filter(fn (string $body): bool => $body !== '')
|
|
->values();
|
|
|
|
$payload = $sections->isNotEmpty()
|
|
? $sections->implode("\n".self::SECTION_SEPARATOR."\n")
|
|
: self::EMPTY_MESSAGE;
|
|
|
|
return self::FEED_HEADER."\n\n".$payload."\n";
|
|
}
|
|
|
|
/**
|
|
* @param array{title: string, body: string, sort_order: int, is_published?: bool} $attributes
|
|
* @return array{title: string, body: string, sort_order: int, is_published: bool}
|
|
*/
|
|
private function normalizeAttributes(array $attributes): array
|
|
{
|
|
return [
|
|
'title' => trim($attributes['title']),
|
|
'body' => $this->normalizeBody($attributes['body']),
|
|
'sort_order' => (int) $attributes['sort_order'],
|
|
'is_published' => (bool) ($attributes['is_published'] ?? false),
|
|
];
|
|
}
|
|
|
|
private function normalizeBody(string $body): string
|
|
{
|
|
$normalized = trim(str_replace(["\r\n", "\r"], "\n", $body));
|
|
|
|
if (Str::startsWith($normalized, self::FEED_HEADER)) {
|
|
$normalized = trim(Str::after($normalized, self::FEED_HEADER));
|
|
}
|
|
|
|
return $normalized;
|
|
}
|
|
}
|