feat:兼容开发

main
gzydong 2022-01-16 10:29:16 +08:00
parent b6d28d6091
commit 5b45941c58
36 changed files with 1217 additions and 901 deletions

View File

@ -3,7 +3,7 @@
namespace App\Cache;
use App\Cache\Repository\HashRedis;
use App\Model\UsersFriend;
use App\Model\Contact;
/**
* 好友备注 - 缓存助手
@ -55,7 +55,7 @@ class FriendRemark extends HashRedis
*/
public function reload()
{
UsersFriend::select(['id', 'user_id', 'friend_id', 'remark'])->chunk(200, function ($rows) {
Contact::select(['id', 'user_id', 'friend_id', 'remark'])->chunk(200, function ($rows) {
foreach ($rows as $row) {
$row->remark && $this->save($row->user_id, $row->friend_id, $row->remark);
}

View File

@ -5,7 +5,7 @@ namespace App\Command;
use App\Cache\IpAddressCache;
use App\Constants\RobotConstant;
use App\Model\UsersFriend;
use App\Model\Contact;
use App\Repository\ExampleRepository;
use App\Repository\RobotRepository;
use App\Service\RobotService;
@ -55,8 +55,8 @@ class TestCommand extends HyperfCommand
// 更新好友表数据
public function updateData()
{
$max = UsersFriend::max('id');
UsersFriend::where('id', '<=', $max)->chunk(1000, function ($rows) {
$max = Contact::max('id');
Contact::where('id', '<=', $max)->chunk(1000, function ($rows) {
$arr = [];
foreach ($rows as $row) {
$arr[] = [
@ -69,7 +69,7 @@ class TestCommand extends HyperfCommand
];
}
UsersFriend::insert($arr);
Contact::insert($arr);
});
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace App\Constants;
class FileDriveConstant
{
const Local = 1; // 本地系统
const Cos = 2; // Cos 存储
}

View File

@ -0,0 +1,196 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Article;
use App\Constants\FileDriveConstant;
use App\Controller\Api\V1\CController;
use App\Helpers\DateHelper;
use App\Model\Article\ArticleAnnex;
use App\Service\ArticleService;
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 League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
/**
* Class AnnexController
*
* @Controller(prefix="/api/v1/note/annex")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1\Article
*/
class AnnexController extends CController
{
/**
* @Inject
* @var ArticleService
*/
private $articleService;
/**
* 上传附件
*
* @RequestMapping(path="upload", methods="post")
*/
public function upload(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 = [
'suffix' => pathinfo($file->getClientFilename(), PATHINFO_EXTENSION),
'size' => $file->getSize(),
'path' => '',
'drive' => FileDriveConstant::Local,
'original_name' => $file->getClientFilename()
];
$annex['path'] = 'private/files/notes/' . date('Ymd') . '/' . "[{$annex['suffix']}]" . create_random_filename('tmp');
try {
$filesystem->write($annex['path'], file_get_contents($file->getRealPath()));
} catch (\Exception $e) {
return $this->response->fail();
}
$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="delete", methods="post")
*/
public function delete(): 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="recover", methods="post")
*/
public function recover(): 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="recover/list", methods="get")
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function recoverList(): 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="forever/delete", methods="post")
*
* @return \Psr\Http\Message\ResponseInterface
* @throws \Exception
*/
public function foreverDelete(): 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();
}
/**
* 下载附件
*
* @RequestMapping(path="download", methods="get")
*/
public function download(\Hyperf\HttpServer\Contract\ResponseInterface $response, Filesystem $filesystem)
{
$params = $this->request->inputs(['annex_id']);
$this->validate($params, [
'annex_id' => 'required|integer'
]);
/** @var ArticleAnnex $info */
$info = ArticleAnnex::select(['path', 'original_name'])->where('id', $params['annex_id'])->where('user_id', $this->uid())->first();
if (!$info || !$filesystem->has($info->path)) {
return $this->response->fail('文件不存在或没有下载权限!');
}
switch ($info->drive) {
case FileDriveConstant::Local:
return $response->download($this->getFilePath($info->path), $info->original_name);
case FileDriveConstant::Cos:
// 后期添加
break;
default:
break;
}
}
private function getFilePath(string $path)
{
return di()->get(Filesystem::class)->getConfig()->get('root') . '/' . $path;
}
}

View File

@ -0,0 +1,275 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Article;
use App\Controller\Api\V1\CController;
use App\Helpers\StringHelper;
use App\Service\ArticleService;
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 League\Flysystem\Filesystem;
use Psr\Http\Message\ResponseInterface;
/**
* Class ArticleController
* @Controller(prefix="/api/v1/note/article")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
*/
class ArticleController extends CController
{
/**
* @Inject
* @var ArticleService
*/
private $articleService;
/**
* 获取笔记列表
*
* @RequestMapping(path="list", 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 detail(): 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="editor", methods="post")
*/
public function editor(): 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();
}
/**
* 删除笔记
*
* @RequestMapping(path="delete", methods="post")
*/
public function delete(): 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 recover(): 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 upload(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 = 'public/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(['url' => get_media_url($path)]);
}
/**
* 移动笔记至指定分类
*
* @RequestMapping(path="move", methods="post")
*/
public function move(): 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 asterisk(): 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="tag", methods="post")
*/
public function tag(): 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() : $this->response->fail();
}
/**
* 永久删除笔记文章
*
* @RequestMapping(path="forever/delete", methods="post")
* @return ResponseInterface
* @throws \Exception
*/
public function foreverDelete(): 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="merge", methods="post")
*/
public function merge(): 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();
}
}

