让分类、会员和示例工具共用同一账号,本地即可跑通登录与授权。 Co-authored-by: Cursor <cursoragent@cursor.com>
167 lines
5.4 KiB
PHP
167 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Agreement;
|
|
use App\Models\Article;
|
|
use App\Models\Banner;
|
|
use App\Models\Navigation;
|
|
use App\Support\HtmlSanitizer;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class ContentController extends Controller
|
|
{
|
|
public function articles()
|
|
{
|
|
return $this->ok(Article::query()->latest('id')->limit(100)->get());
|
|
}
|
|
|
|
public function storeArticle(Request $request)
|
|
{
|
|
$article = Article::query()->create($this->articleData($request));
|
|
$this->audit($request->user(), 'article.create', $article, '新建文章 '.$article->title);
|
|
|
|
return $this->ok($article);
|
|
}
|
|
|
|
public function updateArticle(Request $request, Article $article)
|
|
{
|
|
$data = $this->articleData($request, $article->id);
|
|
if ($data['status'] === 'published' && ! $article->published_at) {
|
|
$data['published_at'] = now();
|
|
}
|
|
$article->update($data);
|
|
$this->audit($request->user(), 'article.update', $article, '更新文章 '.$article->title);
|
|
|
|
return $this->ok($article);
|
|
}
|
|
|
|
public function destroyArticle(Request $request, Article $article)
|
|
{
|
|
$article->delete();
|
|
$this->audit($request->user(), 'article.delete', $article, '删除文章 '.$article->title);
|
|
|
|
return $this->ok(null, '已删除');
|
|
}
|
|
|
|
public function banners()
|
|
{
|
|
return $this->ok(Banner::query()->orderByDesc('sort')->get());
|
|
}
|
|
|
|
public function storeBanner(Request $request)
|
|
{
|
|
$banner = Banner::query()->create($this->bannerData($request));
|
|
$this->audit($request->user(), 'banner.create', $banner, '新建轮播 '.$banner->title);
|
|
|
|
return $this->ok($banner);
|
|
}
|
|
|
|
public function updateBanner(Request $request, Banner $banner)
|
|
{
|
|
$banner->update($this->bannerData($request));
|
|
$this->audit($request->user(), 'banner.update', $banner, '更新轮播 '.$banner->title);
|
|
|
|
return $this->ok($banner);
|
|
}
|
|
|
|
public function destroyBanner(Request $request, Banner $banner)
|
|
{
|
|
$banner->delete();
|
|
$this->audit($request->user(), 'banner.delete', $banner, '删除轮播 '.$banner->title);
|
|
|
|
return $this->ok(null, '已删除');
|
|
}
|
|
|
|
public function navigations()
|
|
{
|
|
return $this->ok(Navigation::query()->orderBy('group_name')->orderByDesc('sort')->get());
|
|
}
|
|
|
|
public function storeNavigation(Request $request)
|
|
{
|
|
$item = Navigation::query()->create($this->navData($request));
|
|
$this->audit($request->user(), 'nav.create', $item, '新建导航 '.$item->title);
|
|
|
|
return $this->ok($item);
|
|
}
|
|
|
|
public function updateNavigation(Request $request, Navigation $navigation)
|
|
{
|
|
$navigation->update($this->navData($request));
|
|
$this->audit($request->user(), 'nav.update', $navigation, '更新导航 '.$navigation->title);
|
|
|
|
return $this->ok($navigation);
|
|
}
|
|
|
|
public function destroyNavigation(Request $request, Navigation $navigation)
|
|
{
|
|
$navigation->delete();
|
|
$this->audit($request->user(), 'nav.delete', $navigation, '删除导航 '.$navigation->title);
|
|
|
|
return $this->ok(null, '已删除');
|
|
}
|
|
|
|
public function agreements()
|
|
{
|
|
return $this->ok(Agreement::query()->orderBy('type')->get());
|
|
}
|
|
|
|
public function updateAgreement(Request $request, Agreement $agreement)
|
|
{
|
|
$data = $request->validate([
|
|
'title' => ['required', 'string', 'max:120'],
|
|
'body' => ['required', 'string'],
|
|
]);
|
|
$data['body'] = HtmlSanitizer::clean($data['body']);
|
|
$agreement->update($data);
|
|
$this->audit($request->user(), 'agreement.update', $agreement, '更新协议 '.$agreement->title);
|
|
|
|
return $this->ok($agreement);
|
|
}
|
|
|
|
private function articleData(Request $request, ?int $id = null): array
|
|
{
|
|
$data = $request->validate([
|
|
'type' => ['required', 'in:help,announcement,page'],
|
|
'title' => ['required', 'string', 'max:160'],
|
|
'slug' => ['required', 'regex:/^[a-z0-9]+(?:-[a-z0-9]+)*$/', Rule::unique('articles', 'slug')->ignore($id)],
|
|
'summary' => ['nullable', 'string', 'max:255'],
|
|
'body' => ['required', 'string'],
|
|
'status' => ['required', 'in:draft,published'],
|
|
]);
|
|
$data['body'] = HtmlSanitizer::clean($data['body']);
|
|
if ($data['status'] === 'published') {
|
|
$data['published_at'] = now();
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function bannerData(Request $request): array
|
|
{
|
|
return $request->validate([
|
|
'title' => ['required', 'string', 'max:120'],
|
|
'image' => ['nullable', 'string', 'max:500'],
|
|
'link' => ['nullable', 'string', 'max:500'],
|
|
'sort' => ['nullable', 'integer'],
|
|
'starts_at' => ['nullable', 'date'],
|
|
'ends_at' => ['nullable', 'date'],
|
|
'status' => ['required', 'in:published,hidden'],
|
|
]);
|
|
}
|
|
|
|
private function navData(Request $request): array
|
|
{
|
|
return $request->validate([
|
|
'group_name' => ['required', 'in:header,footer'],
|
|
'title' => ['required', 'string', 'max:80'],
|
|
'link' => ['required', 'string', 'max:500'],
|
|
'sort' => ['nullable', 'integer'],
|
|
'status' => ['required', 'in:published,hidden'],
|
|
]);
|
|
}
|
|
}
|