1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-07-15 12:52:21 +08:00

Merge branch 'koogua/v1.4.5'

This commit is contained in:
koogua 2021-10-08 08:41:15 +08:00
commit b29ae1ef2f
196 changed files with 2294 additions and 619 deletions

View File

@ -1,3 +1,19 @@
### [v1.4.5](https://gitee.com/koogua/course-tencent-cloud/releases/v1.4.5)(2021-09-27)
- 修正点击内容分享到微信会额外出现公众号二维码的问题
- 修正后台首页提问和回答的数量统计
- 调整登录限制(邮箱|手机)为注册限制
- 调整订单发货为每一分钟执行一次
- 增强课时安全性,无权限时不返回播放地址或内容
- 抽离出文章关闭,仅我可见操作
- 增加退出群组和解除好友接口
- 增加删除文章和提问接口
- 增加首页推荐教师接口
- 增加微信公众号支付处理
- 增加取消订单功能
- 优化订单API结构
- 优化计划任务
### [v1.4.4](https://gitee.com/koogua/course-tencent-cloud/releases/v1.4.4)(2021-09-17)
- 后台增加邮件手机登录选择配置

View File

@ -58,7 +58,7 @@ class AnswerList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -71,7 +71,7 @@ class ArticleList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -69,6 +69,7 @@ class CategoryTreeList extends Builder
$query->where('parent_id = 0');
$query->andWhere('published = 1');
$query->andWhere('deleted = 0');
$query->andWhere('type = :type:', ['type' => $type]);
$query->orderBy('priority ASC');
@ -84,6 +85,7 @@ class CategoryTreeList extends Builder
$query = CategoryModel::query();
$query->where('published = 1');
$query->where('deleted = 0');
$query->andWhere('parent_id = :parent_id:', ['parent_id' => $parentId]);
$query->orderBy('priority ASC');

View File

@ -32,7 +32,7 @@ class CommentList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -79,7 +79,7 @@ class ConsultList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -62,7 +62,7 @@ class CourseList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -87,7 +87,7 @@ class DanmuList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -29,7 +29,7 @@ class ImMessageList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -48,7 +48,7 @@ class LiveList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($teacherIds, ['id', 'name', 'title', 'avatar', 'about']);
$users = $userRepo->findShallowUserByIds($teacherIds);
$baseUrl = kg_cos_url();

View File