View File

@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Article;
use App\Cache\Repository\LockRedis;
use App\Controller\Api\V1\CController;
use App\Service\ArticleService;
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 Psr\Http\Message\ResponseInterface;
/**
* Class ClassController
*
* @Controller(prefix="/api/v1/note/class")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1\Article
*/
class ClassController extends CController
{
/**
* @Inject
* @var ArticleService
*/
private $articleService;
/**
* 获取笔记分类列表
*
* @RequestMapping(path="list", methods="get")
*/
public function list(): 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="editor", methods="post")
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function editor(): 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="delete", methods="post")
*
* @return \Psr\Http\Message\ResponseInterface
* @throws \Exception
*/
public function delete(): ResponseInterface
{
$params = $this->request->inputs(['class_id']);
$this->validate($params, [
'class_id' => 'required|integer'
]);
$isTrue = $this->articleService->delArticleClass($this->uid(), (int)$params['class_id']);
return $isTrue ? $this->response->success() : $this->response->fail();
}
/**
* 笔记分类列表排序接口
*
* @RequestMapping(path="sort", methods="post")
* @return ResponseInterface
* @throws \Exception
*/
public function sort(): 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();
}
}

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Article;
use App\Controller\Api\V1\CController;
use App\Service\ArticleService;
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 Psr\Http\Message\ResponseInterface;
/**
* Class TagController
*
* @Controller(prefix="/api/v1/note/tag")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1\Article
*/
class TagController extends CController
{
/**
* @Inject
* @var ArticleService
*/
private $articleService;
/**
* 获取标签列表
*
* @RequestMapping(path="list", methods="get")
*/
public function list(): ResponseInterface
{
return $this->response->success([
'tags' => $this->articleService->getUserTags($this->uid())
]);
}
/**
* 编辑标签
*
* @RequestMapping(path="editor", methods="post")
*/
public function editor(): 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="delete", methods="post")
*/
public function delete(): 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();
}
}

View File

@ -1,553 +0,0 @@
<?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('笔记附件删除失败!');
}
}

View File

@ -58,18 +58,9 @@ class AuthController extends CController
event()->dispatch(new LoginEvent($this->request, $user));
return $this->response->success([
'authorize' => [
'type' => 'Bearer',
'access_token' => $token,
'expires_in' => $this->guard()->getJwtManager()->getTtl(),
],
'user_info' => [
'nickname' => $user->nickname,
'avatar' => $user->avatar,
'gender' => $user->gender,
'motto' => $user->motto,
'email' => $user->email,
]
'type' => 'Bearer',
'access_token' => $token,
'expires_in' => $this->guard()->getJwtManager()->getTtl(),
], '账号登录成功...');
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1;
class CommonController extends CController
{
/**
* 发送短信验证码
*/
public function SmsCode(){
}
/**
* 发送邮件验证码
*/
public function EmailCode(){
}
/**
* 公共设置
*/
public function Setting(){
}
}

View File

@ -1,10 +1,11 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1;
namespace App\Controller\Api\V1\Contact;
use App\Cache\FriendApply;
use App\Cache\Repository\LockRedis;
use App\Controller\Api\V1\CController;
use App\Service\UserService;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
@ -16,12 +17,12 @@ use Psr\Http\Message\ResponseInterface;
/**
* Class ContactsApplyController
* @Controller(prefix="/api/v1/contacts/apply")
* @Controller(prefix="/api/v1/contact/apply")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
*/
class ContactsApplyController extends CController
class ContactApplyController extends CController
{
/**
* @Inject
@ -130,4 +131,16 @@ class ContactsApplyController extends CController
$this->service->getApplyRecords($user_id, $page, $page_size)
);
}
/**
* 获取联系人申请未读数
*
* @RequestMapping(path="unread-num", methods="get")
*/
public function getContactApplyUnreadNum(): ResponseInterface
{
return $this->response->success([
'unread_num' => (int)FriendApply::getInstance()->get(strval($this->uid()))
]);
}
}

View File

