1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-26 20:52:44 +08:00

Merge branch 'koogua/v1.7.2' into demo

This commit is contained in:
xiaochong0302 2024-08-13 09:27:46 +08:00
commit 335f2fd5cf
22 changed files with 141 additions and 101 deletions

View File

@ -1,3 +1,14 @@
### [v1.7.2](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.2)(2024-07-31)
- 更新layui-v2.9.14
- 优化docker自动化脚本
- 修正教师直播通知
- 修正课程分类删选问题
- 后台增加客户服务入口
- redis增加expire方法
- 日志记录增加log.trace参数
- 精简代码
### [v1.7.1](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.1)(2024-06-31) ### [v1.7.1](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.1)(2024-06-31)
- 更新layui-v2.9.10 - 更新layui-v2.9.10

View File

@ -7,11 +7,29 @@
namespace App\Console\Migrations; namespace App\Console\Migrations;
use App\Models\Setting as SettingModel;
use App\Repos\Setting as SettingRepo;
use App\Traits\Service as ServiceTrait; use App\Traits\Service as ServiceTrait;
abstract class Migration abstract class Migration
{ {
use ServiceTrait; use ServiceTrait;
abstract public function run(); abstract public function run();
protected function saveSetting(array $setting)
{
$settingRepo = new SettingRepo();
$item = $settingRepo->findItem($setting['section'], $setting['item_key']);
if (!$item) {
$item = new SettingModel();
$item->create($setting);
} else {
$item->update($setting);
}
}
} }

View File

@ -30,7 +30,7 @@ class TeacherLiveNoticeTask extends Task
$keyName = $this->getCacheKeyName(); $keyName = $this->getCacheKeyName();
foreach ($lives as $live) { foreach ($lives as $live) {
$redis->sAdd($keyName, $live->chapter_id); $redis->sAdd($keyName, $live->id);
} }
$redis->expire($keyName, 86400); $redis->expire($keyName, 86400);

View File

@ -0,0 +1,41 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Http\Admin\Controllers;
use App\Traits\Response as ResponseTrait;
/**
* @RoutePrefix("/admin/koogua")
*/
class KooguaController extends \Phalcon\Mvc\Controller
{
use ResponseTrait;
/**
* @Get("/wiki", name="admin.koogua.wiki")
*/
public function wikiAction()
{
$url = 'https://www.koogua.com/page/wiki';
$this->response->redirect($url, true);
}
/**
* @Get("/community", name="admin.koogua.community")
*/
public function communityAction()
{
$url = 'https://www.koogua.com/question/list';
return $this->response->redirect($url, true);
}
}

View File

@ -28,6 +28,16 @@
{% endfor %} {% endfor %}
</ul> </ul>
<ul class="layui-nav layui-layout-right"> <ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="{{ url({'for':'home.index'}) }}" target="_blank">前台首页</a>
</li>
<li class="layui-nav-item">
<a href="javascript:">用户服务</a>
<dl class="layui-nav-child">
<dd><a href="{{ url({'for':'admin.koogua.wiki'}) }}" target="_blank">系统文档</a></dd>
<dd><a href="{{ url({'for':'admin.koogua.community'}) }}" target="_blank">开源社区</a></dd>
</dl>
</li>
<li class="layui-nav-item"> <li class="layui-nav-item">
<a href="javascript:">{{ auth_user.name }}</a> <a href="javascript:">{{ auth_user.name }}</a>
<dl class="layui-nav-child"> <dl class="layui-nav-child">
@ -36,9 +46,6 @@
<dd><a href="{{ url({'for':'admin.logout'}) }}">退出登录</a></dd> <dd><a href="{{ url({'for':'admin.logout'}) }}">退出登录</a></dd>
</dl> </dl>
</li> </li>
<li class="layui-nav-item">
<a href="{{ url({'for':'home.index'}) }}" target="_blank">前台</a>
</li>
</ul> </ul>
</div> </div>
<div class="layui-side layui-bg-black"> <div class="layui-side layui-bg-black">

View File

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

View File