@ -68,6 +68,7 @@ class NavTreeList extends Builder
return NavModel::query()
->where('parent_id = :parent_id:', ['parent_id' => $navId])
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->execute();
}
@ -80,7 +81,9 @@ class NavTreeList extends Builder
{
return NavModel::query()
->where('position = :position:', ['position' => $position])
->andWhere('level = 1 AND published = 1')
->andWhere('level = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->execute();
}

View File

@ -32,7 +32,7 @@ class NotificationList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -7,6 +7,7 @@
namespace App\Builders;
use App\Models\Course as CourseModel;
use App\Models\Order as OrderModel;
use App\Repos\User as UserRepo;
@ -42,7 +43,7 @@ class OrderList extends Builder
public function handleItems(array $orders)
{
foreach ($orders as $key => $order) {
$itemInfo = $this->handleItem($order);
$itemInfo = $this->handleItemInfo($order);
$orders[$key]['item_info'] = $itemInfo;
}
@ -53,7 +54,7 @@ class OrderList extends Builder
* @param array $order
* @return array|mixed
*/
public function handleItem(array $order)
public function handleItemInfo(array $order)
{
$itemInfo = [];
@ -72,6 +73,52 @@ class OrderList extends Builder
return $itemInfo;
}
/**
* @param array $order
* @return array|mixed
*/
public function handleMeInfo(array $order)
{
$me = [
'allow_pay' => 0,
'allow_cancel' => 0,
'allow_refund' => 0,
];
$payStatusOk = $order['status'] == OrderModel::STATUS_PENDING ? 1 : 0;
$cancelStatusOk = $order['status'] == OrderModel::STATUS_PENDING ? 1 : 0;
$refundStatusOk = $order['status'] == OrderModel::STATUS_FINISHED ? 1 : 0;
if ($order['item_type'] == OrderModel::ITEM_COURSE) {
$course = $order['item_info']['course'];
$courseModelOk = $course['model'] != CourseModel::MODEL_OFFLINE;
$refundTimeOk = $course['refund_expiry_time'] > time();
$me['allow_refund'] = $courseModelOk && $refundStatusOk && $refundTimeOk ? 1 : 0;
} elseif ($order['item_type'] == OrderModel::ITEM_PACKAGE) {
$courses = $order['item_info']['courses'];
$refundTimeOk = false;
foreach ($courses as $course) {
if ($course['refund_expiry_time'] > time()) {
$refundTimeOk = true;
}
}
$me['allow_refund'] = $refundStatusOk && $refundTimeOk ? 1 : 0;
}
$me['allow_pay'] = $payStatusOk;
$me['allow_cancel'] = $cancelStatusOk;
return $me;
}
/**
* @param string $itemInfo
* @return mixed
@ -139,7 +186,7 @@ class OrderList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name']);
$users = $userRepo->findShallowUserByIds($ids);
$result = [];

View File

@ -72,7 +72,7 @@ class QuestionFavoriteList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -74,7 +74,7 @@ class QuestionList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -7,6 +7,7 @@
namespace App\Builders;
use App\Models\Refund as RefundModel;
use App\Repos\Order as OrderRepo;
use App\Repos\User as UserRepo;
@ -35,6 +36,24 @@ class RefundList extends Builder
return $refunds;
}
public function handleMeInfo(array $refund)
{
$me = [
'allow_cancel' => 0,
];
$statusTypes = [
RefundModel::STATUS_PENDING,
RefundModel::STATUS_APPROVED,
];
if (in_array($refund['status'], $statusTypes)) {
$me['allow_cancel'] = 1;
}
return $me;
}
public function getOrders(array $trades)
{
$ids = kg_array_column($trades, 'order_id');
@ -58,11 +77,14 @@ class RefundList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();
$result = [];
foreach ($users->toArray() as $user) {
$user['avatar'] = $baseUrl . $user['avatar'];
$result[$user['id']] = $user;
}

View File

@ -29,7 +29,7 @@ class ReportList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -58,7 +58,7 @@ class ReviewList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name', 'avatar']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();

View File

@ -58,11 +58,14 @@ class TradeList extends Builder
$userRepo = new UserRepo();
$users = $userRepo->findByIds($ids, ['id', 'name']);
$users = $userRepo->findShallowUserByIds($ids);
$baseUrl = kg_cos_url();
$result = [];
foreach ($users->toArray() as $user) {
$user['avatar'] = $baseUrl . $user['avatar'];
$result[$user['id']] = $user;
}

View File

@ -38,6 +38,7 @@ class CategoryList extends Cache
->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path'])
->where('type = :type:', ['type' => $type])
->andWhere('published = 1')
->andWhere('deleted = 0')
->execute();
if ($categories->count() == 0) {

View File

@ -70,7 +70,9 @@ class CourseRecommendedList extends Cache
public function findCourses($limit = 5)
{
return CourseModel::query()
->where('published = 1 AND market_price > 0')
->where('market_price > 0')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('RAND()')
->limit($limit)
->execute();

View File

@ -51,6 +51,7 @@ class CourseTeacherList extends Cache
'id' => $user->id,
'name' => $user->name,
'avatar' => $user->avatar,
'vip' => $user->vip,
'title' => $user->title,
'about' => $user->about,
];

View File

@ -73,7 +73,9 @@ class HelpList extends Cache
{
return CategoryModel::query()
->where('type = :type:', ['type' => CategoryModel::TYPE_HELP])
->andWhere('level = 1 AND published = 1')
->andWhere('level = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->execute();
}
@ -87,6 +89,7 @@ class HelpList extends Cache
return HelpModel::query()
->where('category_id = :category_id:', ['category_id' => $categoryId])
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->execute();
}

View File

@ -111,7 +111,8 @@ class HotQuestionList extends Cache
{
return QuestionModel::query()
->where('create_time > :create_time:', ['create_time' => $createTime])
->andWhere('published = 1 AND deleted = 0')
->andWhere('published = :published:', ['published' => QuestionModel::PUBLISH_APPROVED])
->andWhere('deleted = 0')
->orderBy('score DESC')
->limit($limit)
->execute();

View File

@ -72,6 +72,8 @@ class ImActiveGroupList extends Cache
->orderBy('total_count DESC')
->where('receiver_type = :type:', ['type' => ImMessageModel::TYPE_GROUP])
->betweenWhere('create_time', $startTime, $endTime)
->andWhere('published = 1')
->andWhere('deleted = 0')
->limit($limit)
->execute();

View File

@ -70,6 +70,7 @@ class ImNewGroupList extends Cache
{
return ImGroupModel::query()
->where('published = 1')
->andWhere('deleted = 0')
->orderBy('id DESC')
->limit($limit)
->execute();

View File

@ -14,7 +14,7 @@ use App\Services\Logic\Article\ArticleList as ArticleListService;
class IndexArticleList extends Cache
{
protected $lifetime = 1 * 86400;
protected $lifetime = 15 * 60;
public function getLifetime()
{
@ -30,7 +30,10 @@ class IndexArticleList extends Cache
{
$articleRepo = new ArticleRepo();
$where = ['published' => ArticleModel::PUBLISH_APPROVED];
$where = [
'published' => ArticleModel::PUBLISH_APPROVED,
'deleted' => 0,
];
$pager = $articleRepo->paginate($where, 'latest', 1, 10);

View File

@ -94,7 +94,9 @@ class IndexFeaturedCourseList extends Cache
{
return CategoryModel::query()
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->andWhere('level = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->limit($limit)
->execute();
@ -113,8 +115,9 @@ class IndexFeaturedCourseList extends Cache
return CourseModel::query()
->inWhere('category_id', $categoryIds)
->andWhere('published = 1')
->andWhere('featured = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('id DESC')
->limit($limit)
->execute();

View File

@ -0,0 +1,36 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Caches;
use App\Services\Logic\FlashSale\SaleList;
class IndexFlashSaleList extends Cache
{
protected $lifetime = 1 * 86400;
public function getLifetime()
{
return strtotime('tomorrow') - time();
}
public function getKey($id = null)
{
return 'index_flash_sale_list';
}
public function getContent($id = null)
{
$service = new SaleList();
$sales = $service->handle();
return $sales[0]['items'] ?? [];
}
}

View File

@ -94,7 +94,9 @@ class IndexFreeCourseList extends Cache
{
return CategoryModel::query()
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->andWhere('level = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->limit($limit)
->execute();
@ -113,8 +115,9 @@ class IndexFreeCourseList extends Cache
return CourseModel::query()
->inWhere('category_id', $categoryIds)
->andWhere('published = 1')
->andWhere('market_price = 0')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('score DESC')
->limit($limit)
->execute();

View File

@ -132,6 +132,8 @@ class IndexLiveList extends Cache
->addFrom(ChapterLiveModel::class, 'cl')
->join(ChapterModel::class, 'cl.chapter_id = c.id', 'c')
->betweenWhere('start_time', $startTime, $endTime)
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('start_time ASC')
->getQuery()
->execute();

View File

@ -94,7 +94,9 @@ class IndexNewCourseList extends Cache
{
return CategoryModel::query()
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->andWhere('level = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->limit($limit)
->execute();
@ -114,6 +116,7 @@ class IndexNewCourseList extends Cache
return CourseModel::query()
->inWhere('category_id', $categoryIds)
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('id DESC')
->limit($limit)
->execute();

View File

@ -14,7 +14,7 @@ use App\Services\Logic\Question\QuestionList as QuestionListService;
class IndexQuestionList extends Cache
{
protected $lifetime = 1 * 86400;
protected $lifetime = 15 * 60;
public function getLifetime()
{
@ -30,7 +30,10 @@ class IndexQuestionList extends Cache
{
$questionRepo = new QuestionRepo();
$where = ['published' => QuestionModel::PUBLISH_APPROVED];
$where = [
'published' => QuestionModel::PUBLISH_APPROVED,
'deleted' => 0,
];
$pager = $questionRepo->paginate($where, 'latest', 1, 10);

View File

@ -65,8 +65,9 @@ class IndexSimpleFeaturedCourseList extends Cache
protected function findCourses($limit = 8)
{
return CourseModel::query()
->where('published = 1')
->andWhere('featured = 1')
->where('featured = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('id DESC')
->limit($limit)
->execute();

View File

@ -65,8 +65,9 @@ class IndexSimpleFreeCourseList extends Cache
protected function findCourses($limit = 8)
{
return CourseModel::query()
->where('published = 1')
->andWhere('market_price = 0')
->where('market_price = 0')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('score DESC')
->limit($limit)
->execute();

View File

@ -66,6 +66,7 @@ class IndexSimpleNewCourseList extends Cache
{
return CourseModel::query()
->where('published = 1')
->andWhere('deleted = 0')
->orderBy('id DESC')
->limit($limit)
->execute();

View File

@ -65,9 +65,10 @@ class IndexSimpleVipCourseList extends Cache
protected function findCourses($limit = 8)
{
return CourseModel::query()
->where('published = 1')
->andWhere('market_price > vip_price')
->where('market_price > vip_price')
->andWhere('vip_price >= 0')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('score DESC')
->limit($limit)
->execute();

View File

@ -68,6 +68,7 @@ class IndexSlideList extends Cache
{
return SlideModel::query()
->where('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->limit($limit)
->execute();

View File

@ -0,0 +1,69 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Caches;
use App\Models\User as UserModel;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class IndexTeacherList extends Cache
{
protected $lifetime = 1 * 3600;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return 'index_teacher_list';
}
public function getContent($id = null)
{
$teachers = $this->findTeachers();
if ($teachers->count() == 0) return [];
$result = [];
$baseUrl = kg_cos_url();
foreach ($teachers->toArray() as $teacher) {
$teacher['avatar'] = $baseUrl . $teacher['avatar'];
$result[] = [
'id' => $teacher['id'],
'name' => $teacher['name'],
'title' => $teacher['title'],
'avatar' => $teacher['avatar'],
'about' => $teacher['about'],
];
}
return $result;
}
/**
* @param int $limit
* @return ResultsetInterface|Resultset|UserModel[]
*/
protected function findTeachers($limit = 8)
{
return UserModel::query()
->where('edu_role = :edu_role:', ['edu_role' => UserModel::EDU_ROLE_TEACHER])
->andWhere('deleted = 0')
->orderBy('RAND()')
->limit($limit)
->execute();
}
}

View File

@ -94,7 +94,9 @@ class IndexVipCourseList extends Cache
{
return CategoryModel::query()
->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->andWhere('level = 1')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('priority ASC')
->limit($limit)
->execute();
@ -113,9 +115,10 @@ class IndexVipCourseList extends Cache
return CourseModel::query()
->inWhere('category_id', $categoryIds)
->andWhere('published = 1')
->andWhere('market_price > vip_price')
->andWhere('vip_price >= 0')
->andWhere('published = 1')
->andWhere('deleted = 0')
->orderBy('score DESC')
->limit($limit)
->execute();

View File

@ -76,6 +76,7 @@ class PointHotGiftList extends Cache
{
return PointGiftModel::query()
->where('published = 1')
->andWhere('deleted = 0')
->orderBy('redeem_count DESC')
->limit($limit)
->execute();

View File

@ -1,70 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Caches;
use App\Models\Order as OrderModel;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class SaleTrend extends Cache
{
protected $lifetime = 2 * 3600;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return 'sale_trend';
}
public function getContent($id = null)
{
}
/**
* @param OrderModel[] $sales
* @param int $days
* @return array
*/
protected function handleSales($sales, $days = 7)
{
$result = [];
foreach (array_reverse(range(1, $days)) as $num) {
$date = date('Y-m-d', strtotime("-{$num} days"));
$result[$date] = 0;
}
foreach ($sales as $sale) {
$date = date('Y-m-d', $sale->create_time);
$result[$date] += $sale->amount;
}
return $result;
}
/**
* @param int $days
* @return ResultsetInterface|Resultset|OrderModel[]
*/
protected function findSales($days = 7)
{
$time = strtotime("-{$days} days");
return OrderModel::query()
->where('status = :status:', ['status' => OrderModel::STATUS_FINISHED])
->andWhere('create_time > :time:', ['time' => $time])
->execute();
}
}

View File

@ -7,12 +7,14 @@
namespace App\Caches;
use App\Repos\Answer as AnswerRepo;
use App\Repos\Article as ArticleRepo;
use App\Repos\Comment as CommentRepo;
use App\Repos\Consult as ConsultRepo;
use App\Repos\Course as CourseRepo;
use App\Repos\ImGroup as GroupRepo;
use App\Repos\Package as PackageRepo;
use App\Repos\Question as QuestionRepo;
use App\Repos\Review as ReviewRepo;
use App\Repos\Topic as TopicRepo;
use App\Repos\User as UserRepo;
@ -36,6 +38,8 @@ class SiteGlobalStat extends Cache
{
$courseRepo = new CourseRepo();
$articleRepo = new ArticleRepo();
$questionRepo = new QuestionRepo();
$answerRepo = new AnswerRepo();
$commentRepo = new CommentRepo();
$consultRepo = new ConsultRepo();
$groupRepo = new GroupRepo();
@ -47,6 +51,8 @@ class SiteGlobalStat extends Cache
return [
'course_count' => $courseRepo->countCourses(),
'article_count' => $articleRepo->countArticles(),
'question_count' => $questionRepo->countQuestions(),
'answer_count' => $answerRepo->countAnswers(),
'comment_count' => $commentRepo->countComments(),
'consult_count' => $consultRepo->countConsults(),
'group_count' => $groupRepo->countGroups(),

View File

@ -34,6 +34,7 @@ class TaggedArticleList extends Cache
$where = [
'tag_id' => $id,
'published' => ArticleModel::PUBLISH_APPROVED,
'deleted' => 0,
];
$pager = $articleRepo->paginate($where);

View File

@ -35,6 +35,7 @@ class TaggedQuestionList extends Cache
$where = [
'tag_id' => $id,
'published' => QuestionModel::PUBLISH_APPROVED,
'deleted' => 0,
];
$pager = $questionRepo->paginate($where);

View File

@ -124,6 +124,7 @@ class ArticleIndexTask extends Task
{
return ArticleModel::query()
->where('published = :published:', ['published' => ArticleModel::PUBLISH_APPROVED])
->andWhere('deleted = 0')
->execute();
}

View File

@ -124,6 +124,7 @@ class CourseIndexTask extends Task
{
return CourseModel::query()
->where('published = 1')
->where('deleted = 0')
->execute();
}

View File

@ -293,11 +293,11 @@ class DeliverTask extends Task
* @param int $limit
* @return ResultsetInterface|Resultset|TaskModel[]
*/
protected function findTasks($limit = 30)
protected function findTasks($limit = 100)
{
$itemType = TaskModel::TYPE_DELIVER;
$status = TaskModel::STATUS_PENDING;
$createTime = strtotime('-3 days');
$createTime = strtotime('-1 days');
return TaskModel::query()
->where('item_type = :item_type:', ['item_type' => $itemType])

View File

@ -124,6 +124,7 @@ class GroupIndexTask extends Task
{
return GroupModel::query()
->where('published = 1')
->andWhere('deleted = 0')
->execute();
}

View File

@ -84,7 +84,7 @@ class NoticeTask extends Task
$task->update();
$logger->info('Notice Process Exception ' . kg_json_encode([
$logger->error('Notice Process Exception ' . kg_json_encode([
'file' => $e->getFile(),
'line' => $e->getLine(),
'message' => $e->getMessage(),

View File

@ -124,6 +124,7 @@ class QuestionIndexTask extends Task
{
return QuestionModel::query()
->where('published = :published:', ['published' => QuestionModel::PUBLISH_APPROVED])
->andWhere('deleted = 0')
->execute();
}

View File

@ -139,6 +139,7 @@ class UserIndexTask extends Task
protected function findUsers($limit, $offset)
{
return UserModel::query()
->where('deleted = 0')
->limit($limit, $offset)
->execute();
}

View File

@ -1205,7 +1205,7 @@ class AuthNode extends Service
],
[
'id' => '5-1-12',
'title' => '登录设置',
'title' => '注册登录',
'type' => 'menu',
'route' => 'admin.setting.oauth',
],

View File

@ -59,13 +59,13 @@
<div class="layui-col-md2">
<div class="kg-stat-card">
<div class="name">提问数</div>
<div class="count">0</div>
<div class="count">{{ global_stat.question_count }}</div>
</div>
</div>
<div class="layui-col-md2">
<div class="kg-stat-card">
<div class="name">回答数</div>
<div class="count">0</div>
<div class="count">{{ global_stat.answer_count }}</div>
</div>
</div>
<div class="layui-col-md2">

View File

@ -4,7 +4,7 @@
<div class="layui-tab layui-tab-brief">
<ul class="layui-tab-title kg-tab-title">
<li class="layui-this">本地登录</li>
<li class="layui-this">注册设置</li>
<li>QQ登录</li>
<li>微信登录</li>
<li>微博登录</li>

View File

@ -1,16 +1,16 @@
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.oauth'}) }}">
<div class="layui-form-item">
<label class="layui-form-label">开启手机登录</label>
<label class="layui-form-label">开启手机注册</label>
<div class="layui-input-block">
<input type="radio" name="login_with_phone" value="1" title="是" {% if local_auth.login_with_phone == "1" %}checked="checked"{% endif %}>
<input type="radio" name="login_with_phone" value="0" title="否" {% if local_auth.login_with_phone == "0" %}checked="checked"{% endif %}>
<input type="radio" name="register_with_phone" value="1" title="是" {% if local_auth.register_with_phone == "1" %}checked="checked"{% endif %}>
<input type="radio" name="register_with_phone" value="0" title="否" {% if local_auth.register_with_phone == "0" %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">开启邮箱登录</label>
<label class="layui-form-label">开启邮箱注册</label>
<div class="layui-input-block">
<input type="radio" name="login_with_email" value="1" title="是" {% if local_auth.login_with_email == "1" %}checked="checked"{% endif %}>
<input type="radio" name="login_with_email" value="0" title="否" {% if local_auth.login_with_email == "0" %}checked="checked"{% endif %}>
<input type="radio" name="register_with_email" value="1" title="是" {% if local_auth.register_with_email == "1" %}checked="checked"{% endif %}>
<input type="radio" name="register_with_email" value="0" title="否" {% if local_auth.register_with_email == "0" %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">

View File

@ -7,6 +7,7 @@
namespace App\Http\Api\Controllers;
use App\Models\Answer as AnswerModel;
use App\Services\Logic\Answer\AnswerAccept as AnswerAcceptService;
use App\Services\Logic\Answer\AnswerCreate as AnswerCreateService;
use App\Services\Logic\Answer\AnswerDelete as AnswerDeleteService;
@ -30,6 +31,17 @@ class AnswerController extends Controller
$answer = $service->handle($id);
if ($answer['deleted'] == 1) {
$this->notFound();
}
$approved = $answer['published'] != AnswerModel::PUBLISH_APPROVED;
$owned = $answer['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
return $this->jsonSuccess(['answer' => $answer]);
}
@ -82,7 +94,7 @@ class AnswerController extends Controller
$service->handle($id);
return $this->jsonSuccess(['msg' => '删除回答成功']);
return $this->jsonSuccess();
}
/**

View File

@ -7,10 +7,14 @@
namespace App\Http\Api\Controllers;
use App\Models\Article as ArticleModel;
use App\Services\Logic\Article\ArticleClose as ArticleCloseService;
use App\Services\Logic\Article\ArticleDelete as ArticleDeleteService;
use App\Services\Logic\Article\ArticleFavorite as ArticleFavoriteService;
use App\Services\Logic\Article\ArticleInfo as ArticleInfoService;
use App\Services\Logic\Article\ArticleLike as ArticleLikeService;
use App\Services\Logic\Article\ArticleList as ArticleListService;
use App\Services\Logic\Article\ArticlePrivate as ArticlePrivateService;
use App\Services\Logic\Article\CategoryList as CategoryListService;
use App\Services\Logic\Article\CommentList as CommentListService;
@ -53,6 +57,22 @@ class ArticleController extends Controller
$article = $service->handle($id);
if ($article['deleted'] == 1) {
$this->notFound();
}
$approved = $article['published'] == ArticleModel::PUBLISH_APPROVED;
$owned = $article['me']['owned'] == 1;
$private = $article['private'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
if ($private && !$owned) {
$this->forbidden();
}
return $this->jsonSuccess(['article' => $article]);
}
@ -68,6 +88,46 @@ class ArticleController extends Controller
return $this->jsonPaginate($pager);
}
/**
* @Post("/{id:[0-9]+}/delete", name="api.article.delete")
*/
public function deleteAction($id)
{
$service = new ArticleDeleteService();
$service->handle($id);
return $this->jsonSuccess();
}
/**
* @Post("/{id:[0-9]+}/close", name="home.article.close")
*/
public function closeAction($id)
{
$service = new ArticleCloseService();
$article = $service->handle($id);
$msg = $article->closed == 1 ? '关闭评论成功' : '开启评论成功';
return $this->jsonSuccess(['msg' => $msg]);
}
/**
* @Post("/{id:[0-9]+}/private", name="home.article.private")
*/
public function privateAction($id)
{
$service = new ArticlePrivateService();
$article = $service->handle($id);
$msg = $article->private == 1 ? '开启仅我可见成功' : '关闭仅我可见成功';
return $this->jsonSuccess(['msg' => $msg]);
}
/**
* @Post("/{id:[0-9]+}/favorite", name="api.article.favorite")
*/

View File

@ -65,8 +65,16 @@ class ChapterController extends Controller
$chapter = $service->handle($id);
if ($chapter['deleted'] == 1) {
$this->notFound();
}
if ($chapter['published'] == 0) {
$this->notFound();
}
if ($chapter['me']['owned'] == 0) {
return $this->jsonError(['msg' => '没有访问章节权限']);
$this->forbidden();
}
return $this->jsonSuccess(['chapter' => $chapter]);

View File

@ -85,7 +85,7 @@ class CommentController extends Controller
$service->handle($id);
return $this->jsonSuccess(['msg' => '删除评论成功']);
return $this->jsonSuccess();
}
/**

View File

@ -0,0 +1,74 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Api\Controllers;
use App\Http\Api\Services\Connect as ConnectService;
use App\Models\Connect as ConnectModel;
/**
* @RoutePrefix("/api/oauth")
*/
class ConnectController extends Controller
{
/**
* @Get("/wechat", name="api.oauth.wechat")
*/
public function wechatAction()
{
$redirect = $this->request->getQuery('redirect', 'trim');
$service = new ConnectService();
if ($redirect) {
$service->setWechatRedirectCache($redirect);
}
$url = $service->getAuthorizeUrl(ConnectModel::PROVIDER_WECHAT);
return $this->response->redirect($url, true);
}
/**
* @Get("/wechat/callback", name="api.oauth.wechat_callback")
*/
public function wechatCallbackAction()
{
$service = new ConnectService();
$data = $service->handleCallback(ConnectModel::PROVIDER_WECHAT);
$redirect = $service->getWechatRedirectCache();
if ($redirect) {
$service->removeWechatRedirectCache();
if (strpos($redirect, '?')) {
$location = $redirect . '&' . http_build_query($data);
} else {
$location = $redirect . '?' . http_build_query($data);
}
} else {
$location = kg_h5_index_url() . '?' . http_build_query($data);
}
return $this->response->redirect($location, true);
}
/**
* @Get("/wechat/info", name="api.oauth.wechat_info")
*/
public function wechatInfoAction()
{
$service = new ConnectService();
$wechat = $service->getWechatInfo();
return $this->jsonSuccess(['wechat' => $wechat]);
}
}

View File

@ -7,6 +7,7 @@
namespace App\Http\Api\Controllers;
use App\Models\Consult as ConsultModel;
use App\Services\Logic\Consult\ConsultCreate as ConsultCreateService;
use App\Services\Logic\Consult\ConsultDelete as ConsultDeleteService;
use App\Services\Logic\Consult\ConsultInfo as ConsultInfoService;
@ -28,6 +29,17 @@ class ConsultController extends Controller
$consult = $service->handle($id);
if ($consult['deleted'] == 1) {
$this->notFound();
}
$approved = $consult['published'] == ConsultModel::PUBLISH_APPROVED;
$owned = $consult['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
return $this->jsonSuccess(['consult' => $consult]);
}

View File

@ -11,6 +11,7 @@ use App\Models\User as UserModel;
use App\Services\Auth\Api as ApiAuth;
use App\Traits\Response as ResponseTrait;
use App\Traits\Security as SecurityTrait;
use App\Validators\Validator as AppValidator;
use Phalcon\Mvc\Dispatcher;
class Controller extends \Phalcon\Mvc\Controller
@ -30,6 +31,10 @@ class Controller extends \Phalcon\Mvc\Controller
$this->setCors();
}
$validator = new AppValidator();
$validator->checkSiteStatus();
$this->checkRateLimit();
return true;

View File

@ -55,6 +55,14 @@ class CourseController extends Controller
$course = $service->handle($id);
if ($course['deleted'] == 1) {
$this->notFound();
}
if ($course['published'] == 0) {
$this->notFound();
}
return $this->jsonSuccess(['course' => $course]);
}

View File

@ -37,6 +37,14 @@ class HelpController extends Controller
$help = $service->handle($id);
if ($help['deleted'] == 1) {
$this->notFound();
}
if ($help['published'] == 0) {
$this->notFound();
}
return $this->jsonSuccess(['help' => $help]);
}

View File

@ -0,0 +1,30 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Api\Controllers;
use App\Services\Logic\Im\FriendQuit as FriendQuitService;
/**
* @RoutePrefix("/api/im/friend")
*/
class ImFriendController extends Controller
{
/**
* @Post("/{id:[0-9]+}/quit", name="api.im_friend.quit")
*/
public function quitAction($id)
{
$service = new FriendQuitService();
$service->handle($id);
return $this->jsonSuccess();
}
}

View File

@ -9,6 +9,7 @@ namespace App\Http\Api\Controllers;
use App\Services\Logic\Im\GroupInfo as GroupInfoService;
use App\Services\Logic\Im\GroupList as GroupListService;
use App\Services\Logic\Im\GroupQuit as GroupQuitService;
use App\Services\Logic\Im\GroupUserList as GroupUserListService;
/**
@ -38,6 +39,14 @@ class ImGroupController extends Controller
$group = $service->handle($id);
if ($group['deleted'] == 1) {
$this->notFound();
}
if ($group['published'] == 0) {
$this->notFound();
}
return $this->jsonSuccess(['group' => $group]);
}
@ -53,4 +62,16 @@ class ImGroupController extends Controller
return $this->jsonPaginate($pager);
}
/**
* @Post("/{id:[0-9]+}/quit", name="api.im_group.quit")
*/
public function quitAction($id)
{
$service = new GroupQuitService();
$service->handle($id);
return $this->jsonSuccess();
}
}

View File

@ -8,6 +8,7 @@
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;
@ -15,6 +16,7 @@ use App\Caches\IndexSimpleFreeCourseList;
use App\Caches\IndexSimpleNewCourseList;
use App\Caches\IndexSimpleVipCourseList;
use App\Caches\IndexSlideList;
use App\Caches\IndexTeacherList;
/**
* @RoutePrefix("/api/index")
@ -70,6 +72,30 @@ class IndexController extends Controller
return $this->jsonSuccess(['lives' => $lives]);
}
/**
* @Get("/teachers", name="api.index.teachers")
*/
public function teachersAction()
{
$cache = new IndexTeacherList();
$teachers = $cache->get();
return $this->jsonSuccess(['teachers' => $teachers]);
}
/**
* @Get("/flash/sales", name="api.index.flash_sales")
*/
public function flashSalesAction()
{
$cache = new IndexFlashSaleList();
$sales = $cache->get();
return $this->jsonSuccess(['sales' => $sales]);
}
/**
* @Get("/courses/featured", name="api.index.featured_courses")
*/

View File

@ -29,6 +29,10 @@ class OrderController extends Controller
$order = $service->handle($sn);
if ($order['deleted'] == 1) {
$this->notFound();
}
return $this->jsonSuccess(['order' => $order]);
}

View File

@ -24,6 +24,14 @@ class PageController extends Controller
$page = $service->handle($id);
if ($page['deleted'] == 1) {
$this->notFound();
}
if ($page['published'] == 0) {
$this->notFound();
}
return $this->jsonSuccess(['page' => $page]);
}

View File

@ -49,8 +49,12 @@ class PublicController extends Controller
$content = [];
/**
* ssl通过nginx转发实现
*/
if ($this->request->isSecure()) {
$content['connect_url'] = sprintf('wss://%s/wss', $this->request->getHttpHost());
list($domain) = explode(':', $websocket->connect_address);
$content['connect_url'] = sprintf('wss://%s/wss', $domain);
} else {
$content['connect_url'] = sprintf('ws://%s', $websocket->connect_address);
}

View File

@ -7,9 +7,11 @@
namespace App\Http\Api\Controllers;
use App\Models\Question as QuestionModel;
use App\Services\Logic\Question\AnswerList as AnswerListService;
use App\Services\Logic\Question\CategoryList as CategoryListService;
use App\Services\Logic\Question\CommentList as CommentListService;
use App\Services\Logic\Question\QuestionDelete as QuestionDeleteService;
use App\Services\Logic\Question\QuestionFavorite as QuestionFavoriteService;
use App\Services\Logic\Question\QuestionInfo as QuestionInfoService;
use App\Services\Logic\Question\QuestionLike as QuestionLikeService;
@ -54,6 +56,17 @@ class QuestionController extends Controller
$question = $service->handle($id);
if ($question['deleted'] == 1) {
$this->notFound();
}
$approved = $question['published'] == QuestionModel::PUBLISH_APPROVED;
$owned = $question['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
return $this->jsonSuccess(['question' => $question]);
}
@ -81,6 +94,18 @@ class QuestionController extends Controller
return $this->jsonPaginate($pager);
}
/**
* @Post("/{id:[0-9]+}/delete", name="api.question.delete")
*/
public function deleteAction($id)
{
$service = new QuestionDeleteService();
$service->handle($id);
return $this->jsonSuccess();
}
/**
* @Post("/{id:[0-9]+}/favorite", name="api.question.favorite")
*/

View File

@ -43,6 +43,14 @@ class RefundController extends Controller
$refund = $service->handle($sn);
if ($refund['deleted'] == 1) {
$this->notFound();
}
if ($refund['me']['owned'] == 0) {
$this->forbidden();
}
return $this->jsonSuccess(['refund' => $refund]);
}

View File

@ -7,6 +7,7 @@
namespace App\Http\Api\Controllers;
use App\Models\Review as ReviewModel;
use App\Services\Logic\Review\ReviewCreate as ReviewCreateService;
use App\Services\Logic\Review\ReviewDelete as ReviewDeleteService;
use App\Services\Logic\Review\ReviewInfo as ReviewInfoService;
@ -28,6 +29,17 @@ class ReviewController extends Controller
$review = $service->handle($id);
if ($review['deleted'] == 1) {
$this->notFound();
}
$approved = $review['published'] == ReviewModel::PUBLISH_APPROVED;
$owned = $review['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
return $this->jsonSuccess(['review' => $review]);
}

View File

@ -27,6 +27,14 @@ class TradeController extends Controller
$trade = $service->handle($sn);
if ($trade['deleted'] == 1) {
$this->notFound();
}
if ($trade['me']['owned'] == 0) {
$this->forbidden();
}
return $this->jsonSuccess(['trade' => $trade]);
}
@ -54,6 +62,18 @@ class TradeController extends Controller
return $this->jsonSuccess($content);
}
/**
* @Post("/mini/create", name="api.trade.mini_create")
*/
public function createMiniTradeAction()
{
$service = new TradeService();
$content = $service->createMiniTrade();
return $this->jsonSuccess($content);
}
/**
* @Post("/app/create", name="api.trade.app_create")
*/
@ -61,7 +81,7 @@ class TradeController extends Controller
{
$service = new TradeService();
$content = $service->createMpTrade();
$content = $service->createAppTrade();
return $this->jsonSuccess($content);
}

