mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-29 05:41:37 +08:00
Merge branch 'koogua/v1.6.9'
# Conflicts: # app/Validators/Security.php
This commit is contained in:
commit
046db8877c
18
CHANGELOG.md
18
CHANGELOG.md
@ -1,3 +1,21 @@
|
||||
### [v1.6.9](https://gitee.com/koogua/course-tencent-cloud/releases/v1.6.9)(2024-04-15)
|
||||
|
||||
- 增加用户删除和还原功能
|
||||
- 增加unauthorized响应
|
||||
- 增加post方式传递csrf_token
|
||||
- 删除chapter中resource_count,consult_count属性
|
||||
- 精简csrf_token白名单
|
||||
- 拆解优化migrations创建表脚本
|
||||
- 修正chapter_user时长重复计数问题
|
||||
- 修正后台刷新首页缓存问题
|
||||
- 修正home模块中编辑器图片上传
|
||||
- 优化文章和提问搜索条件
|
||||
- 优化课程详情页排版
|
||||
- 优化storage上传
|
||||
- 优化CategoryTreeList
|
||||
- 优化CourseUserTrait
|
||||
- 更新layui-v2.9.7
|
||||
|
||||
### [v1.6.8](https://gitee.com/koogua/course-tencent-cloud/releases/v1.6.8)(2024-01-30)
|
||||
|
||||
- 修正course_user中active_time未更新问题
|
||||
|
@ -8,15 +8,16 @@
|
||||
namespace App\Builders;
|
||||
|
||||
use App\Models\Category as CategoryModel;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
use App\Repos\Category as CategoryRepo;
|
||||
|
||||
class CategoryTreeList extends Builder
|
||||
{
|
||||
|
||||
public function handle($type)
|
||||
{
|
||||
$topCategories = $this->findTopCategories($type);
|
||||
$categoryRepo = new CategoryRepo();
|
||||
|
||||
$topCategories = $categoryRepo->findTopCategories($type);
|
||||
|
||||
if ($topCategories->count() == 0) {
|
||||
return [];
|
||||
@ -39,7 +40,9 @@ class CategoryTreeList extends Builder
|
||||
|
||||
protected function handleChildren(CategoryModel $category)
|
||||
{
|
||||
$subCategories = $this->findChildCategories($category->id);
|
||||
$categoryRepo = new CategoryRepo();
|
||||
|
||||
$subCategories = $categoryRepo->findChildCategories($category->id);
|
||||
|
||||
if ($subCategories->count() == 0) {
|
||||
return [];
|
||||
@ -59,37 +62,4 @@ class CategoryTreeList extends Builder
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findTopCategories($type)
|
||||
{
|
||||
$query = CategoryModel::query();
|
||||
|
||||
$query->where('parent_id = 0');
|
||||
$query->andWhere('published = 1');
|
||||
$query->andWhere('deleted = 0');
|
||||
$query->andWhere('type = :type:', ['type' => $type]);
|
||||
$query->orderBy('priority ASC');
|
||||
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $parentId
|
||||
* @return ResultsetInterface|Resultset|CategoryModel[]
|
||||
*/
|
||||
protected function findChildCategories($parentId)
|
||||
{
|
||||
$query = CategoryModel::query();
|
||||
|
||||
$query->where('parent_id = :parent_id:', ['parent_id' => $parentId]);
|
||||
$query->andWhere('published = 1');
|
||||
$query->andWhere('deleted = 0');
|
||||
$query->orderBy('priority ASC');
|
||||
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class SyncLearningTask extends Task
|
||||
|
||||
} else {
|
||||
|
||||
$dbLearning->duration += $cacheLearning->duration;
|
||||
$dbLearning->duration = $cacheLearning->duration;
|
||||
$dbLearning->position = $cacheLearning->position;
|
||||
$dbLearning->active_time = $cacheLearning->active_time;
|
||||
|
||||
|
@ -40,7 +40,7 @@ class UploadController extends Controller
|
||||
}
|
||||
|
||||
$data = [
|
||||
'src' => $service->getImageUrl($file->path),
|
||||
'url' => $service->getImageUrl($file->path),
|
||||
'title' => $file->name,
|
||||
];
|
||||
|
||||
@ -61,7 +61,7 @@ class UploadController extends Controller
|
||||
}
|
||||
|
||||
$data = [
|
||||
'src' => $service->getImageUrl($file->path),
|
||||
'url' => $service->getImageUrl($file->path),
|
||||
'title' => $file->name,
|
||||
];
|
||||
|
||||
@ -82,7 +82,7 @@ class UploadController extends Controller
|
||||
}
|
||||
|
||||
$data = [
|
||||
'src' => $service->getImageUrl($file->path),
|
||||
'url' => $service->getImageUrl($file->path),
|
||||
'title' => $file->name,
|
||||
];
|
||||
|
||||
|
@ -140,4 +140,42 @@ class UserController extends Controller
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/delete", name="admin.user.delete")
|
||||
*/
|
||||
public function deleteAction($id)
|
||||
{
|
||||
$userService = new UserService();
|
||||
|
||||
$userService->deleteUser($id);
|
||||
|
||||
$location = $this->url->get(['for' => 'admin.user.list']);
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '删除用户成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/{id:[0-9]+}/restore", name="admin.user.restore")
|
||||
*/
|
||||
public function restoreAction($id)
|
||||
{
|
||||
$userService = new UserService();
|
||||
|
||||
$userService->restoreUser($id);
|
||||
|
||||
$location = $this->url->get(['for' => 'admin.user.list']);
|
||||
|
||||
$content = [
|
||||
'location' => $location,
|
||||
'msg' => '还原用户成功',
|
||||
];
|
||||
|
||||
return $this->jsonSuccess($content);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -178,7 +178,6 @@ class Article extends Service
|
||||
|
||||
if (isset($post['content'])) {
|
||||
$data['content'] = $validator->checkContent($post['content']);
|
||||
$data['word_count'] = WordUtil::getWordCount($data['content']);
|
||||
}
|
||||
|
||||
if (isset($post['source_type'])) {
|
||||
|
@ -48,14 +48,12 @@ class Chapter extends Service
|
||||
|
||||
$data['course_id'] = $course->id;
|
||||
$data['title'] = $validator->checkTitle($post['title']);
|
||||
$data['summary'] = $validator->checkSummary($post['summary']);
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
if (isset($post['parent_id'])) {
|
||||
$parent = $validator->checkParent($post['parent_id']);
|
||||
$data['parent_id'] = $parent->id;
|
||||
$data['free'] = $validator->checkFreeStatus($post['free']);
|
||||
$data['priority'] = $chapterRepo->maxLessonPriority($post['parent_id']);
|
||||
} else {
|
||||
$data['priority'] = $chapterRepo->maxChapterPriority($post['course_id']);
|
||||
|
@ -13,6 +13,7 @@ use App\Http\Admin\Services\Traits\AccountSearchTrait;
|
||||
use App\Library\Paginator\Query as PaginateQuery;
|
||||
use App\Library\Utils\Password as PasswordUtil;
|
||||
use App\Models\Account as AccountModel;
|
||||
use App\Models\Role as RoleModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\Account as AccountRepo;
|
||||
use App\Repos\Online as OnlineRepo;
|
||||
@ -242,6 +243,48 @@ class User extends Service
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function deleteUser($id)
|
||||
{
|
||||
$user = $this->findOrFail($id);
|
||||
|
||||
if ($user->admin_role == RoleModel::ROLE_ROOT) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user->deleted = 1;
|
||||
|
||||
$user->update();
|
||||
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->findById($id);
|
||||
|
||||
$account->deleted = 1;
|
||||
|
||||
$account->update();
|
||||
|
||||
$this->rebuildUserCache($user);
|
||||
}
|
||||
|
||||
public function restoreUser($id)
|
||||
{
|
||||
$user = $this->findOrFail($id);
|
||||
|
||||
$user->deleted = 0;
|
||||
|
||||
$user->update();
|
||||
|
||||
$accountRepo = new AccountRepo();
|
||||
|
||||
$account = $accountRepo->findById($id);
|
||||
|
||||
$account->deleted = 0;
|
||||
|
||||
$account->update();
|
||||
|
||||
$this->rebuildUserCache($user);
|
||||
}
|
||||
|
||||
public function updateAccount($id)
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
@ -23,19 +23,6 @@
|
||||
<input class="layui-input" type="text" name="title" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">简介</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea class="layui-textarea" name="summary"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">免费</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="free" value="1" title="是">
|
||||
<input type="radio" name="free" value="0" title="否" checked="checked">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
|
@ -51,6 +51,8 @@
|
||||
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
||||
{% set online_url = url({'for':'admin.user.online','id':item.id}) %}
|
||||
{% set edit_url = url({'for':'admin.user.edit','id':item.id}) %}
|
||||
{% set delete_url = url({'for':'admin.user.delete','id':item.id}) %}
|
||||
{% set restore_url = url({'for':'admin.user.restore','id':item.id}) %}
|
||||
<tr>
|
||||
<td class="center">
|
||||
<img class="kg-avatar-sm" src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
|
||||
@ -87,7 +89,14 @@
|
||||
<ul>
|
||||
<li><a href="{{ user_url }}" target="_blank">用户主页</a></li>
|
||||
<li><a href="javascript:" class="kg-online" data-url="{{ online_url }}">在线记录</a></li>
|
||||
{% if item.admin_role.id != 1 %}
|
||||
<li><a href="{{ edit_url }}">编辑用户</a></li>
|
||||
{% if item.deleted == 0 %}
|
||||
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除用户</a></li>
|
||||
{% else %}
|
||||
<li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原用户</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -68,6 +68,13 @@
|
||||
<input type="radio" name="locked" value="0" title="否">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">是否删除</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="deleted" value="1" title="是">
|
||||
<input type="radio" name="deleted" value="0" title="否">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
|
@ -12,7 +12,6 @@ use App\Services\Logic\Chapter\ChapterLike as ChapterLikeService;
|
||||
use App\Services\Logic\Chapter\CommentList as CommentListService;
|
||||
use App\Services\Logic\Chapter\ConsultList as ConsultListService;
|
||||
use App\Services\Logic\Chapter\Learning as LearningService;
|
||||
use App\Services\Logic\Chapter\ResourceList as ResourceListService;
|
||||
|
||||
/**
|
||||
* @RoutePrefix("/api/chapter")
|
||||
@ -44,18 +43,6 @@ class ChapterController extends Controller
|
||||
return $this->jsonPaginate($pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}/resources", name="api.chapter.resourses")
|
||||
*/
|
||||
public function resourcesAction($id)
|
||||
{
|
||||
$service = new ResourceListService();
|
||||
|
||||
$resources = $service->handle($id);
|
||||
|
||||
return $this->jsonSuccess(['resources' => $resources]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Get("/{id:[0-9]+}/info", name="api.chapter.info")
|
||||
*/
|
||||
@ -73,6 +60,10 @@ class ChapterController extends Controller
|
||||
$this->notFound();
|
||||
}
|
||||
|
||||
if ($chapter['me']['logged'] == 0) {
|
||||
$this->unauthorized();
|
||||
}
|
||||
|
||||
if ($chapter['me']['owned'] == 0) {
|
||||
$this->forbidden();
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
namespace App\Http\Api\Controllers;
|
||||
|
||||
use App\Caches\IndexArticleList;
|
||||
use App\Caches\IndexFlashSaleList;
|
||||
use App\Caches\IndexLiveList;
|
||||
use App\Caches\IndexQuestionList;
|
||||
use App\Caches\IndexSimpleFeaturedCourseList;
|
||||
|
@ -30,7 +30,7 @@ class UploadController extends Controller
|
||||
}
|
||||
|
||||
$data = [
|
||||
'src' => $service->getImageUrl($file->path),
|
||||
'url' => $service->getImageUrl($file->path),
|
||||
'title' => $file->name,
|
||||
];
|
||||
|
||||
|
@ -39,7 +39,7 @@ class UploadController extends Controller
|
||||
}
|
||||
|
||||
$data = [
|
||||
'src' => $service->getImageUrl($file->path),
|
||||
'url' => $service->getImageUrl($file->path),
|
||||
'title' => $file->name,
|
||||
];
|
||||
|
||||
@ -47,9 +47,9 @@ class UploadController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @Post("/content/img", name="home.upload.content_img")
|
||||
* @Post("/editor/img", name="home.upload.editor_img")
|
||||
*/
|
||||
public function uploadContentImageAction()
|
||||
public function uploadEditorImageAction()
|
||||
{
|
||||
$service = new StorageService();
|
||||
|
||||
|
@ -92,7 +92,7 @@
|
||||
<div class="course-meta wrap">
|
||||
<div class="cover">
|
||||
<span class="model layui-badge layui-bg-green">{{ model_type(course.model) }}</span>
|
||||
<img src="{{ course.cover }}" alt="{{ course.title }}">
|
||||
<img src="{{ course.cover }}!cover_270" alt="{{ course.title }}">
|
||||
</div>
|
||||
<div class="info">
|
||||
{% if course.model == 1 %}
|
||||
|
@ -69,35 +69,35 @@
|
||||
<tr>
|
||||
<td>发布问题</td>
|
||||
<td>{{ event_rule.question_post.point }}</td>
|
||||
<td>{{ event_rule.article_post.limit }}</td>
|
||||
<td>{{ event_rule.question_post.limit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if event_rule.answer_post.enabled == 1 %}
|
||||
<tr>
|
||||
<td>回答问题</td>
|
||||
<td>{{ event_rule.answer_post.point }}</td>
|
||||
<td>{{ event_rule.article_post.limit }}</td>
|
||||
<td>{{ event_rule.answer_post.limit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if event_rule.article_liked.enabled == 1 %}
|
||||
<tr>
|
||||
<td>文章被赞</td>
|
||||
<td>{{ event_rule.article_liked.point }}</td>
|
||||
<td>{{ event_rule.article_post.limit }}</td>
|
||||
<td>{{ event_rule.article_liked.limit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if event_rule.question_liked.enabled == 1 %}
|
||||
<tr>
|
||||
<td>问题被赞</td>
|
||||
<td>{{ event_rule.question_liked.point }}</td>
|
||||
<td>{{ event_rule.article_post.limit }}</td>
|
||||
<td>{{ event_rule.question_liked.limit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if event_rule.answer_liked.enabled == 1 %}
|
||||
<tr>
|
||||
<td>回答被赞</td>
|
||||
<td>{{ event_rule.answer_liked.point }}</td>
|
||||
<td>{{ event_rule.article_post.limit }}</td>
|
||||
<td>{{ event_rule.answer_liked.limit }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
|
@ -79,7 +79,7 @@
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('home/js/upload.avatar.js') }}
|
||||
{{ js_include('home/js/user.avatar.upload.js') }}
|
||||
{{ js_include('home/js/user.console.profile.js') }}
|
||||
|
||||
{% endblock %}
|
@ -38,7 +38,7 @@ class Question extends Model
|
||||
public $category_id = 0;
|
||||
|
||||
/**
|
||||
* 提问者
|
||||
* 提问者编号
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
|
@ -57,6 +57,14 @@ class Article extends Repository
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where['owner_id'])) {
|
||||
if (is_array($where['owner_id'])) {
|
||||
$builder->inWhere('owner_id', $where['owner_id']);
|
||||
} else {
|
||||
$builder->andWhere('owner_id = :owner_id:', ['owner_id' => $where['owner_id']]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where['source_type'])) {
|
||||
if (is_array($where['source_type'])) {
|
||||
$builder->inWhere('source_type', $where['source_type']);
|
||||
@ -73,10 +81,6 @@ class Article extends Repository
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where['owner_id'])) {
|
||||
$builder->andWhere('owner_id = :owner_id:', ['owner_id' => $where['owner_id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['title'])) {
|
||||
$builder->andWhere('title LIKE :title:', ['title' => "%{$where['title']}%"]);
|
||||
}
|
||||
|
@ -58,6 +58,14 @@ class Question extends Repository
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where['owner_id'])) {
|
||||
if (is_array($where['owner_id'])) {
|
||||
$builder->inWhere('owner_id', $where['owner_id']);
|
||||
} else {
|
||||
$builder->andWhere('owner_id = :owner_id:', ['owner_id' => $where['owner_id']]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($where['published'])) {
|
||||
if (is_array($where['published'])) {
|
||||
$builder->inWhere('published', $where['published']);
|
||||
@ -72,10 +80,6 @@ class Question extends Repository
|
||||
$builder->betweenWhere('create_time', $startTime, $endTime);
|
||||
}
|
||||
|
||||
if (!empty($where['owner_id'])) {
|
||||
$builder->andWhere('owner_id = :owner_id:', ['owner_id' => $where['owner_id']]);
|
||||
}
|
||||
|
||||
if (!empty($where['title'])) {
|
||||
$builder->andWhere('title LIKE :title:', ['title' => "%{$where['title']}%"]);
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class Review extends Repository
|
||||
|
||||
public function countLikes($reviewId)
|
||||
{
|
||||
return ReviewLikeModel::count([
|
||||
return (int)ReviewLikeModel::count([
|
||||
'conditions' => 'review_id = :review_id: AND deleted = 0',
|
||||
'bind' => ['review_id' => $reviewId],
|
||||
]);
|
||||
|
@ -11,7 +11,6 @@ use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
|
||||
use App\Models\Chapter as ChapterModel;
|
||||
use App\Models\ChapterLive as ChapterLiveModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
|
||||
class TeacherLive extends Repository
|
||||
{
|
||||
@ -33,7 +32,6 @@ class TeacherLive extends Repository
|
||||
->join(ChapterLiveModel::class, 'chapter.id = cl.chapter_id', 'cl')
|
||||
->join(CourseModel::class, 'chapter.course_id = course.id', 'course')
|
||||
->where('course.teacher_id = :teacher_id:', ['teacher_id' => $userId])
|
||||
->andWhere('course.model = :model:', ['model' => CourseModel::MODEL_LIVE])
|
||||
->andWhere('cl.start_time > :start_time:', ['start_time' => strtotime('today')])
|
||||
->orderBy('cl.start_time ASC');
|
||||
|
||||
|
@ -50,7 +50,7 @@ class ChapterVod extends Service
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($vod->file_transcode as $key => $file) {
|
||||
foreach ($vod->file_transcode as $file) {
|
||||
$file['url'] = $vodService->getPlayUrl($file['url']);
|
||||
$type = $this->getDefinitionType($file['height']);
|
||||
$result[$type] = $file;
|
||||
|
@ -14,6 +14,7 @@ use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\ChapterLike as ChapterLikeRepo;
|
||||
use App\Services\Logic\ChapterTrait;
|
||||
use App\Services\Logic\Course\CourseUserTrait;
|
||||
use App\Services\Logic\CourseTrait;
|
||||
use App\Services\Logic\Service as LogicService;
|
||||
|
||||
@ -31,6 +32,7 @@ class ChapterInfo extends LogicService
|
||||
protected $user;
|
||||
|
||||
use CourseTrait;
|
||||
use CourseUserTrait;
|
||||
use ChapterTrait;
|
||||
|
||||
public function handle($id)
|
||||
@ -88,8 +90,6 @@ class ChapterInfo extends LogicService
|
||||
|
||||
if (!$this->ownedCourse) return;
|
||||
|
||||
$courseUser = new CourseUserModel();
|
||||
|
||||
$sourceType = CourseUserModel::SOURCE_FREE;
|
||||
|
||||
if ($course->market_price > 0) {
|
||||
@ -100,18 +100,14 @@ class ChapterInfo extends LogicService
|
||||
}
|
||||
}
|
||||
|
||||
$courseUser->course_id = $course->id;
|
||||
$courseUser->user_id = $user->id;
|
||||
$courseUser->source_type = $sourceType;
|
||||
|
||||
$courseUser->create();
|
||||
$courseUser = $this->createCourseUser($course, $user, 0, $sourceType);
|
||||
|
||||
$this->courseUser = $courseUser;
|
||||
|
||||
$this->joinedCourse = true;
|
||||
|
||||
$this->incrCourseUserCount($course);
|
||||
$this->incrUserCourseCount($user);
|
||||
$this->recountCourseUsers($course);
|
||||
$this->recountUserCourses($user);
|
||||
}
|
||||
|
||||
protected function handleChapterUser(ChapterModel $chapter, UserModel $user)
|
||||
@ -188,20 +184,6 @@ class ChapterInfo extends LogicService
|
||||
return $me;
|
||||
}
|
||||
|
||||
protected function incrUserCourseCount(UserModel $user)
|
||||
{
|
||||
$user->course_count += 1;
|
||||
|
||||
$user->update();
|
||||
}
|
||||
|
||||
protected function incrCourseUserCount(CourseModel $course)
|
||||
{
|
||||
$course->user_count += 1;
|
||||
|
||||
$course->update();
|
||||
}
|
||||
|
||||
protected function incrChapterUserCount(ChapterModel $chapter)
|
||||
{
|
||||
$chapter->user_count += 1;
|
||||
|
@ -23,9 +23,9 @@ class Learning extends LogicService
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$chapter = $this->checkChapter($id);
|
||||
$chapter = $this->checkChapterCache($id);
|
||||
|
||||
$user = $this->getLoginUser();
|
||||
$user = $this->getLoginUser(true);
|
||||
|
||||
$validator = new LearningValidator();
|
||||
|
||||
|
@ -18,6 +18,7 @@ class ChapterList extends LogicService
|
||||
{
|
||||
|
||||
use CourseTrait;
|
||||
use CourseUserTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ class CourseInfo extends LogicService
|
||||
{
|
||||
|
||||
use CourseTrait;
|
||||
use CourseUserTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -17,6 +17,67 @@ use App\Repos\User as UserRepo;
|
||||
trait CourseUserTrait
|
||||
{
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $ownedCourse = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $joinedCourse = false;
|
||||
|
||||
/**
|
||||
* @var CourseUserModel|null
|
||||
*/
|
||||
protected $courseUser;
|
||||
|
||||
public function setCourseUser(CourseModel $course, UserModel $user)
|
||||
{
|
||||
if ($user->id == 0) return;
|
||||
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseUser($course->id, $user->id);
|
||||
|
||||
$this->courseUser = $courseUser;
|
||||
|
||||
if ($courseUser) {
|
||||
$this->joinedCourse = true;
|
||||
}
|
||||
|
||||
if ($course->market_price == 0) {
|
||||
|
||||
$this->ownedCourse = true;
|
||||
|
||||
} elseif ($course->market_price > 0 && $course->vip_price == 0 && $user->vip == 1) {
|
||||
|
||||
$this->ownedCourse = true;
|
||||
|
||||
} elseif ($courseUser) {
|
||||
|
||||
$sourceTypes = [
|
||||
CourseUserModel::SOURCE_CHARGE,
|
||||
CourseUserModel::SOURCE_MANUAL,
|
||||
CourseUserModel::SOURCE_POINT_REDEEM,
|
||||
CourseUserModel::SOURCE_LUCKY_REDEEM,
|
||||
];
|
||||
|
||||
$case1 = $courseUser->deleted == 0;
|
||||
$case2 = $courseUser->expiry_time > time();
|
||||
$case3 = in_array($courseUser->source_type, $sourceTypes);
|
||||
|
||||
/**
|
||||
* 之前参与过课程,但不再满足条件,视为未参与
|
||||
*/
|
||||
if ($case1 && $case2 && $case3) {
|
||||
$this->ownedCourse = true;
|
||||
} else {
|
||||
$this->joinedCourse = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function assignUserCourse(CourseModel $course, UserModel $user, int $expiryTime, int $sourceType)
|
||||
{
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
@ -16,6 +16,7 @@ class ResourceList extends LogicService
|
||||
{
|
||||
|
||||
use CourseTrait;
|
||||
use CourseUserTrait;
|
||||
|
||||
public function handle($id)
|
||||
{
|
||||
|
@ -7,30 +7,11 @@
|
||||
|
||||
namespace App\Services\Logic;
|
||||
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\CourseUser as CourseUserModel;
|
||||
use App\Models\User as UserModel;
|
||||
use App\Repos\CourseUser as CourseUserRepo;
|
||||
use App\Validators\Course as CourseValidator;
|
||||
|
||||
trait CourseTrait
|
||||
{
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $ownedCourse = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $joinedCourse = false;
|
||||
|
||||
/**
|
||||
* @var CourseUserModel|null
|
||||
*/
|
||||
protected $courseUser;
|
||||
|
||||
public function checkCourse($id)
|
||||
{
|
||||
$validator = new CourseValidator();
|
||||
@ -45,50 +26,4 @@ trait CourseTrait
|
||||
return $validator->checkCourseCache($id);
|
||||
}
|
||||
|
||||
public function setCourseUser(CourseModel $course, UserModel $user)
|
||||
{
|
||||
if ($user->id == 0) return;
|
||||
|
||||
$courseUserRepo = new CourseUserRepo();
|
||||
|
||||
$courseUser = $courseUserRepo->findCourseUser($course->id, $user->id);
|
||||
|
||||
$this->courseUser = $courseUser;
|
||||
|
||||
if ($courseUser) {
|
||||
$this->joinedCourse = true;
|
||||
}
|
||||
|
||||
if ($course->market_price == 0) {
|
||||
|
||||
$this->ownedCourse = true;
|
||||
|
||||
} elseif ($course->market_price > 0 && $course->vip_price == 0 && $user->vip == 1) {
|
||||
|
||||
$this->ownedCourse = true;
|
||||
|
||||
} elseif ($courseUser) {
|
||||
|
||||
$sourceTypes = [
|
||||
CourseUserModel::SOURCE_CHARGE,
|
||||
CourseUserModel::SOURCE_MANUAL,
|
||||
CourseUserModel::SOURCE_POINT_REDEEM,
|
||||
CourseUserModel::SOURCE_LUCKY_REDEEM,
|
||||
];
|
||||
|
||||
$case1 = $courseUser->deleted == 0;
|
||||
$case2 = $courseUser->expiry_time > time();
|
||||
$case3 = in_array($courseUser->source_type, $sourceTypes);
|
||||
|
||||
/**
|
||||
* 之前参与过课程,但不再满足条件,视为未参与
|
||||
*/
|
||||
if ($case1 && $case2 && $case3) {
|
||||
$this->ownedCourse = true;
|
||||
} else {
|
||||
$this->joinedCourse = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||
* @license https://opensource.org/licenses/GPL-2.0
|
||||
* @link https://www.koogua.com
|
||||
*/
|
||||
|
||||
namespace App\Services\Logic;
|
||||
|
||||
use App\Validators\Danmu as DanmuValidator;
|
||||
|
||||
trait DanmuTrait
|
||||
{
|
||||
|
||||
public function checkDanmu($id)
|
||||
{
|
||||
$validator = new DanmuValidator();
|
||||
|
||||
return $validator->checkDanmu($id);
|
||||
}
|
||||
|
||||
}
|
@ -140,7 +140,7 @@ class MyStorage extends Storage
|
||||
*/
|
||||
public function uploadCoverImage()
|
||||
{
|
||||
return $this->upload('/img/cover/', self::MIME_IMAGE, UploadModel::TYPE_COVER_IMG);
|
||||
return $this->upload('/img/cover', self::MIME_IMAGE, UploadModel::TYPE_COVER_IMG);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,7 +150,7 @@ class MyStorage extends Storage
|
||||
*/
|
||||
public function uploadContentImage()
|
||||
{
|
||||
return $this->upload('/img/content/', self::MIME_IMAGE, UploadModel::TYPE_CONTENT_IMG);
|
||||
return $this->upload('/img/content', self::MIME_IMAGE, UploadModel::TYPE_CONTENT_IMG);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,7 +160,7 @@ class MyStorage extends Storage
|
||||
*/
|
||||
public function uploadAvatarImage()
|
||||
{
|
||||
return $this->upload('/img/avatar/', self::MIME_IMAGE, UploadModel::TYPE_AVATAR_IMG);
|
||||
return $this->upload('/img/avatar', self::MIME_IMAGE, UploadModel::TYPE_AVATAR_IMG);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,7 +170,7 @@ class MyStorage extends Storage
|
||||
*/
|
||||
public function uploadIconImage()
|
||||
{
|
||||
return $this->upload('/img/icon/', self::MIME_IMAGE, UploadModel::TYPE_ICON_IMG);
|
||||
return $this->upload('/img/icon', self::MIME_IMAGE, UploadModel::TYPE_ICON_IMG);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +180,7 @@ class MyStorage extends Storage
|
||||
*/
|
||||
public function uploadResource()
|
||||
{
|
||||
return $this->upload('/resource/', self::MIME_FILE, UploadModel::TYPE_RESOURCE);
|
||||
return $this->upload('/resource', self::MIME_FILE, UploadModel::TYPE_RESOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,7 +221,7 @@ class MyStorage extends Storage
|
||||
if (empty($fileName)) {
|
||||
$keyName = $this->generateFileName($extension, $prefix);
|
||||
} else {
|
||||
$keyName = $prefix . $fileName;
|
||||
$keyName = $prefix .'/'. $fileName;
|
||||
}
|
||||
|
||||
$path = $this->putFile($keyName, $file->getTempName());
|
||||
|
@ -198,7 +198,7 @@ class Refund extends Service
|
||||
|
||||
if (!$courseUser) return 1.00;
|
||||
|
||||
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId);
|
||||
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $courseUser->plan_id);
|
||||
|
||||
if ($userLearnings->count() == 0) return 1.00;
|
||||
|
||||
|
@ -259,7 +259,7 @@ class Storage extends Service
|
||||
|
||||
$dot = $extension ? '.' : '';
|
||||
|
||||
return sprintf('%s%s%s%s', $prefix, $name, $dot, $extension);
|
||||
return sprintf('%s/%s%s%s', $prefix, $name, $dot, $extension);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,10 +21,6 @@ class Learning extends AppService
|
||||
*/
|
||||
protected $lifetime = 86400;
|
||||
|
||||
/**
|
||||
* @param LearningModel $learning
|
||||
* @param int $intervalTime
|
||||
*/
|
||||
public function addItem(LearningModel $learning, $intervalTime = 10)
|
||||
{
|
||||
$cache = $this->getCache();
|
||||
|
@ -9,14 +9,20 @@ namespace App\Traits;
|
||||
|
||||
use App\Exceptions\Forbidden as ForbiddenException;
|
||||
use App\Exceptions\NotFound as NotFoundException;
|
||||
use Phalcon\Config;
|
||||
use Phalcon\Di;
|
||||
use App\Exceptions\Unauthorized as UnauthorizedException;
|
||||
use Phalcon\Config as Config;
|
||||
use Phalcon\Di as Di;
|
||||
use Phalcon\Http\Request as HttpRequest;
|
||||
use Phalcon\Http\Response as HttpResponse;
|
||||
|
||||
trait Response
|
||||
{
|
||||
|
||||
public function unauthorized()
|
||||
{
|
||||
throw new UnauthorizedException('sys.unauthorized');
|
||||
}
|
||||
|
||||
public function forbidden()
|
||||
{
|
||||
throw new ForbiddenException('sys.forbidden');
|
||||
|
@ -18,16 +18,22 @@ class Security extends Validator
|
||||
public function checkCsrfToken()
|
||||
{
|
||||
$route = $this->router->getMatchedRoute();
|
||||
$headerToken = $this->request->getHeader('X-Csrf-Token');
|
||||
$postToken = $this->request->getPost('csrf_token');
|
||||
|
||||
if (in_array($route->getName(), $this->getCsrfWhitelist())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$token = $this->request->getHeader('X-Csrf-Token');
|
||||
|
||||
$service = new CsrfTokenService();
|
||||
|
||||
$result = $service->checkToken($token);
|
||||
$result = false;
|
||||
|
||||
if ($headerToken) {
|
||||
$result = $service->checkToken($headerToken);
|
||||
} elseif ($postToken) {
|
||||
$result = $service->checkToken($postToken);
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
throw new BadRequestException('security.invalid_csrf_token');
|
||||
@ -58,10 +64,7 @@ class Security extends Validator
|
||||
|
||||
protected function getCsrfWhitelist()
|
||||
{
|
||||
return [
|
||||
'admin.upload.content_img',
|
||||
'home.upload.content_img',
|
||||
];
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"require": {
|
||||
"ext-phalcon": "~3.4",
|
||||
"ext-redis": "~5.0",
|
||||
"ext-redis": "*",
|
||||
"ext-pdo": "*",
|
||||
"ext-json": "*",
|
||||
"ext-fileinfo": "*",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,8 +32,8 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
||||
});
|
||||
},
|
||||
done: function (res, index, upload) {
|
||||
$('#img-avatar').attr('src', res.data.src);
|
||||
$('input[name=avatar]').val(res.data.src);
|
||||
$('#img-avatar').attr('src', res.data.url);
|
||||
$('input[name=avatar]').val(res.data.url);
|
||||
layer.closeAll('loading');
|
||||
},
|
||||
error: function (index, upload) {
|
||||
|
@ -18,6 +18,9 @@ layui.use(['jquery'], function () {
|
||||
'superscript', 'subscript', '|', 'image', 'link', 'unlink', '|',
|
||||
'source', 'about'
|
||||
],
|
||||
extraFileUploadParams: {
|
||||
csrf_token: $('meta[name="csrf-token"]').attr('content')
|
||||
}
|
||||
};
|
||||
|
||||
KindEditor.ready(function (K) {
|
||||
|
@ -13,8 +13,8 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
||||
layer.load();
|
||||
},
|
||||
done: function (res, index, upload) {
|
||||
$('#img-cover').attr('src', res.data.src);
|
||||
$('input[name=cover]').val(res.data.src);
|
||||
$('#img-cover').attr('src', res.data.url);
|
||||
$('input[name=cover]').val(res.data.url);
|
||||
layer.closeAll('loading');
|
||||
},
|
||||
error: function (index, upload) {
|
||||
|
@ -13,8 +13,8 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
||||
layer.load();
|
||||
},
|
||||
done: function (res, index, upload) {
|
||||
$('#img-icon').attr('src', res.data.src);
|
||||
$('input[name=icon]').val(res.data.src);
|
||||
$('#img-icon').attr('src', res.data.url);
|
||||
$('input[name=icon]').val(res.data.url);
|
||||
layer.closeAll('loading');
|
||||
},
|
||||
error: function (index, upload) {
|
||||
|
@ -18,6 +18,9 @@ layui.use(['jquery'], function () {
|
||||
'superscript', 'subscript', '|', 'image', 'link', 'unlink', '|',
|
||||
'source', 'about'
|
||||
],
|
||||
extraFileUploadParams: {
|
||||
csrf_token: $('meta[name="csrf-token"]').attr('content')
|
||||
}
|
||||
};
|
||||
|
||||
KindEditor.ready(function (K) {
|
||||
|
@ -17,7 +17,6 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
||||
choose: function (obj) {
|
||||
var flag = true;
|
||||
obj.preview(function (index, file, result) {
|
||||
console.log(file);
|
||||
var img = new Image();
|
||||
img.src = result;
|
||||
img.onload = function () {
|
||||
@ -33,8 +32,8 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
||||
});
|
||||
},
|
||||
done: function (res, index, upload) {
|
||||
$('#img-avatar').attr('src', res.data.src);
|
||||
$('input[name=avatar]').val(res.data.src);
|
||||
$('#img-avatar').attr('src', res.data.url);
|
||||
$('input[name=avatar]').val(res.data.url);
|
||||
layer.closeAll('loading');
|
||||
},
|
||||
error: function (index, upload) {
|
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@ layui.define(['jquery', 'layer'], function (exports) {
|
||||
|
||||
helper.getRequestId = function () {
|
||||
var id = Date.now().toString(36);
|
||||
id += Math.random().toString(36).substr(3);
|
||||
id += Math.random().toString(36).substring(3);
|
||||
return id;
|
||||
};
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user