@ -16,13 +16,13 @@
<div class="layui-form-item" style="margin-bottom:20px;"> <div class="layui-form-item" style="margin-bottom:20px;">
<label class="layui-form-label">用户协议</label> <label class="layui-form-label">用户协议</label>
<div class="layui-input-block"> <div class="layui-input-block">
<a class="layui-btn layui-btn-normal" href="{{ url({'for':'admin.page.edit','id':'terms'}) }}">前往设置</a> <a class="layui-btn layui-btn-normal" href="{{ url({'for':'admin.page.edit','id':'terms'}) }}">设置</a>
</div> </div>
</div> </div>
<div class="layui-form-item" style="margin-bottom:20px;"> <div class="layui-form-item" style="margin-bottom:20px;">
<label class="layui-form-label">隐私政策</label> <label class="layui-form-label">隐私政策</label>
<div class="layui-input-block"> <div class="layui-input-block">
<a class="layui-btn layui-btn-normal" href="{{ url({'for':'admin.page.edit','id':'privacy'}) }}">前往设置</a> <a class="layui-btn layui-btn-normal" href="{{ url({'for':'admin.page.edit','id':'privacy'}) }}">设置</a>
</div> </div>
</div> </div>
<div class="layui-form-item"> <div class="layui-form-item">

View File

@ -16,7 +16,7 @@ class AppInfo
protected $link = 'https://www.koogua.com'; protected $link = 'https://www.koogua.com';
protected $version = '1.7.1'; protected $version = '1.7.2';
public function __get($name) public function __get($name)
{ {

View File

@ -161,7 +161,7 @@ class Redis extends \Phalcon\Cache\Backend\Redis
$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); $redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY);
$it = null; $it = 0;
while ($keys = $redis->scan($it, $pattern)) { while ($keys = $redis->scan($it, $pattern)) {
if (count($result) > $limit) break; if (count($result) > $limit) break;
@ -191,6 +191,35 @@ class Redis extends \Phalcon\Cache\Backend\Redis
return (bool)$redis->exists($lastKey); return (bool)$redis->exists($lastKey);
} }
/**
* @param string $keyName
* @return bool
*/
public function expire($keyName = null, $lifetime = null): bool
{
$redis = $this->getRedis();
/**
* @var FrontendInterface $frontend
*/
$frontend = $this->_frontend;
if ($keyName === null) {
$lastKey = $this->_lastKey;
} else {
$lastKey = $this->getKeyName($keyName);
}
if ($lifetime === null) {
$tmp = $this->_lastLifetime;
$ttl = $tmp ?: $frontend->getLifetime();
} else {
$ttl = $lifetime;
}
return $redis->expire($lastKey, $ttl);
}
/** /**
* @param string $keyName * @param string $keyName
* @return int|bool * @return int|bool

View File

@ -26,19 +26,4 @@ class UserSession extends Repository
->execute(); ->execute();
} }
/**
* @param int $userId
* @param int $minutes
* @return ResultsetInterface|Resultset|UserSessionModel[]
*/
public function findUserRecentSessions($userId, $minutes = 10)
{
$createTime = time() - $minutes * 60;
return UserSessionModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->andWhere('create_time > :create_time:', ['create_time' => $createTime])
->execute();
}
} }

View File

@ -25,19 +25,4 @@ class UserToken extends Repository
->execute(); ->execute();
} }
/**
* @param int $userId
* @param int $minutes
* @return ResultsetInterface|Resultset|UserTokenModel[]
*/
public function findUserRecentTokens($userId, $minutes = 10)
{
$createTime = time() - $minutes * 60;
return UserTokenModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->andWhere('create_time > :create_time:', ['create_time' => $createTime])
->execute();
}
} }

View File

@ -56,19 +56,4 @@ class Admin extends AuthService
return 'admin_auth_info'; return 'admin_auth_info';
} }
public function hasPermission($route)
{
$authUser = $this->getAuthInfo();
if ($authUser['root'] == 1) {
return true;
}
if (in_array($route, $authUser['routes'])) {
return true;
}
return false;
}
} }

View File

@ -57,11 +57,6 @@ class Home extends AuthService
return $authInfo ?: null; return $authInfo ?: null;
} }
public function getAuthKey()
{
return 'home_auth_info';
}
public function logoutClients($userId) public function logoutClients($userId)
{ {
$cache = $this->getCache(); $cache = $this->getCache();
@ -104,4 +99,9 @@ class Home extends AuthService
return "_PHCR_SESSION_:{$sessionId}"; return "_PHCR_SESSION_:{$sessionId}";
} }
protected function getAuthKey()
{
return 'home_auth_info';
}
} }

View File

@ -38,10 +38,11 @@ class CourseList extends LogicService
$childCategoryIds = $categoryService->getChildCategoryIds($params['tc']); $childCategoryIds = $categoryService->getChildCategoryIds($params['tc']);
/** $parentCategoryIds = [$params['tc']];
* 构造空记录条件
*/ $allCategoryIds = array_merge($parentCategoryIds, $childCategoryIds);
$params['category_id'] = $childCategoryIds ?: -999;
$params['category_id'] = $allCategoryIds;
} }
$params['published'] = 1; $params['published'] = 1;