@ -1,8 +1,9 @@
<?php
namespace App\Controller\Api\V1;
namespace App\Controller\Api\V1\Contact;
use App\Constants\TalkModeConstant;
use App\Controller\Api\V1\CController;
use App\Service\TalkListService;
use App\Service\UserService;
use Hyperf\Di\Annotation\Inject;
@ -13,18 +14,17 @@ use App\Middleware\JWTAuthMiddleware;
use Psr\Http\Message\ResponseInterface;
use App\Service\ContactsService;
use App\Service\SocketClientService;
use App\Cache\FriendApply;
use App\Cache\FriendRemark;
use App\Cache\ServerRunID;
/**
* Class ContactsController
* @Controller(prefix="/api/v1/contacts")
* @Controller(prefix="/api/v1/contact")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1
*/
class ContactsController extends CController
class ContactController extends CController
{
/**
* @Inject
@ -32,6 +32,12 @@ class ContactsController extends CController
*/
private $service;
/**
* @Inject
* @var UserService
*/
private $userService;
/**
* 获取用户联系人列表
*
@ -69,36 +75,24 @@ class ContactsController extends CController
di()->get(TalkListService::class)->deleteByType($user_id, $params['friend_id'], TalkModeConstant::PRIVATE_CHAT);
// TODO 推送消息(待完善)
return $this->response->success([], '好友关系解除成功...');
}
/**
* 获取联系人申请未读数
*
* @RequestMapping(path="apply-unread-num", methods="get")
*/
public function getContactApplyUnreadNum(): ResponseInterface
{
return $this->response->success([
'unread_num' => (int)FriendApply::getInstance()->get(strval($this->uid()))
]);
}
/**
* 搜索联系人
*
* @RequestMapping(path="search", methods="get")
*/
public function searchContacts(): ResponseInterface
public function search(): ResponseInterface
{
$params = $this->request->inputs(['mobile']);
$this->validate($params, [
'mobile' => "present|regex:/^1[3456789][0-9]{9}$/"
]);
$result = $this->service->findContact($params['mobile']);
return $this->response->success($result);
}
@ -107,9 +101,10 @@ class ContactsController extends CController
*
* @RequestMapping(path="edit-remark", methods="post")
*/
public function editContactRemark(): ResponseInterface
public function editRemark(): ResponseInterface
{
$params = $this->request->inputs(['friend_id', 'remarks']);
$this->validate($params, [
'friend_id' => 'required|integer|min:1',
'remarks' => "required|max:20"
@ -125,4 +120,23 @@ class ContactsController extends CController
return $this->response->success([], '备注修改成功...');
}
/**
* 通过用户ID查找用户
*
* @RequestMapping(path="detail", methods="get")
*
* @return ResponseInterface
*/
public function detail(): ResponseInterface
{
$params = $this->request->inputs(['user_id']);
$this->validate($params, ['user_id' => 'required|integer']);
if ($data = $this->userService->getUserCard($params['user_id'], $this->uid())) {
return $this->response->success($data);
}
return $this->response->fail('用户查询失败!');
}
}

View File

@ -70,31 +70,4 @@ class DownloadController extends CController
return $response->download($this->getFilePath($info->save_dir), $info->original_name);
}
/**
* 下载笔记附件
* @RequestMapping(path="article-annex", methods="get")
*
* @param ResponseInterface $response
* @param Filesystem $filesystem
* @return \Psr\Http\Message\ResponseInterface
*/
public function articleAnnex(ResponseInterface $response, Filesystem $filesystem)
{
$params = $this->request->inputs(['annex_id']);
$this->validate($params, [
'annex_id' => 'required|integer'
]);
$info = ArticleAnnex::select(['save_dir', 'original_name'])
->where('id', $params['annex_id'])
->where('user_id', $this->uid())
->first();
if (!$info || !$filesystem->has($info->save_dir)) {
return $this->response->fail('文件不存在或没有下载权限!');
}
return $response->download($this->getFilePath($info->save_dir), $info->original_name);
}
}

View File

@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Group;
use App\Controller\Api\V1\CController;
use App\Service\Group\GroupMemberService;
use App\Service\Group\GroupService;
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 Psr\Http\Message\ResponseInterface;
/**
* Class GroupController
*
* @Controller(prefix="/api/v1/group")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1\Group
*/
class GroupController extends CController
{
/**
* @Inject
* @var GroupService
*/
private $groupService;
/**
* @inject
* @var GroupMemberService
*/
private $groupMemberService;
/**
* 获取群组列表
* @RequestMapping(path="list", methods="get")
*/
public function list(): ResponseInterface
{
return $this->response->success([
"rows" => $this->groupService->getUserGroups($this->uid()),
]);
}
// public function Detail()
// {
//
// }
//
// public function Create()
// {
//
// }
//
// public function Dismiss()
// {
//
// }
//
// public function Invite()
// {
//
// }
//
// public function SignOut()
// {
//
// }
//
// public function Setting()
// {
//
// }
}

View File

@ -0,0 +1,142 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Group;
use App\Controller\Api\V1\CController;
use App\Model\Group\GroupMember;
use App\Service\Group\GroupMemberService;
use App\Service\Group\GroupService;
use App\Service\UserService;
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 Psr\Http\Message\ResponseInterface;
/**
* Class MemberController
*
* @Controller(prefix="/api/v1/group/member")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1\Group
*/
class MemberController extends CController
{
/**
* @Inject
* @var GroupService
*/
private $groupService;
/**
* @inject
* @var GroupMemberService
*/
private $groupMemberService;
/**
* 获取群组成员列表
* @RequestMapping(path="list", methods="get")
*/
public function list(): ResponseInterface
{
$user_id = $this->uid();
$group_id = (int)$this->request->input('group_id', 0);
// 判断用户是否是群成员
if (!$this->groupMemberService->isMember($group_id, $user_id)) {
return $this->response->fail('非法操作!');
}
$members = GroupMember::select([
'group_member.id',
'group_member.leader',
'group_member.user_card',
'group_member.user_id',
'users.avatar',
'users.nickname',
'users.gender',
'users.motto',
])
->leftJoin('users', 'users.id', '=', 'group_member.user_id')
->where([
['group_member.group_id', '=', $group_id],
['group_member.is_quit', '=', 0],
])->orderBy('leader', 'desc')->get()->toArray();
return $this->response->success($members);
}
/**
* 获取可邀请加入群组的好友列表
*
* @RequestMapping(path="invites", methods="get")
*/
public function invites(UserService $service): ResponseInterface
{
$group_id = (int)$this->request->input('group_id', 0);
$friends = $service->getUserFriends($this->uid());
if ($group_id > 0 && $friends) {
if ($ids = $this->groupMemberService->getMemberIds($group_id)) {
foreach ($friends as $k => $item) {
if (in_array($item['id'], $ids)) unset($friends[$k]);
}
}
$friends = array_values($friends);
}
return $this->response->success($friends);
}
/**
* 移除指定成员(管理员权限)
*
* @RequestMapping(path="remove", methods="post")
*/
public function removeMembers(): ResponseInterface
{
$params = $this->request->inputs(['group_id', 'members_ids']);
$this->validate($params, [
'group_id' => 'required|integer',
'members_ids' => 'required|ids'
]);
$params['members_ids'] = parse_ids($params['members_ids']);
$user_id = $this->uid();
if (in_array($user_id, $params['members_ids'])) {
return $this->response->fail('群聊用户移除失败!');
}
$isTrue = $this->groupService->removeMember(intval($params['group_id']), $user_id, $params['members_ids']);
if (!$isTrue) {
return $this->response->fail('群聊用户移除失败!');
}
return $this->response->success([], '已成功退出群组...');
}
/**
* 设置群名片
* @RequestMapping(path="remark", methods="post")
*/
public function remark(): ResponseInterface
{
$params = $this->request->inputs(['group_id', 'visit_card']);
$this->validate($params, [
'group_id' => 'required|integer',
'visit_card' => 'required|max:20'
]);
$isTrue = $this->groupService->updateMemberCard(intval($params['group_id']), $this->uid(), $params['visit_card']);
return $isTrue ? $this->response->success([], '群名片修改成功...') : $this->response->fail('群名片修改失败!');
}
}