View File

@ -30,6 +30,10 @@ class UserController extends Controller
$user = $service->handle($id);
if ($user['deleted'] == 1) {
$this->notFound();
}
return $this->jsonSuccess(['user' => $user]);
}

View File

@ -0,0 +1,210 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Api\Services;
use App\Models\Connect as ConnectModel;
use App\Models\User as UserModel;
use App\Repos\Connect as ConnectRepo;
use App\Repos\User as UserRepo;
use App\Services\Auth\Api as ApiAuthService;
use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
use App\Services\OAuth\QQ as QQAuth;
use App\Services\OAuth\WeChat as WeChatAuth;
use App\Services\OAuth\WeiBo as WeiBoAuth;
use Exception;
class Connect extends Service
{
public function getWechatInfo()
{
return [
'auth_url' => kg_full_url(['for' => 'api.oauth.wechat']),
'auto_login' => 1,
];
}
public function getWechatRedirectCache()
{
return $this->session->get('wechat_redirect');
}
public function setWechatRedirectCache($redirect)
{
$this->session->set('wechat_redirect', $redirect);
}
public function removeWechatRedirectCache()
{
$this->session->remove('wechat_redirect');
}
public function handleCallback($provider)
{
$code = $this->request->getQuery('code');
$state = $this->request->getQuery('state');
$openUser = $this->getOpenUserInfo($code, $state, $provider);
$relation = $this->getConnectRelation($openUser['id'], $provider);
$token = null;
if ($relation) {
$userRepo = new UserRepo();
$user = $userRepo->findById($relation->user_id);
$auth = new ApiAuthService();
$token = $auth->saveAuthInfo($user);
$this->handleLoginNotice($user);
}
return [
'openid' => $openUser['id'],
'token' => $token,
];
}
public function getAuthorizeUrl($provider)
{
$auth = $this->getConnectAuth($provider);
return $auth->getAuthorizeUrl();
}
public function getOpenUserInfo($code, $state, $provider)
{
$auth = $this->getConnectAuth($provider);
$auth->checkState($state);
$token = $auth->getAccessToken($code);
$openId = $auth->getOpenId($token);
return $auth->getUserInfo($token, $openId);
}
public function getConnectRelation($openId, $provider)
{
$connectRepo = new ConnectRepo();
return $connectRepo->findByOpenId($openId, $provider);
}
public function getConnectAuth($provider)
{
$auth = null;
switch ($provider) {
case ConnectModel::PROVIDER_QQ:
$auth = $this->getQQAuth();
break;
case ConnectModel::PROVIDER_WEIBO:
$auth = $this->getWeiBoAuth();
break;
case ConnectModel::PROVIDER_WECHAT:
$auth = $this->getWeChatAuth();
break;
}
if (!$auth) {
throw new Exception('Invalid OAuth Provider');
}
return $auth;
}
protected function getQQAuth()
{
$settings = $this->getSettings('oauth.qq');
$settings['redirect_uri'] = kg_full_url(['for' => 'api.oauth.qq_callback']);
return new QQAuth(
$settings['client_id'],
$settings['client_secret'],
$settings['redirect_uri']
);
}
protected function getWeChatAuth()
{
/**
* 使用的是微信公众号网页授权登录功能
*/
$settings = $this->getSettings('wechat.oa');
$settings['redirect_uri'] = kg_full_url(['for' => 'api.oauth.wechat_callback']);
return new WeChatAuth(
$settings['app_id'],
$settings['app_secret'],
$settings['redirect_uri']
);
}
protected function getWeiBoAuth()
{
$settings = $this->getSettings('oauth.weibo');
$settings['redirect_uri'] = kg_full_url(['for' => 'api.oauth.weibo_callback']);
return new WeiBoAuth(
$settings['client_id'],
$settings['client_secret'],
$settings['redirect_uri']
);
}
protected function handleConnectRelation(UserModel $user, array $openUser)
{
$connectRepo = new ConnectRepo();
$connect = $connectRepo->findByOpenId($openUser['id'], $openUser['provider']);
if ($connect) {
$connect->open_name = $openUser['name'];
$connect->open_avatar = $openUser['avatar'];
if ($connect->user_id != $user->id) {
$connect->user_id = $user->id;
}
if ($connect->deleted == 1) {
$connect->deleted = 0;
}
$connect->update();
} else {
$connect = new ConnectModel();
$connect->user_id = $user->id;
$connect->open_id = $openUser['id'];
$connect->open_name = $openUser['name'];
$connect->open_avatar = $openUser['avatar'];
$connect->provider = $openUser['provider'];
$connect->create();
}
}
protected function handleLoginNotice(UserModel $user)
{
$service = new AccountLoginNoticeService();
$service->createTask($user);
}
}

