You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
2.7 KiB

<?php
namespace App\Services\CompanyNews;
use App\Models\CompanyNews;
use HTMLPurifier;
use HTMLPurifier_Config;
use Illuminate\Support\Facades\DB;
use RuntimeException;
class NewsEditor
{
public function save(int $id, int $version, array $input, ?int $actor): CompanyNews
{
return DB::transaction(function () use ($id, $version, $input, $actor) {
$news = $this->locked($id, $version);
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.DefinitionImpl', null);
$config->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true]);
$html = (new HTMLPurifier($config))->purify($input['content_html'] ?? '');
$news->fill([
'title' => $input['title'], 'summary' => $input['summary'] ?? null,
'content_html' => $html, 'content_source' => 'manual',
'content_updated_by' => $actor, 'content_updated_at' => now(),
'is_visible' => false, 'visible_at' => null, 'version' => $version + 1,
])->save();
$this->log($news, $actor, 'edit', ['version' => $news->version, 'content_hash' => hash('sha256', $html)]);
return $news;
});
}
public function review(int $id, int $version, string $status, ?string $note, ?int $actor): CompanyNews
{
return DB::transaction(function () use ($id, $version, $status, $note, $actor) {
$news = $this->locked($id, $version);
$from = $news->review_status;
$news->fill([
'review_status' => $status, 'review_note' => $note,
'reviewed_by' => $actor, 'reviewed_at' => now(),
'is_visible' => false, 'visible_at' => null, 'version' => $version + 1,
])->save();
$this->log($news, $actor, 'review', ['from' => $from, 'to' => $status, 'note' => $note]);
return $news;
});
}
private function locked(int $id, int $version): CompanyNews
{
$news = CompanyNews::whereKey($id)->lockForUpdate()->first();
if (!$news) {
throw new RuntimeException('新闻不存在');
}
if ($news->version !== $version) {
throw new RuntimeException('新闻已被其他管理员修改,请重新打开后操作');
}
return $news;
}
private function log(CompanyNews $news, ?int $actor, string $action, array $detail): void
{
DB::table('company_news_logs')->insert([
'news_id' => $news->id, 'actor_id' => $actor, 'action' => $action,
'detail' => json_encode($detail, JSON_UNESCAPED_UNICODE), 'created_at' => now(),
]);
}
}