View File

@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\V1\Group;
use App\Controller\Api\V1\CController;
use App\Service\Group\GroupMemberService;
use App\Service\Group\GroupNoticeService;
use App\Service\Group\GroupService;
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 Psr\Http\Message\ResponseInterface;
/**
* Class NoticeController
*
* @Controller(prefix="/api/v1/group/notice")
* @Middleware(JWTAuthMiddleware::class)
*
* @package App\Controller\Api\V1\Group
*/
class NoticeController extends CController
{
/**
* @Inject
* @var GroupService
*/
private $groupService;
/**
* @inject
* @var GroupMemberService
*/
private $groupMemberService;
/**
* 获取群组公告列表
* @RequestMapping(path="list", methods="get")
*/
public function list(GroupNoticeService $service): ResponseInterface
{
$user_id = $this->uid();
$group_id = (int)$this->request->input('group_id', 0);
// 判断用户是否是群成员
if (!$this->groupMemberService->isMember($group_id, $user_id)) {
return $this->response->fail('非管理员禁止操作!');
}
return $this->response->success([
"rows" => $service->lists($group_id)
]);
}
/**
* 创建/编辑群公告
* @RequestMapping(path="edit", methods="post")
*/
public function edit(GroupNoticeService $service): ResponseInterface
{
$params = $this->request->inputs([
'group_id', 'notice_id', 'title', 'content', 'is_top', 'is_confirm'
]);
$this->validate($params, [
'notice_id' => 'required|integer',
'group_id' => 'required|integer',
'title' => 'required|max:50',
'is_top' => 'integer|in:0,1',
'is_confirm' => 'integer|in:0,1',
'content' => 'required'
]);
$user_id = $this->uid();
// 判断用户是否是管理员
if (!$this->groupMemberService->isAuth(intval($params['group_id']), $user_id)) {
return $this->response->fail('非管理员禁止操作!');
}
// 判断是否是新增数据
if (empty($params['notice_id'])) {
if (!$service->create($user_id, $params)) {
return $this->response->fail('添加群公告信息失败!');
}
return $this->response->success([], '添加群公告信息成功...');
}
return $service->update($params)
? $this->response->success([], '修改群公告信息成功...')
: $this->response->fail('修改群公告信息失败!');
}
/**
* 删除群公告
*
* @RequestMapping(path="delete", methods="post")
*/
public function delete(GroupNoticeService $service): ResponseInterface
{
$params = $this->request->inputs(['group_id', 'notice_id']);
$this->validate($params, [
'group_id' => 'required|integer',
'notice_id' => 'required|integer'
]);
try {
$isTrue = $service->delete(intval($params['notice_id']), $this->uid());
} catch (\Exception $e) {
return $this->response->fail($e->getMessage());
}
return $isTrue ? $this->response->success([], '公告删除成功...') : $this->response->fail('公告删除失败!');
}
}

View File

