hyperf-chat/app/Controller/Api/V1/ArticleController.php

554 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Controller\Api\V1;
use App\Helpers\DateHelper;
use App\Helpers\StringHelper;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\JWTAuthMiddleware;
use App\Service\ArticleService;
use League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
use App\Cache\Repository\LockRedis;
/**
* Class ArticleController
* @Controller(prefix="/api/v1/article")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
*/
class ArticleController extends CController
{
/**
* @Inject
* @var ArticleService
*/
private $articleService;
/**
* 获取笔记分类列表
*
* @RequestMapping(path="classifys", methods="get")
*/
public function getArticleClass(): ResponseInterface
{
$rows = $this->articleService->getUserClass($this->uid());
foreach ($rows as &$row) {
$row['count'] = is_null($row['count']) ? 0 : $row['count'];
}
return $this->response->success(['rows' => $rows]);
}
/**
* 获取笔记标签列表
*
* @RequestMapping(path="tags", methods="get")
*/
public function getArticleTags(): ResponseInterface
{
return $this->response->success([
'tags' => $this->articleService->getUserTags($this->uid())
]);
}
/**
* 获取笔记列表
*
* @RequestMapping(path="search", methods="get")
*/
public function getArticleList(): ResponseInterface
{
$params1 = $this->request->inputs(['keyword', 'find_type', 'cid', 'page']);
$this->validate($params1, [
// 搜索关键词
'keyword' => "present",
// 查询类型 $findType 1:获取近期日记 2:获取星标日记 3:获取指定分类文章 4:获取指定标签文章 5:获取已删除文章 6:关键词搜索
'find_type' => 'required|in:0,1,2,3,4,5,6',
// 分类ID
'cid' => 'present|integer|min:-1',
'page' => 'present|integer|min:1'
]);
$params = [];
$params['find_type'] = $params1['find_type'];
if (in_array($params1['find_type'], [3, 4])) {
$params['class_id'] = $params1['cid'];
}
if (!empty($params1['keyword'])) {
$params['keyword'] = $params1['keyword'];
}
return $this->response->success(
$this->articleService->getUserArticleList($this->uid(), 1, 10000, $params)
);
}
/**
* 获取笔记详情
*
* @RequestMapping(path="detail", methods="get")
*/
public function getArticleDetail(): ResponseInterface
{
$params = $this->request->inputs(['article_id']);
$this->validate($params, [
'article_id' => 'required|integer'
]);
return $this->response->success(
$this->articleService->getArticleDetail((int)$params['article_id'], $this->uid())
);
}
/**
* 添加或编辑笔记分类
*
* @RequestMapping(path="classify/editor", methods="post")
*/
public function editArticleClass(): ResponseInterface
{
$params = $this->request->inputs(['class_id', 'class_name']);
$this->validate($params, [
'class_id' => 'required|integer',
'class_name' => 'required|max:20'
]);
$class_id = $this->articleService->editArticleClass($this->uid(), $params['class_id'], $params['class_name']);
if (!$class_id) {
return $this->response->fail('笔记分类编辑失败!');
}
return $this->response->success(['id' => $class_id]);
}
/**
* 删除笔记分类
*
* @RequestMapping(path="classify/delete", methods="post")
* @return ResponseInterface
* @throws \Exception
*/
public function delArticleClass(): ResponseInterface
{
$params = $this->request->inputs(['class_id']);
$this->validate($params, [
'class_id' => 'required|integer'
]);
if (!$this->articleService->delArticleClass($this->uid(), (int)$params['class_id'])) {
return $this->response->fail('笔记分类删除失败!');
}
return $this->response->success([], '笔记分类删除成功...');
}
/**
* 笔记分类列表排序接口
*
* @RequestMapping(path="classify/sort", methods="post")
* @return ResponseInterface
* @throws \Exception
*/
public function articleClassSort(): ResponseInterface
{
$params = $this->request->inputs(['class_id', 'sort_type']);
$this->validate($params, [
'class_id' => 'required|integer',
'sort_type' => 'required|in:1,2'
]);
$lockKey = "article:sort_{$params['class_id']}_{$params['sort_type']}";
$lock = LockRedis::getInstance();
if ($lock->lock($lockKey, 3, 500)) {
$isTrue = $this->articleService->articleClassSort($this->uid(), (int)$params['class_id'], (int)$params['sort_type']);
$lock->delete($lockKey);
} else {
$isTrue = false;
}
return $isTrue
? $this->response->success([], '排序完成...')
: $this->response->fail('排序失败!');
}
/**
* 笔记分类合并接口
*
* @RequestMapping(path="classify/merge", methods="post")
*/
public function mergeArticleClass(): ResponseInterface
{
$params = $this->request->inputs(['class_id', 'toid']);
$this->validate($params, [
'class_id' => 'required|integer',
'toid' => 'required|integer'
]);
$isTrue = $this->articleService->mergeArticleClass($this->uid(), (int)$params['class_id'], (int)$params['toid']);
return $isTrue
? $this->response->success([], '合并完成...')
: $this->response->fail('合并失败!');
}
/**
* 添加或编辑笔记标签
*
* @RequestMapping(path="tag/editor", methods="post")
*/
public function editArticleTags(): ResponseInterface
{
$params = $this->request->inputs(['tag_id', 'tag_name']);
$this->validate($params, [
'tag_id' => 'required|integer|min:0',
'tag_name' => 'required|max:20'
]);
$id = $this->articleService->editArticleTag($this->uid(), (int)$params['tag_id'], $params['tag_name']);
return $id
? $this->response->success(['id' => $id])
: $this->response->fail('笔记标签编辑失败!');
}
/**
* 删除笔记标签
*
* @RequestMapping(path="del-article-tag", methods="post")
*/
public function delArticleTags(): ResponseInterface
{
$params = $this->request->inputs(['tag_id']);
$this->validate($params, [
'tag_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->delArticleTags($this->uid(), (int)$params['tag_id']);
return $isTrue
? $this->response->success([], '笔记标签删除完成...')
: $this->response->fail('笔记标签删除失败!');
}
/**
* 添加或编辑笔记
*
* @RequestMapping(path="editor", methods="post")
*/
public function editArticle(): ResponseInterface
{
$params = $this->request->all();
$this->validate($params, [
'article_id' => 'required|integer|min:0',
'class_id' => 'required|integer|min:0',
'title' => 'required|max:255',
'content' => 'required',
'md_content' => 'required'
]);
$id = $this->articleService->editArticle($this->uid(), (int)$params['article_id'], [
'title' => $params['title'],
'abstract' => mb_substr(strip_tags($params['content']), 0, 200),
'class_id' => $params['class_id'],
'image' => StringHelper::getHtmlImage($params['content']),
'md_content' => htmlspecialchars($params['md_content']),
'content' => htmlspecialchars($params['content'])
]);
return $id
? $this->response->success(['aid' => $id], '笔记编辑成功...')
: $this->response->fail('笔记编辑失败!', ['id' => null]);
}
/**
* 删除笔记
*
* @RequestMapping(path="delete", methods="post")
*/
public function deleteArticle(): ResponseInterface
{
$params = $this->request->inputs(['article_id']);
$this->validate($params, [
'article_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->updateArticleStatus($this->uid(), (int)$params['article_id'], 2);
return $isTrue
? $this->response->success([], '笔记删除成功...')
: $this->response->fail('笔记删除失败!');
}
/**
* 恢复删除笔记
*
* @RequestMapping(path="recover", methods="post")
*/
public function recoverArticle(): ResponseInterface
{
$params = $this->request->inputs(['article_id']);
$this->validate($params, [
'article_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->updateArticleStatus($this->uid(), (int)$params['article_id'], 1);
return $isTrue
? $this->response->success([], '笔记恢复成功...')
: $this->response->fail('笔记恢复失败!');
}
/**
* 笔记图片上传接口
*
* @RequestMapping(path="upload-image", methods="post")
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function uploadArticleImage(Filesystem $filesystem): ResponseInterface
{
$file = $this->request->file('image');
if (!$file || !$file->isValid()) {
return $this->response->fail();
}
$ext = $file->getExtension();
if (!in_array($ext, ['jpg', 'png', 'jpeg', 'gif', 'webp'])) {
return $this->response->fail('图片格式错误目前仅支持jpg、png、jpeg、gif和webp');
}
try {
$path = 'media/images/notes/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath()));
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
return $this->response->success([
'save_path' => get_media_url($path)
]);
}
/**
* 移动笔记至指定分类
*
* @RequestMapping(path="move", methods="post")
*/
public function moveArticle(): ResponseInterface
{
$params = $this->request->inputs(['article_id', 'class_id']);
$this->validate($params, [
'article_id' => 'required|integer|min:0',
'class_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->moveArticle(
$this->uid(),
$params['article_id'],
$params['class_id']
);
return $isTrue
? $this->response->success([], '笔记移动成功...')
: $this->response->fail('笔记移动失败!');
}
/**
* 笔记标记星号接口
*
* @RequestMapping(path="asterisk", methods="post")
*/
public function setAsterisk(): ResponseInterface
{
$params = $this->request->inputs(['article_id', 'type']);
$this->validate($params, [
'article_id' => 'required|integer|min:0',
'type' => 'required|in:1,2'
]);
$isTrue = $this->articleService->setAsteriskArticle(
$this->uid(),
(int)$params['article_id'],
(int)$params['type']
);
return $isTrue
? $this->response->success([], '笔记标记成功...')
: $this->response->fail('笔记标记失败!');
}
/**
* 更新笔记关联标签ID
*
* @RequestMapping(path="update-tag", methods="post")
*/
public function updateArticleTag(): ResponseInterface
{
$params = $this->request->inputs(['article_id', 'tags']);
$this->validate($params, [
'article_id' => 'required|integer|min:0',
'tags' => 'present|array'
]);
$isTrue = $this->articleService->updateArticleTag($this->uid(), (int)$params['article_id'], $params['tags']);
return $isTrue
? $this->response->success([], 'success...')
: $this->response->fail('编辑失败!');
}
/**
* 永久删除笔记文章
*
* @RequestMapping(path="forever-delete", methods="post")
* @return ResponseInterface
* @throws \Exception
*/
public function foreverDelArticle(): ResponseInterface
{
$params = $this->request->inputs(['article_id']);
$this->validate($params, [
'article_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->foreverDelArticle($this->uid(), (int)$params['article_id']);
return $isTrue
? $this->response->success([], '笔记删除成功...')
: $this->response->fail('笔记删除失败!');
}
/**
* 上传笔记附件
*
* @RequestMapping(path="annex/upload", methods="post")
* @param Filesystem $filesystem
* @return ResponseInterface
*/
public function uploadArticleAnnex(Filesystem $filesystem): ResponseInterface
{
$params = $this->request->inputs(['article_id']);
$this->validate($params, [
'article_id' => 'required|integer|min:0'
]);
$file = $this->request->file('annex');
if (!$file || !$file->isValid()) {
return $this->response->fail('上传文件验证失败!');
}
$annex = [
'file_suffix' => pathinfo($file->getClientFilename(), PATHINFO_EXTENSION),
'file_size' => $file->getSize(),
'save_dir' => '',
'original_name' => $file->getClientFilename()
];
try {
$path = 'files/notes/' . date('Ymd') . '/' . "[{$annex['file_suffix']}]" . create_random_filename('tmp');
$filesystem->write($path, file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
$annex['save_dir'] = $path;
$annex['id'] = $this->articleService->insertArticleAnnex($this->uid(), (int)$params['article_id'], $annex);
if (!$annex['id']) {
return $this->response->fail('附件上传失败,请稍后再试!');
}
return $this->response->success($annex, '笔记附件上传成功...');
}
/**
* 删除笔记附件
*
* @RequestMapping(path="annex/delete", methods="post")
*/
public function deleteArticleAnnex(): ResponseInterface
{
$params = $this->request->inputs(['annex_id']);
$this->validate($params, [
'annex_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->updateArticleAnnexStatus($this->uid(), (int)$params['annex_id'], 2);
return $isTrue
? $this->response->success([], '笔记附件删除成功...')
: $this->response->fail('笔记附件删除失败!');
}
/**
* 恢复笔记附件
*
* @RequestMapping(path="annex/recover", methods="post")
*/
public function recoverArticleAnnex(): ResponseInterface
{
$params = $this->request->inputs(['annex_id']);
$this->validate($params, [
'annex_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->updateArticleAnnexStatus($this->uid(), (int)$params['annex_id'], 1);
return $isTrue
? $this->response->success([], '笔记附件恢复成功...')
: $this->response->fail('笔记附件恢复失败!');
}
/**
* 获取附件回收站列表
*
* @RequestMapping(path="annex/recover-list", methods="get")
*/
public function recoverAnnexList(): ResponseInterface
{
$rows = $this->articleService->recoverAnnexList($this->uid());
if ($rows) {
$getDay = function ($delete_at) {
$last_time = strtotime('+30 days', strtotime($delete_at));
return (time() > $last_time) ? 0 : DateHelper::diff(date('Y-m-d', $last_time), date('Y-m-d'));
};
array_walk($rows, function (&$item) use ($getDay) {
$item['day'] = $getDay($item['deleted_at']);
$item['visible'] = false;
});
}
return $this->response->success(['rows' => $rows]);
}
/**
* 永久删除笔记附件(从已删除附件中永久删除)
*
* @RequestMapping(path="annex/forever-delete", methods="post")
* @return ResponseInterface
* @throws \Exception
*/
public function foreverDelAnnex(): ResponseInterface
{
$params = $this->request->inputs(['annex_id']);
$this->validate($params, [
'annex_id' => 'required|integer|min:0'
]);
$isTrue = $this->articleService->foreverDelAnnex($this->uid(), (int)$params['annex_id']);
return $isTrue
? $this->response->success([], '笔记附件删除成功...')
: $this->response->fail('笔记附件删除失败!');
}
}