diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b2c565..ca93d9a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +### [v1.3.5](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.5)(2021-05-20) + +### 更新 + +- 更新演示数据 +- 优化安装脚本install.sh +- 升级脚本upgrade.sh中加入更新导航缓存 +- 撰写文章和提问markdown编辑器通栏显示 +- 完善文章和问题的浏览权限 +- 优化通用ajax表单提交 +- 文章,提问,回答点赞作者有提醒和积分奖励 +- 前台增加针对回答的预览访问地址 +- 前台增加文章,问题,回答,评论加入举报功能 +- 后台增加文章,问题,回答,评论的举报审核功能 +- 后台首页增加审核队列统计 + ### [v1.3.4](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.4)(2021-05-13) ### 更新 diff --git a/README.md b/README.md index df3f0303..a9d3c94d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## 酷瓜云课堂 -![酷瓜云网课GPL协议开源](https://images.gitee.com/uploads/images/2020/1127/092621_3805cf8f_23592.png) +![酷瓜云网课GPL协议开源](https://images.gitee.com/uploads/images/2021/0520/091646_a94e4e7c_23592.png) ### 项目介绍 @@ -14,7 +14,7 @@ ### 系统功能 -实现了点播、直播、专栏、面授、会员、群组、积分、秒杀等,全功能无阉割,100%真开源在线教育解决方案。 +实现了点播、直播、专栏、面授、问答、会员、群组、积分、秒杀等,100%真开源在线教育解决方案。 友情提示: diff --git a/app/Builders/ReportList.php b/app/Builders/ReportList.php new file mode 100644 index 00000000..2c647e93 --- /dev/null +++ b/app/Builders/ReportList.php @@ -0,0 +1,41 @@ +getUsers($reports); + + foreach ($reports as $key => $report) { + $reports[$key]['owner'] = $users[$report['owner_id']] ?? new \stdClass(); + } + + return $reports; + } + + public function getUsers(array $reports) + { + $ids = kg_array_column($reports, 'owner_id'); + + $userRepo = new UserRepo(); + + $users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']); + + $baseUrl = kg_cos_url(); + + $result = []; + + foreach ($users->toArray() as $user) { + $user['avatar'] = $baseUrl . $user['avatar']; + $result[$user['id']] = $user; + } + + return $result; + } + +} diff --git a/app/Caches/UserDailyCounter.php b/app/Caches/UserDailyCounter.php index 6af20260..b5d7493e 100644 --- a/app/Caches/UserDailyCounter.php +++ b/app/Caches/UserDailyCounter.php @@ -22,13 +22,18 @@ class UserDailyCounter extends Counter public function getContent($id = null) { return [ - 'danmu_count' => 0, + 'article_count' => 0, + 'question_count' => 0, + 'answer_count' => 0, + 'comment_count' => 0, 'consult_count' => 0, 'order_count' => 0, 'chapter_like_count' => 0, 'consult_like_count' => 0, 'review_like_count' => 0, 'article_like_count' => 0, + 'question_like_count' => 0, + 'answer_like_count' => 0, 'comment_like_count' => 0, ]; } diff --git a/app/Http/Admin/Controllers/AnswerController.php b/app/Http/Admin/Controllers/AnswerController.php index 42f0af5d..70b8d34a 100644 --- a/app/Http/Admin/Controllers/AnswerController.php +++ b/app/Http/Admin/Controllers/AnswerController.php @@ -46,10 +46,7 @@ class AnswerController extends Controller $question = $questionService->getQuestion($id); - $referer = $this->request->getHTTPReferer(); - $this->view->setVar('question', $question); - $this->view->setVar('referer', $referer); } /** @@ -65,9 +62,6 @@ class AnswerController extends Controller $question = $questionService->getQuestion($answer->question_id); - $referer = $this->request->getHTTPReferer(); - - $this->view->setVar('referer', $referer); $this->view->setVar('question', $question); $this->view->setVar('answer', $answer); } @@ -165,15 +159,15 @@ class AnswerController extends Controller } /** - * @Route("/{id:[0-9]+}/review", name="admin.answer.review") + * @Route("/{id:[0-9]+}/publish/review", name="admin.answer.publish_review") */ - public function reviewAction($id) + public function publishReviewAction($id) { $answerService = new AnswerService(); if ($this->request->isPost()) { - $answerService->reviewAnswer($id); + $answerService->publishReview($id); $location = $this->url->get(['for' => 'admin.mod.answers']); @@ -188,8 +182,38 @@ class AnswerController extends Controller $reasons = $answerService->getReasons(); $answer = $answerService->getAnswerInfo($id); + $this->view->pick('answer/publish_review'); $this->view->setVar('reasons', $reasons); $this->view->setVar('answer', $answer); } + /** + * @Route("/{id:[0-9]+}/report/review", name="admin.answer.report_review") + */ + public function reportReviewAction($id) + { + $answerService = new AnswerService(); + + if ($this->request->isPost()) { + + $answerService->reportReview($id); + + $location = $this->url->get(['for' => 'admin.report.answers']); + + $content = [ + 'location' => $location, + 'msg' => '审核举报成功', + ]; + + return $this->jsonSuccess($content); + } + + $answer = $answerService->getAnswerInfo($id); + $reports = $answerService->getReports($id); + + $this->view->pick('answer/report_review'); + $this->view->setVar('answer', $answer); + $this->view->setVar('reports', $reports); + } + } diff --git a/app/Http/Admin/Controllers/ArticleController.php b/app/Http/Admin/Controllers/ArticleController.php index a849d35e..b7661e27 100644 --- a/app/Http/Admin/Controllers/ArticleController.php +++ b/app/Http/Admin/Controllers/ArticleController.php @@ -169,15 +169,15 @@ class ArticleController extends Controller } /** - * @Route("/{id:[0-9]+}/review", name="admin.article.review") + * @Route("/{id:[0-9]+}/publish/review", name="admin.article.publish_review") */ - public function reviewAction($id) + public function publishReviewAction($id) { $articleService = new ArticleService(); if ($this->request->isPost()) { - $articleService->reviewArticle($id); + $articleService->publishReview($id); $location = $this->url->get(['for' => 'admin.mod.articles']); @@ -192,8 +192,38 @@ class ArticleController extends Controller $reasons = $articleService->getReasons(); $article = $articleService->getArticleInfo($id); + $this->view->pick('article/publish_review'); $this->view->setVar('reasons', $reasons); $this->view->setVar('article', $article); } + /** + * @Route("/{id:[0-9]+}/report/review", name="admin.article.report_review") + */ + public function reportReviewAction($id) + { + $articleService = new ArticleService(); + + if ($this->request->isPost()) { + + $articleService->reportReview($id); + + $location = $this->url->get(['for' => 'admin.report.articles']); + + $content = [ + 'location' => $location, + 'msg' => '审核举报成功', + ]; + + return $this->jsonSuccess($content); + } + + $article = $articleService->getArticleInfo($id); + $reports = $articleService->getReports($id); + + $this->view->pick('article/report_review'); + $this->view->setVar('reports', $reports); + $this->view->setVar('article', $article); + } + } diff --git a/app/Http/Admin/Controllers/CommentController.php b/app/Http/Admin/Controllers/CommentController.php index c67e875e..57872dfa 100644 --- a/app/Http/Admin/Controllers/CommentController.php +++ b/app/Http/Admin/Controllers/CommentController.php @@ -78,4 +78,62 @@ class CommentController extends Controller return $this->jsonSuccess($content); } + /** + * @Route("/{id:[0-9]+}/publish/review", name="admin.comment.publish_review") + */ + public function publishReviewAction($id) + { + $commentService = new CommentService(); + + if ($this->request->isPost()) { + + $commentService->publishReview($id); + + $location = $this->url->get(['for' => 'admin.mod.comments']); + + $content = [ + 'location' => $location, + 'msg' => '审核回答成功', + ]; + + return $this->jsonSuccess($content); + } + + $reasons = $commentService->getReasons(); + $comment = $commentService->getCommentInfo($id); + + $this->view->pick('comment/publish_review'); + $this->view->setVar('reasons', $reasons); + $this->view->setVar('comment', $comment); + } + + /** + * @Route("/{id:[0-9]+}/report/review", name="admin.comment.report_review") + */ + public function reportReviewAction($id) + { + $commentService = new CommentService(); + + if ($this->request->isPost()) { + + $commentService->reportReview($id); + + $location = $this->url->get(['for' => 'admin.report.comments']); + + $content = [ + 'location' => $location, + 'msg' => '审核举报成功', + ]; + + return $this->jsonSuccess($content); + } + + $comment = $commentService->getCommentInfo($id); + $reports = $commentService->getReports($id); + + $this->view->pick('comment/report_review'); + $this->view->setVar('comment', $comment); + $this->view->setVar('reports', $reports); + } + } diff --git a/app/Http/Admin/Controllers/IndexController.php b/app/Http/Admin/Controllers/IndexController.php index 72e5071b..4e14f929 100644 --- a/app/Http/Admin/Controllers/IndexController.php +++ b/app/Http/Admin/Controllers/IndexController.php @@ -38,11 +38,13 @@ class IndexController extends Controller $globalStat = $indexService->getGlobalStat(); $todayStat = $indexService->getTodayStat(); $modStat = $indexService->getModerationStat(); + $reportStat = $indexService->getReportStat(); $appInfo = $indexService->getAppInfo(); $serverInfo = $indexService->getServerInfo(); $this->view->setVar('global_stat', $globalStat); $this->view->setVar('today_stat', $todayStat); + $this->view->setVar('report_stat', $reportStat); $this->view->setVar('mod_stat', $modStat); $this->view->setVar('app_info', $appInfo); $this->view->setVar('server_info', $serverInfo); diff --git a/app/Http/Admin/Controllers/ModerationController.php b/app/Http/Admin/Controllers/ModerationController.php index 0ec36a01..72dd2cfc 100644 --- a/app/Http/Admin/Controllers/ModerationController.php +++ b/app/Http/Admin/Controllers/ModerationController.php @@ -46,4 +46,16 @@ class ModerationController extends Controller $this->view->setVar('pager', $pager); } + /** + * @Get("/comments", name="admin.mod.comments") + */ + public function commentsAction() + { + $modService = new ModerationService(); + + $pager = $modService->getComments(); + + $this->view->setVar('pager', $pager); + } + } diff --git a/app/Http/Admin/Controllers/QuestionController.php b/app/Http/Admin/Controllers/QuestionController.php index 082139dd..45f9b0c2 100644 --- a/app/Http/Admin/Controllers/QuestionController.php +++ b/app/Http/Admin/Controllers/QuestionController.php @@ -165,15 +165,15 @@ class QuestionController extends Controller } /** - * @Route("/{id:[0-9]+}/review", name="admin.question.review") + * @Route("/{id:[0-9]+}/publish/review", name="admin.question.publish_review") */ - public function reviewAction($id) + public function publishReviewAction($id) { $questionService = new QuestionService(); if ($this->request->isPost()) { - $questionService->reviewQuestion($id); + $questionService->publishReview($id); $location = $this->url->get(['for' => 'admin.mod.questions']); @@ -188,8 +188,38 @@ class QuestionController extends Controller $reasons = $questionService->getReasons(); $question = $questionService->getQuestionInfo($id); + $this->view->pick('question/publish_review'); $this->view->setVar('reasons', $reasons); $this->view->setVar('question', $question); } + /** + * @Route("/{id:[0-9]+}/report/review", name="admin.question.report_review") + */ + public function reportReviewAction($id) + { + $questionService = new QuestionService(); + + if ($this->request->isPost()) { + + $questionService->reportReview($id); + + $location = $this->url->get(['for' => 'admin.report.questions']); + + $content = [ + 'location' => $location, + 'msg' => '审核举报成功', + ]; + + return $this->jsonSuccess($content); + } + + $question = $questionService->getQuestionInfo($id); + $reports = $questionService->getReports($id); + + $this->view->pick('question/report_review'); + $this->view->setVar('question', $question); + $this->view->setVar('reports', $reports); + } + } diff --git a/app/Http/Admin/Controllers/ReportController.php b/app/Http/Admin/Controllers/ReportController.php new file mode 100644 index 00000000..bc660089 --- /dev/null +++ b/app/Http/Admin/Controllers/ReportController.php @@ -0,0 +1,61 @@ +getArticles(); + + $this->view->setVar('pager', $pager); + } + + /** + * @Get("/questions", name="admin.report.questions") + */ + public function questionsAction() + { + $reportService = new ReportService(); + + $pager = $reportService->getQuestions(); + + $this->view->setVar('pager', $pager); + } + + /** + * @Get("/answers", name="admin.report.answers") + */ + public function answersAction() + { + $reportService = new ReportService(); + + $pager = $reportService->getAnswers(); + + $this->view->setVar('pager', $pager); + } + + /** + * @Get("/comments", name="admin.report.comments") + */ + public function commentsAction() + { + $reportService = new ReportService(); + + $pager = $reportService->getComments(); + + $this->view->setVar('pager', $pager); + } + +} diff --git a/app/Http/Admin/Services/Answer.php b/app/Http/Admin/Services/Answer.php index abaf914e..4eda7f57 100644 --- a/app/Http/Admin/Services/Answer.php +++ b/app/Http/Admin/Services/Answer.php @@ -3,13 +3,16 @@ namespace App\Http\Admin\Services; use App\Builders\AnswerList as AnswerListBuilder; +use App\Builders\ReportList as ReportListBuilder; use App\Library\Paginator\Query as PagerQuery; use App\Models\Answer as AnswerModel; use App\Models\Question as QuestionModel; use App\Models\Reason as ReasonModel; +use App\Models\Report as ReportModel; use App\Models\User as UserModel; use App\Repos\Answer as AnswerRepo; use App\Repos\Question as QuestionRepo; +use App\Repos\Report as ReportRepo; use App\Repos\User as UserRepo; use App\Services\Logic\Answer\AnswerInfo as AnswerInfoService; use App\Services\Logic\Notice\System\AnswerApproved as AnswerApprovedNotice; @@ -62,6 +65,23 @@ class Answer extends Service return $service->handle($id); } + public function getReports($id) + { + $reportRepo = new ReportRepo(); + + $where = [ + 'item_id' => $id, + 'item_type' => ReportModel::ITEM_ANSWER, + 'reviewed' => 0, + ]; + + $pager = $reportRepo->paginate($where); + + $pager = $this->handleReports($pager); + + return $pager->items; + } + public function createAnswer() { $post = $this->request->getPost(); @@ -167,7 +187,7 @@ class Answer extends Service return $answer; } - public function reviewAnswer($id) + public function publishReview($id) { $type = $this->request->getPost('type', ['trim', 'string']); $reason = $this->request->getPost('reason', ['trim', 'string']); @@ -218,6 +238,42 @@ class Answer extends Service return $answer; } + public function reportReview($id) + { + $accepted = $this->request->getPost('accepted', 'int', 0); + $deleted = $this->request->getPost('deleted', 'int', 0); + + $answer = $this->findOrFail($id); + + $reportRepo = new ReportRepo(); + + $reports = $reportRepo->findItemPendingReports($answer->id, ReportModel::ITEM_ANSWER); + + if ($reports->count() > 0) { + foreach ($reports as $report) { + $report->accepted = $accepted; + $report->reviewed = 1; + $report->update(); + } + } + + $answer->report_count = 0; + + if ($deleted == 1) { + $answer->deleted = 1; + } + + $answer->update(); + + $question = $this->findQuestion($answer->question_id); + + $this->recountQuestionAnswers($question); + + $user = $this->findUser($answer->owner_id); + + $this->recountUserAnswers($user); + } + protected function findOrFail($id) { $validator = new AnswerValidator(); @@ -257,6 +313,23 @@ class Answer extends Service return $pager; } + protected function handleReports($pager) + { + if ($pager->total_items > 0) { + + $builder = new ReportListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleUsers($items); + $pipeB = $builder->objects($pipeA); + + $pager->items = $pipeB; + } + + return $pager; + } + protected function recountQuestionAnswers(QuestionModel $question) { $questionRepo = new QuestionRepo(); diff --git a/app/Http/Admin/Services/Article.php b/app/Http/Admin/Services/Article.php index c8b96086..5af24563 100644 --- a/app/Http/Admin/Services/Article.php +++ b/app/Http/Admin/Services/Article.php @@ -3,15 +3,18 @@ namespace App\Http\Admin\Services; use App\Builders\ArticleList as ArticleListBuilder; +use App\Builders\ReportList as ReportListBuilder; use App\Caches\Article as ArticleCache; use App\Library\Paginator\Query as PagerQuery; use App\Library\Utils\Word as WordUtil; use App\Models\Article as ArticleModel; use App\Models\Category as CategoryModel; use App\Models\Reason as ReasonModel; +use App\Models\Report as ReportModel; use App\Models\User as UserModel; use App\Repos\Article as ArticleRepo; use App\Repos\Category as CategoryRepo; +use App\Repos\Report as ReportRepo; use App\Repos\Tag as TagRepo; use App\Repos\User as UserRepo; use App\Services\Logic\Article\ArticleDataTrait; @@ -119,6 +122,23 @@ class Article extends Service return $service->handle($id); } + public function getReports($id) + { + $reportRepo = new ReportRepo(); + + $where = [ + 'item_id' => $id, + 'item_type' => ReportModel::ITEM_ARTICLE, + 'reviewed' => 0, + ]; + + $pager = $reportRepo->paginate($where); + + $pager = $this->handleReports($pager); + + return $pager->items; + } + public function createArticle() { $post = $this->request->getPost(); @@ -251,7 +271,7 @@ class Article extends Service return $article; } - public function reviewArticle($id) + public function publishReview($id) { $type = $this->request->getPost('type', ['trim', 'string']); $reason = $this->request->getPost('reason', ['trim', 'string']); @@ -282,12 +302,8 @@ class Article extends Service if ($type == 'approve') { $this->rebuildArticleIndex($article); - - $this->handlePostPoint($article); - - $notice = new ArticleApprovedNotice(); - - $notice->handle($article, $sender); + $this->handleArticlePostPoint($article); + $this->handleArticleApprovedNotice($article, $sender); $this->eventsManager->fire('Article:afterApprove', $this, $article); @@ -299,9 +315,7 @@ class Article extends Service $reason = $options[$reason]; } - $notice = new ArticleRejectedNotice(); - - $notice->handle($article, $sender, $reason); + $this->handleArticleRejectedNotice($article, $sender, $reason); $this->eventsManager->fire('Article:afterReject', $this, $article); } @@ -309,6 +323,34 @@ class Article extends Service return $article; } + public function reportReview($id) + { + $accepted = $this->request->getPost('accepted', 'int', 0); + $deleted = $this->request->getPost('deleted', 'int', 0); + + $article = $this->findOrFail($id); + + $reportRepo = new ReportRepo(); + + $reports = $reportRepo->findItemPendingReports($article->id, ReportModel::ITEM_ARTICLE); + + if ($reports->count() > 0) { + foreach ($reports as $report) { + $report->accepted = $accepted; + $report->reviewed = 1; + $report->update(); + } + } + + $article->report_count = 0; + + if ($deleted == 1) { + $article->deleted = 1; + } + + $article->update(); + } + protected function findOrFail($id) { $validator = new ArticleValidator(); @@ -342,6 +384,23 @@ class Article extends Service return $pager; } + protected function handleReports($pager) + { + if ($pager->total_items > 0) { + + $builder = new ReportListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleUsers($items); + $pipeB = $builder->objects($pipeA); + + $pager->items = $pipeB; + } + + return $pager; + } + protected function recountUserArticles(UserModel $user) { $userRepo = new UserRepo(); @@ -367,7 +426,7 @@ class Article extends Service $sync->addItem($article->id); } - protected function handlePostPoint(ArticleModel $article) + protected function handleArticlePostPoint(ArticleModel $article) { if ($article->published != ArticleModel::PUBLISH_APPROVED) return; @@ -376,4 +435,18 @@ class Article extends Service $service->handle($article); } + protected function handleArticleApprovedNotice(ArticleModel $article, UserModel $sender) + { + $notice = new ArticleApprovedNotice(); + + $notice->handle($article, $sender); + } + + protected function handleArticleRejectedNotice(ArticleModel $article, UserModel $sender, $reason) + { + $notice = new ArticleRejectedNotice(); + + $notice->handle($article, $sender, $reason); + } + } diff --git a/app/Http/Admin/Services/AuthNode.php b/app/Http/Admin/Services/AuthNode.php index 2ed2d003..952d795b 100644 --- a/app/Http/Admin/Services/AuthNode.php +++ b/app/Http/Admin/Services/AuthNode.php @@ -325,7 +325,13 @@ class AuthNode extends Service 'id' => '1-7-10', 'title' => '审核文章', 'type' => 'button', - 'route' => 'admin.article.review', + 'route' => 'admin.article.publish_review', + ], + [ + 'id' => '1-7-11', + 'title' => '审核举报', + 'type' => 'button', + 'route' => 'admin.article.report_review', ], ], ], @@ -374,7 +380,13 @@ class AuthNode extends Service 'id' => '1-10-10', 'title' => '审核问题', 'type' => 'button', - 'route' => 'admin.question.review', + 'route' => 'admin.question.publish_review', + ], + [ + 'id' => '1-10-11', + 'title' => '审核举报', + 'type' => 'button', + 'route' => 'admin.question.report_review', ], ], ], @@ -423,7 +435,13 @@ class AuthNode extends Service 'id' => '1-11-10', 'title' => '审核回答', 'type' => 'button', - 'route' => 'admin.answer.review', + 'route' => 'admin.answer.publish_review', + ], + [ + 'id' => '1-11-11', + 'title' => '审核举报', + 'type' => 'button', + 'route' => 'admin.answer.report_review', ], ], ], @@ -456,6 +474,18 @@ class AuthNode extends Service 'type' => 'button', 'route' => 'admin.comment.delete', ], + [ + 'id' => '1-9-5', + 'title' => '评论审核', + 'type' => 'button', + 'route' => 'admin.comment.publish_review', + ], + [ + 'id' => '1-9-6', + 'title' => '举报审核', + 'type' => 'button', + 'route' => 'admin.comment.report_review', + ], ], ], ], @@ -491,6 +521,43 @@ class AuthNode extends Service 'type' => 'menu', 'route' => 'admin.mod.answers', ], + [ + 'id' => '2-10-4', + 'title' => '评论审核', + 'type' => 'menu', + 'route' => 'admin.mod.comments', + ], + ], + ], + [ + 'id' => '2-10', + 'title' => '举报队列', + 'type' => 'menu', + 'children' => [ + [ + 'id' => '2-11-1', + 'title' => '文章举报', + 'type' => 'menu', + 'route' => 'admin.report.articles', + ], + [ + 'id' => '2-11-2', + 'title' => '问题举报', + 'type' => 'menu', + 'route' => 'admin.report.questions', + ], + [ + 'id' => '2-11-3', + 'title' => '回答举报', + 'type' => 'menu', + 'route' => 'admin.report.answers', + ], + [ + 'id' => '2-11-4', + 'title' => '评论举报', + 'type' => 'menu', + 'route' => 'admin.report.comments', + ], ], ], [ diff --git a/app/Http/Admin/Services/Comment.php b/app/Http/Admin/Services/Comment.php index 1410587a..3f0c59dc 100644 --- a/app/Http/Admin/Services/Comment.php +++ b/app/Http/Admin/Services/Comment.php @@ -3,13 +3,24 @@ namespace App\Http\Admin\Services; use App\Builders\CommentList as CommentListBuilder; +use App\Builders\ReportList as ReportListBuilder; use App\Library\Paginator\Query as PagerQuery; +use App\Models\Comment as CommentModel; +use App\Models\Reason as ReasonModel; +use App\Models\Report as ReportModel; use App\Repos\Comment as CommentRepo; +use App\Repos\Report as ReportRepo; +use App\Services\Logic\Comment\CommentInfo as CommentInfoService; use App\Validators\Comment as CommentValidator; class Comment extends Service { + public function getReasons() + { + return ReasonModel::commentRejectOptions(); + } + public function getComments() { $pagerQuery = new PagerQuery(); @@ -34,6 +45,30 @@ class Comment extends Service return $this->findOrFail($id); } + public function getCommentInfo($id) + { + $service = new CommentInfoService(); + + return $service->handle($id); + } + + public function getReports($id) + { + $reportRepo = new ReportRepo(); + + $where = [ + 'item_id' => $id, + 'item_type' => ReportModel::ITEM_COMMENT, + 'reviewed' => 0, + ]; + + $pager = $reportRepo->paginate($where); + + $pager = $this->handleReports($pager); + + return $pager->items; + } + public function updateComment($id) { $comment = $this->findOrFail($id); @@ -79,6 +114,68 @@ class Comment extends Service return $page; } + public function publishReview($id) + { + $type = $this->request->getPost('type', ['trim', 'string']); + $reason = $this->request->getPost('reason', ['trim', 'string']); + + $comment = $this->findOrFail($id); + + $validator = new CommentValidator(); + + if ($type == 'approve') { + + $comment->published = CommentModel::PUBLISH_APPROVED; + + } elseif ($type == 'reject') { + + $validator->checkRejectReason($reason); + + $comment->published = CommentModel::PUBLISH_REJECTED; + } + + $comment->update(); + + if ($type == 'approve') { + + $this->eventsManager->fire('Comment:afterApprove', $this, $comment); + + } elseif ($type == 'reject') { + + $this->eventsManager->fire('Comment:afterReject', $this, $comment); + } + + return $comment; + } + + public function reportReview($id) + { + $accepted = $this->request->getPost('accepted', 'int', 0); + $deleted = $this->request->getPost('deleted', 'int', 0); + + $comment = $this->findOrFail($id); + + $reportRepo = new ReportRepo(); + + $reports = $reportRepo->findItemPendingReports($comment->id, ReportModel::ITEM_COMMENT); + + if ($reports->count() > 0) { + foreach ($reports as $report) { + $report->accepted = $accepted; + $report->reviewed = 1; + $report->update(); + } + } + + $comment->report_count = 0; + + if ($deleted == 1) { + $comment->deleted = 1; + } + + $comment->update(); + } + protected function findOrFail($id) { $validator = new CommentValidator(); @@ -102,4 +199,21 @@ class Comment extends Service return $pager; } + protected function handleReports($pager) + { + if ($pager->total_items > 0) { + + $builder = new ReportListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleUsers($items); + $pipeB = $builder->objects($pipeA); + + $pager->items = $pipeB; + } + + return $pager; + } + } diff --git a/app/Http/Admin/Services/Index.php b/app/Http/Admin/Services/Index.php index 4749042a..32e0e39b 100644 --- a/app/Http/Admin/Services/Index.php +++ b/app/Http/Admin/Services/Index.php @@ -71,6 +71,23 @@ class Index extends Service ]; } + public function getReportStat() + { + $statRepo = new StatRepo(); + + $articleCount = $statRepo->countReportedArticles(); + $questionCount = $statRepo->countReportedQuestions(); + $answerCount = $statRepo->countReportedAnswers(); + $commentCount = $statRepo->countReportedComments(); + + return [ + 'article_count' => $articleCount, + 'question_count' => $questionCount, + 'answer_count' => $answerCount, + 'comment_count' => $commentCount, + ]; + } + public function getReleases() { $url = 'https://koogua.com/api-releases.json'; diff --git a/app/Http/Admin/Services/Moderation.php b/app/Http/Admin/Services/Moderation.php index fbf3cfa7..5cd23d57 100644 --- a/app/Http/Admin/Services/Moderation.php +++ b/app/Http/Admin/Services/Moderation.php @@ -8,9 +8,11 @@ use App\Builders\QuestionList as QuestionListBuilder; use App\Library\Paginator\Query as PagerQuery; use App\Models\Answer as AnswerModel; use App\Models\Article as ArticleModel; +use App\Models\Comment as CommentModel; use App\Models\Question as QuestionModel; use App\Repos\Answer as AnswerRepo; use App\Repos\Article as ArticleRepo; +use App\Repos\Comment as CommentRepo; use App\Repos\Question as QuestionRepo; class Moderation extends Service @@ -76,6 +78,26 @@ class Moderation extends Service return $this->handleAnswers($pager); } + public function getComments() + { + $pagerQuery = new PagerQuery(); + + $params = $pagerQuery->getParams(); + + $params['published'] = CommentModel::PUBLISH_PENDING; + $params['deleted'] = 0; + + $sort = $pagerQuery->getSort(); + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $commentRepo = new CommentRepo(); + + $pager = $commentRepo->paginate($params, $sort, $page, $limit); + + return $this->handleComments($pager); + } + protected function handleArticles($pager) { if ($pager->total_items > 0) { @@ -132,4 +154,21 @@ class Moderation extends Service return $pager; } + protected function handleComments($pager) + { + if ($pager->total_items > 0) { + + $builder = new AnswerListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleUsers($items); + $pipeB = $builder->objects($pipeA); + + $pager->items = $pipeB; + } + + return $pager; + } + } diff --git a/app/Http/Admin/Services/Question.php b/app/Http/Admin/Services/Question.php index a83914fd..61d7f368 100644 --- a/app/Http/Admin/Services/Question.php +++ b/app/Http/Admin/Services/Question.php @@ -3,14 +3,17 @@ namespace App\Http\Admin\Services; use App\Builders\QuestionList as QuestionListBuilder; +use App\Builders\ReportList as ReportListBuilder; use App\Caches\Question as QuestionCache; use App\Library\Paginator\Query as PagerQuery; use App\Models\Category as CategoryModel; use App\Models\Question as QuestionModel; use App\Models\Reason as ReasonModel; +use App\Models\Report as ReportModel; use App\Models\User as UserModel; use App\Repos\Category as CategoryRepo; use App\Repos\Question as QuestionRepo; +use App\Repos\Report as ReportRepo; use App\Repos\Tag as TagRepo; use App\Repos\User as UserRepo; use App\Services\Logic\Notice\System\QuestionApproved as QuestionApprovedNotice; @@ -113,6 +116,23 @@ class Question extends Service return $service->handle($id); } + public function getReports($id) + { + $reportRepo = new ReportRepo(); + + $where = [ + 'item_id' => $id, + 'item_type' => ReportModel::ITEM_QUESTION, + 'reviewed' => 0, + ]; + + $pager = $reportRepo->paginate($where); + + $pager = $this->handleReports($pager); + + return $pager->items; + } + public function createQuestion() { $post = $this->request->getPost(); @@ -233,7 +253,7 @@ class Question extends Service return $question; } - public function reviewQuestion($id) + public function publishReview($id) { $type = $this->request->getPost('type', ['trim', 'string']); $reason = $this->request->getPost('reason', ['trim', 'string']); @@ -260,12 +280,8 @@ class Question extends Service if ($type == 'approve') { $this->rebuildQuestionIndex($question); - - $this->handlePostPoint($question); - - $notice = new QuestionApprovedNotice(); - - $notice->handle($question, $sender); + $this->handleQuestionPostPoint($question); + $this->handleQuestionApprovedNotice($question, $sender); $this->eventsManager->fire('Question:afterApprove', $this, $question); @@ -277,9 +293,7 @@ class Question extends Service $reason = $options[$reason]; } - $notice = new QuestionRejectedNotice(); - - $notice->handle($question, $sender, $reason); + $this->handleQuestionRejectedNotice($question, $sender, $reason); $this->eventsManager->fire('Question:afterReject', $this, $question); } @@ -287,6 +301,34 @@ class Question extends Service return $question; } + public function reportReview($id) + { + $accepted = $this->request->getPost('accepted', 'int', 0); + $deleted = $this->request->getPost('deleted', 'int', 0); + + $question = $this->findOrFail($id); + + $reportRepo = new ReportRepo(); + + $reports = $reportRepo->findItemPendingReports($question->id, ReportModel::ITEM_QUESTION); + + if ($reports->count() > 0) { + foreach ($reports as $report) { + $report->accepted = $accepted; + $report->reviewed = 1; + $report->update(); + } + } + + $question->report_count = 0; + + if ($deleted == 1) { + $question->deleted = 1; + } + + $question->update(); + } + protected function findOrFail($id) { $validator = new QuestionValidator(); @@ -320,6 +362,23 @@ class Question extends Service return $pager; } + protected function handleReports($pager) + { + if ($pager->total_items > 0) { + + $builder = new ReportListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleUsers($items); + $pipeB = $builder->objects($pipeA); + + $pager->items = $pipeB; + } + + return $pager; + } + protected function recountUserQuestions(UserModel $user) { $userRepo = new UserRepo(); @@ -345,7 +404,7 @@ class Question extends Service $sync->addItem($question->id); } - protected function handlePostPoint(QuestionModel $question) + protected function handleQuestionPostPoint(QuestionModel $question) { if ($question->published != QuestionModel::PUBLISH_APPROVED) return; @@ -354,4 +413,18 @@ class Question extends Service $service->handle($question); } + protected function handleQuestionApprovedNotice(QuestionModel $question, UserModel $sender) + { + $notice = new QuestionApprovedNotice(); + + $notice->handle($question, $sender); + } + + protected function handleQuestionRejectedNotice(QuestionModel $question, UserModel $sender, $reason) + { + $notice = new QuestionRejectedNotice(); + + $notice->handle($question, $sender, $reason); + } + } diff --git a/app/Http/Admin/Services/Report.php b/app/Http/Admin/Services/Report.php new file mode 100644 index 00000000..1a7a70c9 --- /dev/null +++ b/app/Http/Admin/Services/Report.php @@ -0,0 +1,162 @@ +getParams(); + + $params['deleted'] = 0; + + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $articleRepo = new ArticleRepo(); + + $pager = $articleRepo->paginate($params, 'reported', $page, $limit); + + return $this->handleArticles($pager); + } + + public function getQuestions() + { + $pagerQuery = new PagerQuery(); + + $params = $pagerQuery->getParams(); + + $params['deleted'] = 0; + + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $questionRepo = new QuestionRepo(); + + $pager = $questionRepo->paginate($params, 'reported', $page, $limit); + + return $this->handleQuestions($pager); + } + + public function getAnswers() + { + $pagerQuery = new PagerQuery(); + + $params = $pagerQuery->getParams(); + + $params['deleted'] = 0; + + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $answerRepo = new AnswerRepo(); + + $pager = $answerRepo->paginate($params, 'reported', $page, $limit); + + return $this->handleAnswers($pager); + } + + public function getComments() + { + $pagerQuery = new PagerQuery(); + + $params = $pagerQuery->getParams(); + + $params['deleted'] = 0; + + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $commentRepo = new CommentRepo(); + + $pager = $commentRepo->paginate($params, 'reported', $page, $limit); + + return $this->handleComments($pager); + } + + protected function handleArticles($pager) + { + if ($pager->total_items > 0) { + + $builder = new ArticleListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleArticles($items); + $pipeB = $builder->handleCategories($pipeA); + $pipeC = $builder->handleUsers($pipeB); + $pipeD = $builder->objects($pipeC); + + $pager->items = $pipeD; + } + + return $pager; + } + + protected function handleQuestions($pager) + { + if ($pager->total_items > 0) { + + $builder = new QuestionListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleQuestions($items); + $pipeB = $builder->handleCategories($pipeA); + $pipeC = $builder->handleUsers($pipeB); + $pipeD = $builder->objects($pipeC); + + $pager->items = $pipeD; + } + + return $pager; + } + + protected function handleAnswers($pager) + { + if ($pager->total_items > 0) { + + $builder = new AnswerListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleQuestions($items); + $pipeB = $builder->handleUsers($pipeA); + $pipeC = $builder->objects($pipeB); + + $pager->items = $pipeC; + } + + return $pager; + } + + protected function handleComments($pager) + { + if ($pager->total_items > 0) { + + $builder = new AnswerListBuilder(); + + $items = $pager->items->toArray(); + + $pipeA = $builder->handleUsers($items); + $pipeB = $builder->objects($pipeA); + + $pager->items = $pipeB; + } + + return $pager; + } + +} diff --git a/app/Http/Admin/Views/answer/add.volt b/app/Http/Admin/Views/answer/add.volt index 4b6a5dcf..d0e4792d 100644 --- a/app/Http/Admin/Views/answer/add.volt +++ b/app/Http/Admin/Views/answer/add.volt @@ -20,7 +20,7 @@
- +
diff --git a/app/Http/Admin/Views/answer/edit.volt b/app/Http/Admin/Views/answer/edit.volt index d11df81c..4812e5c8 100644 --- a/app/Http/Admin/Views/answer/edit.volt +++ b/app/Http/Admin/Views/answer/edit.volt @@ -20,7 +20,7 @@
- +
diff --git a/app/Http/Admin/Views/answer/list.volt b/app/Http/Admin/Views/answer/list.volt index 697a5f19..80d3c81c 100644 --- a/app/Http/Admin/Views/answer/list.volt +++ b/app/Http/Admin/Views/answer/list.volt @@ -24,15 +24,16 @@ {% for item in pager.items %} {% set question_url = url({'for':'home.question.show','id':item.question.id}) %} + {% set answer_url = url({'for':'home.answer.show','id':item.id}) %} {% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %} - {% set review_url = url({'for':'admin.answer.review','id':item.id}) %} {% set edit_url = url({'for':'admin.answer.edit','id':item.id}) %} {% set delete_url = url({'for':'admin.answer.delete','id':item.id}) %} {% set restore_url = url({'for':'admin.answer.restore','id':item.id}) %} + {% set review_url = url({'for':'admin.answer.publish_review','id':item.id}) %}

问题:{{ item.question.title }}

-

回答:{{ item.summary }}

+

回答:{{ substr(item.summary,0,32) }}

作者:{{ item.owner.name }} 创建:{{ date('Y-m-d',item.create_time) }}

{{ item.comment_count }} @@ -42,6 +43,7 @@