@ -6,17 +6,14 @@ use App\Constants\TalkModeConstant;
use App\Service\Group\GroupMemberService;
use App\Service\TalkListService;
use App\Service\UserService;
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\Model\Group\Group;
use App\Model\Group\GroupMember;
use App\Model\Group\GroupNotice;
use App\Service\Group\GroupService;
use App\Service\Group\GroupNoticeService;
use Psr\Http\Message\ResponseInterface;
/**
@ -141,33 +138,6 @@ class GroupController extends CController
: $this->response->fail('群组信息修改失败!');
}
/**
* 移除指定成员(管理员权限)
* @RequestMapping(path="remove-members", methods="post")
*/
public function removeMembers(): ResponseInterface
{
$params = $this->request->inputs(['group_id', 'members_ids']);
$this->validate($params, [
'group_id' => 'required|integer',
'members_ids' => 'required|ids'
]);
$params['members_ids'] = parse_ids($params['members_ids']);
$user_id = $this->uid();
if (in_array($user_id, $params['members_ids'])) {
return $this->response->fail('群聊用户移除失败!');
}
$isTrue = $this->groupService->removeMember($params['group_id'], $user_id, $params['members_ids']);
if (!$isTrue) {
return $this->response->fail('群聊用户移除失败!');
}
return $this->response->success([], '已成功退出群组...');
}
/**
* 获取群信息接口
* @RequestMapping(path="detail", methods="get")
@ -205,168 +175,4 @@ class GroupController extends CController
'notice' => $notice ? $notice->toArray() : []
]);
}
/**
* 设置群名片
* @RequestMapping(path="set-group-card", methods="post")
*/
public function editGroupCard(): ResponseInterface
{
$params = $this->request->inputs(['group_id', 'visit_card']);
$this->validate($params, [
'group_id' => 'required|integer',
'visit_card' => 'required|max:20'
]);
$isTrue = $this->groupService->updateMemberCard($params['group_id'], $this->uid(), $params['visit_card']);
return $isTrue
? $this->response->success([], '群名片修改成功...')
: $this->response->error('群名片修改失败!');
}
/**
* 获取可邀请加入群组的好友列表
* @RequestMapping(path="invite-friends", methods="get")
*/
public function getInviteFriends(UserService $service): ResponseInterface
{
$group_id = $this->request->input('group_id', 0);
$friends = $service->getUserFriends($this->uid());
if ($group_id > 0 && $friends) {
if ($ids = $this->groupMemberService->getMemberIds($group_id)) {
foreach ($friends as $k => $item) {
if (in_array($item['id'], $ids)) unset($friends[$k]);
}
}
$friends = array_values($friends);
}
return $this->response->success($friends);
}
/**
* 获取群组列表
* @RequestMapping(path="list", methods="get")
*/
public function getGroups(): ResponseInterface
{
return $this->response->success(
$this->groupService->getUserGroups($this->uid())
);
}
/**
* 获取群组成员列表
* @RequestMapping(path="members", methods="get")
*/
public function getGroupMembers(): ResponseInterface
{
$user_id = $this->uid();
$group_id = $this->request->input('group_id', 0);
// 判断用户是否是群成员
if (!$this->groupMemberService->isMember($group_id, $user_id)) {
return $this->response->fail('非法操作!');
}
$members = GroupMember::select([
'group_member.id',
'group_member.leader',
'group_member.user_card',
'group_member.user_id',
'users.avatar',
'users.nickname',
'users.gender',
'users.motto',
])
->leftJoin('users', 'users.id', '=', 'group_member.user_id')
->where([
['group_member.group_id', '=', $group_id],
['group_member.is_quit', '=', 0],
])->orderBy('leader', 'desc')->get()->toArray();
return $this->response->success($members);
}
/**
* 获取群组公告列表
* @RequestMapping(path="notices", methods="get")
*/
public function getGroupNotice(GroupNoticeService $service): ResponseInterface
{
$user_id = $this->uid();
$group_id = $this->request->input('group_id', 0);
// 判断用户是否是群成员
if (!$this->groupMemberService->isMember($group_id, $user_id)) {
return $this->response->fail('非管理员禁止操作!');
}
return $this->response->success($service->lists($group_id));
}
/**
* 创建/编辑群公告
* @RequestMapping(path="edit-notice", methods="post")
*/
public function editNotice(GroupNoticeService $service): ResponseInterface
{
$params = $this->request->inputs([
'group_id', 'notice_id', 'title', 'content', 'is_top', 'is_confirm'
]);
$this->validate($params, [
'notice_id' => 'required|integer',
'group_id' => 'required|integer',
'title' => 'required|max:50',
'is_top' => 'integer|in:0,1',
'is_confirm' => 'integer|in:0,1',
'content' => 'required'
]);
$user_id = $this->uid();
// 判断用户是否是管理员
if (!$this->groupMemberService->isAuth($params['group_id'], $user_id)) {
return $this->response->fail('非管理员禁止操作!');
}
// 判断是否是新增数据
if (empty($params['notice_id'])) {
if (!$service->create($user_id, $params)) {
return $this->response->fail('添加群公告信息失败!');
}
return $this->response->success([], '添加群公告信息成功...');
}
return $service->update($params)
? $this->response->success([], '修改群公告信息成功...')
: $this->response->fail('修改群公告信息失败!');
}
/**
* 删除群公告(软删除)
* @RequestMapping(path="delete-notice", methods="post")
*/
public function deleteNotice(GroupNoticeService $service): ResponseInterface
{
$params = $this->request->inputs(['group_id', 'notice_id']);
$this->validate($params, [
'group_id' => 'required|integer',
'notice_id' => 'required|integer'
]);
try {
$isTrue = $service->delete($params['notice_id'], $this->uid());
} catch (\Exception $e) {
return $this->response->fail($e->getMessage());
}
return $isTrue
? $this->response->success([], '公告删除成功...')
: $this->response->fail('公告删除失败!');
}
}

View File