View File

@ -12,12 +12,9 @@ use App\Exceptions\Forbidden as ForbiddenException;
use App\Library\Utils\Password as PasswordUtil; use App\Library\Utils\Password as PasswordUtil;
use App\Library\Validators\Common as CommonValidator; use App\Library\Validators\Common as CommonValidator;
use App\Models\Account as AccountModel; use App\Models\Account as AccountModel;
use App\Models\Client as ClientModel;
use App\Models\User as UserModel; use App\Models\User as UserModel;
use App\Repos\Account as AccountRepo; use App\Repos\Account as AccountRepo;
use App\Repos\User as UserRepo; use App\Repos\User as UserRepo;
use App\Repos\UserSession as UserSessionRepo;
use App\Repos\UserToken as UserTokenRepo;
use App\Traits\Client as ClientTrait; use App\Traits\Client as ClientTrait;
class Account extends Validator class Account extends Validator
@ -193,34 +190,6 @@ class Account extends Validator
if ($case1 && $case2) { if ($case1 && $case2) {
throw new ForbiddenException('account.locked'); throw new ForbiddenException('account.locked');
} }
$this->checkFloodLogin($user->id);
}
public function checkFloodLogin($userId)
{
$clientIp = $this->getClientIp();
$clientType = $this->getClientType();
if ($clientType == ClientModel::TYPE_PC) {
$repo = new UserSessionRepo();
$records = $repo->findUserRecentSessions($userId, 10);
} else {
$repo = new UserTokenRepo();
$records = $repo->findUserRecentTokens($userId, 10);
}
if ($records->count() == 0) return;
$clientIps = array_column($records->toArray(), 'client_ip');
$countValues = array_count_values($clientIps);
foreach ($countValues as $ip => $count) {
if ($clientIp == $ip && $count > 4) {
throw new ForbiddenException('account.flood_login');
}
}
} }
} }

View File

@ -33,9 +33,12 @@ class ConsoleErrorHandler extends Injectable
$config = $this->getConfig(); $config = $this->getConfig();
if ($config->get('env') == 'dev') { if ($config->path('env') == 'dev' || $config->path('log.trace')) {
$trace = sprintf('%sTrace Content: %s', PHP_EOL, $e->getTraceAsString());
$trace = sprintf('Trace Content: %s', $e->getTraceAsString());
$logger->error($trace); $logger->error($trace);
$content .= $trace; $content .= $trace;
} }

View File

@ -77,8 +77,10 @@ class HttpErrorHandler extends Injectable
$config = $this->getConfig(); $config = $this->getConfig();
if ($config->get('env') == 'dev') { if ($config->path('env') == 'dev' || $config->path('log.trace')) {
$content = sprintf('Trace Content: %s', $e->getTraceAsString()); $content = sprintf('Trace Content: %s', $e->getTraceAsString());
$logger->error($content); $logger->error($content);
} }
} }

View File

@ -27,6 +27,11 @@ $config['timezone'] = 'Asia/Shanghai';
*/ */
$config['log']['level'] = Phalcon\Logger::INFO; $config['log']['level'] = Phalcon\Logger::INFO;
/**
* 日志链路
*/
$config['log']['trace'] = false;
/** /**
* 网站根地址,必须以"/"结尾 * 网站根地址,必须以"/"结尾
*/ */

View File

@ -47,7 +47,6 @@ $error['captcha.invalid_code'] = '无效的验证码';
*/ */
$error['account.not_found'] = '账号不存在'; $error['account.not_found'] = '账号不存在';
$error['account.locked'] = '账号被锁定,无法登录'; $error['account.locked'] = '账号被锁定,无法登录';
$error['account.flood_login'] = '帐号泛滥登录';
$error['account.login_pwd_incorrect'] = '登录密码不正确'; $error['account.login_pwd_incorrect'] = '登录密码不正确';
$error['account.invalid_login_name'] = '无效的登录名'; $error['account.invalid_login_name'] = '无效的登录名';
$error['account.invalid_email'] = '无效的电子邮箱'; $error['account.invalid_email'] = '无效的电子邮箱';

View File

@ -11,7 +11,7 @@ layui.use(['jquery', 'layer', 'helper'], function () {
var url = '/verify/captcha?type=all&account=' + $account.val(); var url = '/verify/captcha?type=all&account=' + $account.val();
layer.open({ layer.open({
type: 2, type: 2,
title: '获取验证码', title: '验证码',
area: ['500px', '250px'], area: ['500px', '250px'],
content: [url, 'no'], content: [url, 'no'],
}); });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long