View File

@ -75,6 +75,45 @@ class Trade extends Service
{
$post = $this->request->getPost();
$order = $this->checkOrderBySn($post['order_sn']);
$user = $this->getLoginUser();
$channel = TradeModel::CHANNEL_WXPAY;
$trade = new TradeModel();
$trade->subject = $order->subject;
$trade->amount = $order->amount;
$trade->channel = $channel;
$trade->order_id = $order->id;
$trade->owner_id = $user->id;
$trade->create();
$wxpay = new Wxpay();
$response = $wxpay->mp($trade, $post['open_id']);
$payment = [
'appId' => $response->appId,
'timeStamp' => $response->timeStamp,
'nonceStr' => $response->nonceStr,
'package' => $response->package,
'signType' => $response->signType,
'paySign' => $response->paySign,
];
return [
'trade' => $this->handleTradeInfo($trade->sn),
'payment' => $payment,
];
}
public function createMiniTrade()
{
$post = $this->request->getPost();
$validator = new ClientValidator();
$platform = $this->getPlatform();
@ -120,7 +159,7 @@ class Trade extends Service
public function createAppTrade()
{
return [];
}
protected function getPlatform()

View File

@ -28,6 +28,10 @@ class AccountController extends Controller
$returnUrl = $this->request->getHTTPReferer();
$service = new OAuthProviderService();
$oauthProvider = $service->handle();
$service = new AccountService();
$captcha = $service->getSettings('captcha');
@ -35,6 +39,7 @@ class AccountController extends Controller
$this->seo->prependTitle('注册');
$this->view->setVar('return_url', $returnUrl);
$this->view->setVar('local_oauth', $oauthProvider['local']);
$this->view->setVar('captcha', $captcha);
}