@ -122,24 +122,6 @@ class UsersController extends CController
return $this->response->success([], '头像修改成功...');
}
/**
* 通过用户ID查找用户
* @RequestMapping(path="search-user", methods="post")
*
* @return ResponseInterface
*/
public function search(): ResponseInterface
{
$params = $this->request->inputs(['user_id']);
$this->validate($params, ['user_id' => 'required|integer']);
if ($data = $this->userService->getUserCard($params['user_id'], $this->uid())) {
return $this->response->success($data);
}
return $this->response->fail('用户查询失败!');
}
/**
* 修改我的密码
* @RequestMapping(path="change-password", methods="post")

View File

@ -93,11 +93,14 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos
*/
public function onMessage($server, Frame $frame): void
{
// 判断是否为心跳检测
if ($frame->data == 'PING') return;
$result = json_decode($frame->data, true);
// 判断是否为心跳检测
if ($result['event'] == 'heartbeat') {
$server->push($frame->fd, json_encode(['event' => "heartbeat", 'content' => "pong"]));
return;
}
if (!isset(ReceiveHandleService::EVENTS[$result['event']])) {
return;
}

View File

@ -12,9 +12,10 @@ use App\Model\BaseModel;
* @property integer $id 笔记附件ID
* @property integer $user_id 用户ID
* @property integer $article_id 笔记ID
* @property integer $drive 文件驱动
* @property string $file_suffix 文件后缀名
* @property int $file_size 文件大小
* @property string $save_dir 文件相对路径
* @property string $path 文件相对路径
* @property string $original_name 文件原名
* @property integer $status 文件状态
* @property string $created_at 上传时间
@ -28,20 +29,23 @@ class ArticleAnnex extends BaseModel
protected $fillable = [
'user_id',
'article_id',
'file_suffix',
'file_size',
'save_dir',
'drive',
'suffix',
'size',
'path',
'original_name',
'status',
'created_at',
'updated_at',
'deleted_at'
];
protected $casts = [
'user_id' => 'integer',
'article_id' => 'integer',
'file_size' => 'integer',
'size' => 'integer',
'status' => 'integer',
'created_at' => 'datetime'
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}

View File

@ -19,20 +19,26 @@ use App\Model\BaseModel;
*/
class ArticleClass extends BaseModel
{
protected $table = 'article_class';
public $timestamps = true;
protected $fillable = [
'user_id',
'class_name',
'sort',
'is_default',
'created_at',
'updated_at',
];
protected $casts = [
'user_id' => 'integer',
'sort' => 'integer',
'is_default' => 'integer',
'created_at' => 'int'
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
}

View File

@ -17,18 +17,22 @@ use App\Model\BaseModel;
*/
class ArticleTag extends BaseModel
{
protected $table = 'article_tags';
protected $table = 'article_tag';
public $timestamps = true;
protected $fillable = [
'user_id',
'tag_name',
'sort',
'created_at'
'created_at',
'updated_at',
];
protected $casts = [
'user_id' => 'integer',
'sort' => 'integer',
'created_at' => 'integer'
'created_at' => 'datetime',
'updated_at' => 'datetime'
];
}

View File

@ -18,9 +18,9 @@ use App\Cache\FriendRemark;
* @property string $updated_at 更新时间
* @package App\Model
*/
class UsersFriend extends BaseModel
class Contact extends BaseModel
{
protected $table = 'users_friends';
protected $table = 'contact';
protected $fillable = [
'user_id',

View File

@ -14,9 +14,9 @@ namespace App\Model;
* @property string $created_at 创建时间
* @package App\ModelÒ
*/
class UsersFriendApply extends BaseModel
class ContactApply extends BaseModel
{
protected $table = 'users_friends_apply';
protected $table = 'contact_apply';
protected $fillable = [
'user_id',

View File

@ -23,7 +23,7 @@ use App\Model\BaseModel;
*/
class TalkList extends BaseModel
{
protected $table = 'talk_list';
protected $table = 'talk_session';
public $timestamps = true;

View File

@ -156,7 +156,7 @@ class ArticleService extends BaseService
['user_id', '=', $user_id],
['article_id', '=', $article_id],
['status', '=', 1]
])->get(['id', 'file_suffix', 'file_size', 'original_name', 'created_at'])->toArray();
])->get(['id', 'suffix', 'size', 'original_name', 'created_at'])->toArray();
}
/**
@ -191,12 +191,18 @@ class ArticleService extends BaseService
ArticleClass::where('id', $val['id'])->update(['sort' => $val['sort']]);
}
$res = ArticleClass::create(['user_id' => $uid, 'class_name' => $class_name, 'sort' => 1, 'created_at' => time()]);
$res = ArticleClass::create(['user_id' => $uid, 'class_name' => $class_name, 'sort' => 1, 'created_at' => date("y-m-d H:i:s")]);
Db::commit();
return $res->id;
} catch (Exception $e) {
Db::rollBack();
logger()->info("编辑标签失败", [
"error" => $e->getMessage(),
"line" => $e->getLine(),
"file" => $e->getFile(),
]);
return false;
}
}
@ -331,7 +337,7 @@ class ArticleService extends BaseService
// 判断新添加的标签名是否存在
if ($id) return false;
$insRes = ArticleTag::create(['user_id' => $uid, 'tag_name' => $tag_name, 'sort' => 1, 'created_at' => time()]);
$insRes = ArticleTag::create(['user_id' => $uid, 'tag_name' => $tag_name, 'sort' => 1]);
if (!$insRes) {
return false;
}
@ -594,7 +600,7 @@ class ArticleService extends BaseService
*/
public function foreverDelAnnex(int $uid, int $annex_id)
{
$info = ArticleAnnex::where('id', $annex_id)->where('user_id', $uid)->where('status', 2)->first(['id', 'save_dir']);
$info = ArticleAnnex::where('id', $annex_id)->where('user_id', $uid)->where('status', 2)->first(['id', 'path']);
if (!$info) {
return false;
}
@ -619,11 +625,13 @@ class ArticleService extends BaseService
$result = ArticleAnnex::create([
'user_id' => $user_id,
'article_id' => $article_id,
'file_suffix' => $annex['file_suffix'],
'file_size' => $annex['file_size'],
'save_dir' => $annex['save_dir'],
'suffix' => $annex['suffix'],
'size' => $annex['size'],
'drive' => $annex['drive'],
'path' => $annex['path'],
'original_name' => $annex['original_name'],
'created_at' => date('Y-m-d H:i:s')
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
return $result ? $result->id : false;

View File

@ -6,8 +6,8 @@ use App\Cache\FriendApply;
use App\Constants\TalkEventConstant;
use App\Event\TalkEvent;
use App\Model\User;
use App\Model\UsersFriend;
use App\Model\UsersFriendApply;
use App\Model\Contact;
use App\Model\ContactApply;
use App\Traits\PagingTrait;
use Hyperf\DbConnection\Db;
@ -25,13 +25,13 @@ class ContactApplyService
*/
public function create(int $user_id, int $friend_id, string $remark)
{
$result = UsersFriendApply::where([
$result = ContactApply::where([
['user_id', '=', $user_id],
['friend_id', '=', $friend_id],
])->orderByDesc('id')->first();
if (!$result) {
$result = UsersFriendApply::create([
$result = ContactApply::create([
'user_id' => $user_id,
'friend_id' => $friend_id,
'remark' => $remark,
@ -66,14 +66,14 @@ class ContactApplyService
*/
public function accept(int $user_id, int $apply_id, string $remarks = '')
{
$info = UsersFriendApply::where('id', $apply_id)->first();
$info = ContactApply::where('id', $apply_id)->first();
if (!$info || $info->friend_id != $user_id) {
return false;
}
Db::beginTransaction();
try {
UsersFriend::updateOrCreate([
Contact::updateOrCreate([
'user_id' => $info->user_id,
'friend_id' => $info->friend_id,
], [
@ -81,7 +81,7 @@ class ContactApplyService
'remark' => $remarks,
]);
UsersFriend::updateOrCreate([
Contact::updateOrCreate([
'user_id' => $info->friend_id,
'friend_id' => $info->user_id,
], [
@ -117,7 +117,7 @@ class ContactApplyService
*/
public function decline(int $user_id, int $apply_id, string $reason = '')
{
$result = UsersFriendApply::where('id', $apply_id)->where('friend_id', $user_id)->delete();
$result = ContactApply::where('id', $apply_id)->where('friend_id', $user_id)->delete();
if (!$result) return false;
@ -136,24 +136,24 @@ class ContactApplyService
*/
public function getApplyRecords(int $user_id, $page = 1, $page_size = 30): array
{
$rowsSqlObj = UsersFriendApply::select([
'users_friends_apply.id',
'users_friends_apply.remark',
$rowsSqlObj = ContactApply::select([
'contact_apply.id',
'contact_apply.remark',
'users.nickname',
'users.avatar',
'users.mobile',
'users_friends_apply.user_id',
'users_friends_apply.friend_id',
'users_friends_apply.created_at'
'contact_apply.user_id',
'contact_apply.friend_id',
'contact_apply.created_at'
]);
$rowsSqlObj->leftJoin('users', 'users.id', '=', 'users_friends_apply.user_id');
$rowsSqlObj->where('users_friends_apply.friend_id', $user_id);
$rowsSqlObj->leftJoin('users', 'users.id', '=', 'contact_apply.user_id');
$rowsSqlObj->where('contact_apply.friend_id', $user_id);
$count = $rowsSqlObj->count();
$rows = [];
if ($count > 0) {
$rows = $rowsSqlObj->orderBy('users_friends_apply.id', 'desc')->forPage($page, $page_size)->get()->toArray();
$rows = $rowsSqlObj->orderBy('contact_apply.id', 'desc')->forPage($page, $page_size)->get()->toArray();
}
return $this->getPagingRows($rows, $count, $page, $page_size);

View File

@ -11,7 +11,7 @@
namespace App\Service;
use App\Model\User;
use App\Model\UsersFriend;
use App\Model\Contact;
use App\Traits\PagingTrait;
/**
@ -33,7 +33,7 @@ class ContactsService extends BaseService
*/
public function delete(int $user_id, int $friend_id): bool
{
$res = (bool)UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->update([
$res = (bool)Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->update([
'status' => 0,
'updated_at' => date('Y-m-d H:i:s')
]);
@ -55,7 +55,7 @@ class ContactsService extends BaseService
*/
public function editRemark(int $user_id, int $friend_id, string $remark): bool
{
return (bool)UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->update([
return (bool)Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->update([
'remark' => $remark,
'updated_at' => date('Y-m-d H:i:s')
]);

View File

@ -380,7 +380,7 @@ class GroupService extends BaseService
*/
public function removeMember(int $group_id, int $user_id, array $member_ids)
{
if (di()->get(GroupMemberService::class)->isAuth($group_id, $user_id)) {
if (!di()->get(GroupMemberService::class)->isAuth($group_id, $user_id)) {
return false;
}

View File

@ -9,7 +9,7 @@ use App\Constants\TalkEventConstant;
use App\Constants\TalkModeConstant;
use App\Model\Talk\TalkRecords;
use App\Model\User;
use App\Model\UsersFriendApply;
use App\Model\ContactApply;
use App\Service\SocketClientService;
use App\Service\UserService;
@ -216,7 +216,7 @@ class SubscribeHandleService
{
$data = $data['data'];
$applyInfo = UsersFriendApply::where('id', $data['apply_id'])->first();
$applyInfo = ContactApply::where('id', $data['apply_id'])->first();
if (!$applyInfo) return;
$fds = $this->clientService->findUserFds($data['type'] == 1 ? $applyInfo->friend_id : $applyInfo->user_id);

View File

@ -114,7 +114,7 @@ class TalkListService
'group.group_name', 'group.avatar as group_avatar'
];
$rows = TalkList::from('talk_list as list')
$rows = TalkList::from('talk_session as list')
->leftJoin('users', function ($join) {
$join->on('users.id', '=', 'list.receiver_id')->where('list.talk_type', '=', TalkModeConstant::PRIVATE_CHAT);
})

View File

@ -3,7 +3,7 @@
namespace App\Service;
use App\Cache\FriendRemark;
use App\Model\UsersFriend;
use App\Model\Contact;
class UserFriendService
{
@ -19,7 +19,7 @@ class UserFriendService
$remark = FriendRemark::getInstance()->read($user_id, $friend_id);
if ($remark) return $remark;
$remark = UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->value('remark');
$remark = Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->value('remark');
if ($remark) FriendRemark::getInstance()->save($user_id, $friend_id, $remark);
return (string)$remark;
@ -35,13 +35,13 @@ class UserFriendService
*/
public function isFriend(int $user_id, int $friend_id, $is_mutual = false): bool
{
$isTrue1 = UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->exists();
$isTrue1 = Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->exists();
if ($is_mutual === false) {
return $isTrue1;
}
$isTrue2 = UsersFriend::where('user_id', $friend_id)->where('friend_id', $user_id)->where('status', 1)->exists();
$isTrue2 = Contact::where('user_id', $friend_id)->where('friend_id', $user_id)->where('status', 1)->exists();
return $isTrue1 && $isTrue2;
}

View File

@ -5,8 +5,8 @@ namespace App\Service;
use App\Helpers\HashHelper;
use App\Model\User;
use App\Model\Article\ArticleClass;
use App\Model\UsersFriend;
use App\Model\UsersFriendApply;
use App\Model\Contact;
use App\Model\ContactApply;
use Hyperf\DbConnection\Db;
class UserService extends BaseService
@ -131,7 +131,7 @@ class UserService extends BaseService
if ($is_friend) {
$info['nickname_remark'] = di()->get(UserFriendService::class)->getFriendRemark($me_user_id, $friend_id);
} else {
$res = UsersFriendApply::where('user_id', $me_user_id)
$res = ContactApply::where('user_id', $me_user_id)
->where('friend_id', $friend_id)
->orderBy('id', 'desc')
->exists();
@ -151,15 +151,15 @@ class UserService extends BaseService
*/
public function getUserFriends(int $user_id): array
{
return UsersFriend::leftJoin('users', 'users.id', '=', 'users_friends.friend_id')
->where('user_id', $user_id)->where('users_friends.status', 1)
return Contact::Join('users', 'users.id', '=', 'contact.friend_id')
->where('user_id', $user_id)->where('contact.status', 1)
->get([
'users.id',
'users.nickname',
'users.avatar',
'users.motto',
'users.gender',
'users_friends.remark as friend_remark',
'contact.remark as friend_remark',
])->toArray();
}
@ -171,6 +171,6 @@ class UserService extends BaseService
*/
public function getFriendIds(int $user_id): array
{
return UsersFriend::where('user_id', $user_id)->where('status', 1)->pluck('friend_id')->toArray();
return Contact::where('user_id', $user_id)->where('status', 1)->pluck('friend_id')->toArray();
}
}

View File

@ -36,8 +36,14 @@ class Response
*/
public function success(array $data = [], string $message = 'success'): PsrResponseInterface
{
$code = ResponseCode::SUCCESS;
return $this->response->json(compact('code', 'message', 'data'));
$resp = [
"code" => ResponseCode::SUCCESS,
"message" => $message,
];
if ($data) $resp["data"] = $data;
return $this->response->json($resp);
}
/**
@ -50,7 +56,14 @@ class Response
*/
public function fail(string $message = 'fail', array $data = [], $code = ResponseCode::FAIL): PsrResponseInterface
{
return $this->response->json(compact('code', 'message', 'data'));
$resp = [
"code" => $code,
"message" => $message,
];
if ($data) $resp["data"] = $data;
return $this->response->json($resp);
}
/**

View File

@ -15,6 +15,6 @@ use Hyperf\HttpServer\Router\Router;
// 添加 ws 服务对应的路由
Router::get('/socket.io', 'App\Controller\WebSocketController', [
Router::get('/wss/default.io', 'App\Controller\WebSocketController', [
'middleware' => [\App\Middleware\WebSocketAuthMiddleware::class]
]);

View File

@ -7,7 +7,7 @@ use Hyperf\Database\Seeders\Seeder;
use App\Model\User;
use App\Model\Article\ArticleClass;
use Hyperf\DbConnection\Db;
use App\Model\UsersFriend;
use App\Model\Contact;
class Initialize extends Seeder
{
@ -65,7 +65,7 @@ class Initialize extends Seeder
];
}
UsersFriend::insert($friends);
Contact::insert($friends);
$service = new \App\Service\TalkListService();
foreach ($list as $item) {