View File

@ -57,8 +57,15 @@ class AnswerController extends Controller
$answer = $service->handle($id);
if ($answer['published'] != AnswerModel::PUBLISH_APPROVED) {
return $this->notFound();
if ($answer['deleted'] == 1) {
$this->notFound();
}
$approved = $answer['published'] != AnswerModel::PUBLISH_APPROVED;
$owned = $answer['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
$questionId = $answer['question']['id'];

View File

@ -10,12 +10,14 @@ namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Article as ArticleService;
use App\Http\Home\Services\ArticleQuery as ArticleQueryService;
use App\Models\Article as ArticleModel;
use App\Services\Logic\Article\ArticleClose as ArticleCloseService;
use App\Services\Logic\Article\ArticleCreate as ArticleCreateService;
use App\Services\Logic\Article\ArticleDelete as ArticleDeleteService;
use App\Services\Logic\Article\ArticleFavorite as ArticleFavoriteService;
use App\Services\Logic\Article\ArticleInfo as ArticleInfoService;
use App\Services\Logic\Article\ArticleLike as ArticleLikeService;
use App\Services\Logic\Article\ArticleList as ArticleListService;
use App\Services\Logic\Article\ArticlePrivate as ArticlePrivateService;
use App\Services\Logic\Article\ArticleUpdate as ArticleUpdateService;
use App\Services\Logic\Article\RelatedArticleList as RelatedArticleListService;
use Phalcon\Mvc\View;
@ -103,8 +105,20 @@ class ArticleController extends Controller
$article = $service->handle($id);
if ($article['published'] != ArticleModel::PUBLISH_APPROVED) {
return $this->notFound();
if ($article['deleted'] == 1) {
$this->notFound();
}
$approved = $article['published'] == ArticleModel::PUBLISH_APPROVED;
$owned = $article['me']['owned'] == 1;
$private = $article['private'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
if ($private && !$owned) {
$this->forbidden();
}
$this->seo->prependTitle(['专栏', $article['title']]);
@ -195,6 +209,34 @@ class ArticleController extends Controller
return $this->jsonSuccess($content);
}
/**
* @Post("/{id:[0-9]+}/close", name="home.article.close")
*/
public function closeAction($id)
{
$service = new ArticleCloseService();
$article = $service->handle($id);
$msg = $article->closed == 1 ? '关闭评论成功' : '开启评论成功';
return $this->jsonSuccess(['msg' => $msg]);
}
/**
* @Post("/{id:[0-9]+}/private", name="home.article.private")
*/
public function privateAction($id)
{
$service = new ArticlePrivateService();
$article = $service->handle($id);
$msg = $article->private == 1 ? '开启仅我可见成功' : '关闭仅我可见成功';
return $this->jsonSuccess(['msg' => $msg]);
}
/**
* @Post("/{id:[0-9]+}/favorite", name="home.article.favorite")
*/

View File

@ -39,20 +39,24 @@ class ChapterController extends Controller
*/
public function showAction($id)
{
$service = new ChapterInfoService();
$chapter = $service->handle($id);
if ($chapter['published'] == 0) {
return $this->notFound();
}
if ($this->authUser->id == 0) {
return $this->response->redirect(['for' => 'home.account.login']);
}
$service = new ChapterInfoService();
$chapter = $service->handle($id);
if ($chapter['deleted'] == 1) {
$this->notFound();
}
if ($chapter['published'] == 0) {
$this->notFound();
}
if ($chapter['me']['owned'] == 0) {
return $this->forbidden();
$this->forbidden();
}
$service = new CourseInfoService();

View File

@ -119,6 +119,19 @@ class ConnectController extends Controller
$service = new ConnectService();
$openUser = $service->getOpenUserInfo($code, $state, $provider);
/**
* 微信扫码登录检查是否关注过公众号,关注过直接登录
*/
if ($provider == ConnectModel::PROVIDER_WEIXIN && !empty($openUser['unionid'])) {
$subscribe = $service->getWeChatSubscribe($openUser['unionid']);
if ($subscribe && $subscribe->deleted == 0) {
$service->authSubscribeLogin($subscribe);
return $this->response->redirect(['for' => 'home.index']);
}
}
$openUser = $service->getOpenUserInfo($code, $state, $provider);
$connect = $service->getConnectRelation($openUser['id'], $openUser['provider']);
@ -129,7 +142,7 @@ class ConnectController extends Controller
}
} else {
if ($connect) {
$service->authLogin($connect);
$service->authConnectLogin($connect);
return $this->response->redirect(['for' => 'home.index']);
}
}

View File

@ -7,6 +7,7 @@
namespace App\Http\Home\Controllers;
use App\Models\Consult as ConsultModel;
use App\Services\Logic\Consult\ConsultCreate as ConsultCreateService;
use App\Services\Logic\Consult\ConsultDelete as ConsultDeleteService;
use App\Services\Logic\Consult\ConsultInfo as ConsultInfoService;
@ -37,6 +38,17 @@ class ConsultController extends Controller
$consult = $service->handle($id);
if ($consult['deleted'] == 1) {
$this->notFound();
}
$approved = $consult['published'] == ConsultModel::PUBLISH_APPROVED;
$owned = $consult['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
$this->view->setVar('consult', $consult);
}

View File

@ -147,7 +147,8 @@ class Controller extends \Phalcon\Mvc\Controller
* ssl通过nginx转发实现
*/
if ($this->request->isSecure()) {
$websocket->connect_url = sprintf('wss://%s/wss', $this->request->getHttpHost());
list($domain) = explode(':', $websocket->connect_address);
$websocket->connect_url = sprintf('wss://%s/wss', $domain);
} else {
$websocket->connect_url = sprintf('ws://%s', $websocket->connect_address);
}

View File

@ -77,8 +77,12 @@ class CourseController extends Controller
$course = $service->handle($id);
if ($course['deleted'] == 1) {
$this->notFound();
}
if ($course['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$service = new CourseChapterListService();

View File

@ -40,8 +40,12 @@ class HelpController extends Controller
$help = $service->handle($id);
if ($help['deleted'] == 1) {
$this->notFound();
}
if ($help['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$featuredCourses = $this->getFeaturedCourses();

View File

@ -145,7 +145,7 @@ class ImController extends Controller
}
/**
* @Post("/notice/read", name="home.im.read_notice")
* @Get("/notice/read", name="home.im.read_notice")
*/
public function readNoticeAction()
{

View File

@ -51,8 +51,12 @@ class ImGroupController extends Controller
$group = $service->getGroup($id);
if ($group['deleted'] == 1) {
$this->notFound();
}
if ($group['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$this->seo->prependTitle(['群组', $group['name']]);

View File

@ -45,6 +45,14 @@ class OrderController extends Controller
$order = $service->handle($sn);
if ($order['deleted'] == 1) {
$this->notFound();
}
if ($order['me']['owned'] == 0) {
$this->forbidden();
}
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
$this->view->setVar('order', $order);
}

View File

@ -27,7 +27,7 @@ class PackageController extends Controller
$package = $service->handle($id);
if ($package['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$this->seo->prependTitle(['套餐', $package['title']]);

View File

@ -25,8 +25,12 @@ class PageController extends Controller
$page = $service->handle($id);
if ($page['deleted'] == 1) {
$this->notFound();
}
if ($page['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$featuredCourses = $this->getFeaturedCourses();

View File

@ -68,8 +68,12 @@ class PointGiftController extends Controller
$gift = $service->handle($id);
if ($gift['deleted'] == 1) {
$this->notFound();
}
if ($gift['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$hotGifts = $this->getHotGifts();

View File

@ -102,8 +102,15 @@ class QuestionController extends Controller
$question = $service->handle($id);
if ($question['published'] != QuestionModel::PUBLISH_APPROVED) {
return $this->notFound();
if ($question['deleted'] == 1) {
$this->notFound();
}
$approved = $question['published'] == QuestionModel::PUBLISH_APPROVED;
$owned = $question['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
$this->seo->prependTitle(['问答', $question['title']]);

View File

@ -63,6 +63,14 @@ class RefundController extends Controller
$refund = $service->handle($sn);
if ($refund['deleted'] == 1) {
$this->notFound();
}
if ($refund['me']['owned'] == 0) {
$this->forbidden();
}
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
$this->view->setVar('refund', $refund);
}

View File

@ -7,6 +7,7 @@
namespace App\Http\Home\Controllers;
use App\Models\Review as ReviewModel;
use App\Services\Logic\Review\ReviewCreate as ReviewCreateService;
use App\Services\Logic\Review\ReviewDelete as ReviewDeleteService;
use App\Services\Logic\Review\ReviewInfo as ReviewInfoService;
@ -50,6 +51,17 @@ class ReviewController extends Controller
$review = $service->handle($id);
if ($review['deleted'] == 1) {
$this->notFound();
}
$approved = $review['published'] == ReviewModel::PUBLISH_APPROVED;
$owned = $review['me']['owned'] == 1;
if (!$approved && !$owned) {
$this->notFound();
}
return $this->jsonSuccess(['review' => $review]);
}

View File

@ -27,7 +27,7 @@ class TopicController extends Controller
$topic = $service->handle($id);
if ($topic['published'] == 0) {
return $this->notFound();
$this->notFound();
}
$this->seo->prependTitle(['专题', $topic['title']]);

View File

@ -32,7 +32,7 @@ class UserController extends Controller
$user = $service->handle($id);
if ($user['deleted'] == 1) {
return $this->notFound();
$this->notFound();
}
$this->seo->prependTitle(['空间', $user['name']]);

View File

@ -9,11 +9,14 @@ namespace App\Http\Home\Services;
use App\Models\Connect as ConnectModel;
use App\Models\User as UserModel;
use App\Models\WeChatSubscribe as WeChatSubscribeModel;
use App\Repos\Connect as ConnectRepo;
use App\Repos\User as UserRepo;
use App\Repos\WeChatSubscribe as WeChatSubscribeRepo;
use App\Services\Auth\Home as AuthService;
use App\Services\Auth\Home as HomeAuthService;
use App\Services\Logic\Account\Register as RegisterService;
use App\Services\Logic\Notice\AccountLogin as AccountLoginNoticeService;
use App\Services\Logic\Notice\AccountLogin as AccountLoginNotice;
use App\Services\OAuth\QQ as QQAuth;
use App\Services\OAuth\WeiBo as WeiBoAuth;
use App\Services\OAuth\WeiXin as WeiXinAuth;
@ -79,7 +82,20 @@ class Connect extends Service
$this->handleConnectRelation($user, $openUser);
}
public function authLogin(ConnectModel $connect)
public function authSubscribeLogin(WeChatSubscribeModel $subscribe)
{
$userRepo = new UserRepo();
$user = $userRepo->findById($subscribe->user_id);
$this->handleLoginNotice($user);
$auth = new HomeAuthService();
$auth->saveAuthInfo($user);
}
public function authConnectLogin(ConnectModel $connect)
{
$userRepo = new UserRepo();
@ -112,6 +128,13 @@ class Connect extends Service
return $auth->getUserInfo($token, $openId);
}
public function getWeChatSubscribe($unionId)
{
$subscribeRepo = new WeChatSubscribeRepo();
return $subscribeRepo->findByUnionId($unionId);
}
public function getConnectRelation($openId, $provider)
{
$connectRepo = new ConnectRepo();
@ -200,6 +223,14 @@ class Connect extends Service
$connect->user_id = $user->id;
}
if (empty($connect->union_id) && !empty($openUser['unionid'])) {
$connect->union_id = $openUser['unionid'];
}
if ($connect->deleted == 1) {
$connect->deleted = 0;
}
$connect->update();
} else {
@ -207,6 +238,7 @@ class Connect extends Service
$connect = new ConnectModel();
$connect->user_id = $user->id;
$connect->union_id = $openUser['unionid'];
$connect->open_id = $openUser['id'];
$connect->open_name = $openUser['name'];
$connect->open_avatar = $openUser['avatar'];
@ -218,9 +250,9 @@ class Connect extends Service
protected function handleLoginNotice(UserModel $user)
{
$service = new AccountLoginNoticeService();
$notice = new AccountLoginNotice();
$service->createTask($user);
$notice->createTask($user);
}
}

View File

@ -114,7 +114,8 @@ class WeChatOfficialAccount extends Service
$subscribe = $subscribeRepo->findByOpenId($openId);
if ($subscribe) {
$subscribe->delete();
$subscribe->deleted = 1;
$subscribe->update();
}
return new TextMessage('伤心呀,我们又少了一个小伙伴!');
@ -128,7 +129,9 @@ class WeChatOfficialAccount extends Service
$userId = str_replace('qrscene_', '', $eventKey);
if ($userId && $openId) {
$this->saveWechatSubscribe($userId, $openId);
$userInfo = $this->getUserInfo($openId);
$unionId = $userInfo['unionid'] ?: '';
$this->saveWechatSubscribe($userId, $openId, $unionId);
}
return $this->emptyReply();
@ -194,7 +197,7 @@ class WeChatOfficialAccount extends Service
return new TextMessage('没有匹配的服务哦!');
}
protected function saveWechatSubscribe($userId, $openId)
protected function saveWechatSubscribe($userId, $openId, $unionId = '')
{
if (!$userId || !$openId) return;
@ -211,14 +214,35 @@ class WeChatOfficialAccount extends Service
if ($subscribe) {
if ($subscribe->user_id != $userId) {
$subscribe->user_id = $userId;
$subscribe->update();
}
if (empty($subscribe->union_id) && !empty($unionId)) {
$subscribe->union_id = $unionId;
}
if ($subscribe->deleted == 1) {
$subscribe->deleted = 0;
}
$subscribe->update();
} else {
$subscribe = new WeChatSubscribeModel();
$subscribe->user_id = $userId;
$subscribe->open_id = $openId;
$subscribe->union_id = $unionId;
$subscribe->create();
}
}
protected function getUserInfo($openId)
{
$app = $this->getOfficialAccount();
return $app->user->get($openId);
}
protected function getWechatLogger()
{
$service = new WeChatService();
return $service->logger;
}
}

Some files were not shown because too many files have changed in this diff Show More