mirror of
https://github.com/v2board/v2board.git
synced 2024-11-10 09:39:10 +08:00
Merge branch 'dev' of https://github.com/v2board/v2board into dev
This commit is contained in:
commit
c8f3684312
@ -57,6 +57,7 @@ class V2boardUpdate extends Command
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
$this->info('更新完毕,请重新启动队列服务。');
|
||||
\Artisan::call('horizon:terminate');
|
||||
$this->info('更新完毕,队列服务已重启,你无需进行任何操作。');
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,12 @@ class RouteController extends Controller
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$routes = ServerRoute::get();
|
||||
// TODO: remove on 1.8.0
|
||||
foreach ($routes as $k => $route) {
|
||||
$array = json_decode($route->match, true);
|
||||
if (is_array($array)) $routes[$k]['match'] = $array;
|
||||
}
|
||||
// TODO: remove on 1.8.0
|
||||
return [
|
||||
'data' => $routes
|
||||
];
|
||||
@ -24,10 +30,19 @@ class RouteController extends Controller
|
||||
{
|
||||
$params = $request->validate([
|
||||
'remarks' => 'required',
|
||||
'match' => 'required',
|
||||
'action' => 'required',
|
||||
'match' => 'required|array',
|
||||
'action' => 'required|in:block,dns',
|
||||
'action_value' => 'nullable'
|
||||
], [
|
||||
'remarks.required' => '备注不能为空',
|
||||
'match.required' => '匹配值不能为空',
|
||||
'action.required' => '动作类型不能为空',
|
||||
'action.in' => '动作类型参数有误'
|
||||
]);
|
||||
$params['match'] = array_filter($params['match']);
|
||||
// TODO: remove on 1.8.0
|
||||
$params['match'] = json_encode($params['match']);
|
||||
// TODO: remove on 1.8.0
|
||||
if ($request->input('id')) {
|
||||
try {
|
||||
$route = ServerRoute::find($request->input('id'));
|
||||
|
@ -25,9 +25,9 @@ class ThemeController extends Controller
|
||||
{
|
||||
$themeConfigs = [];
|
||||
foreach ($this->themes as $theme) {
|
||||
$themeConfigFile = $this->path . "{$theme}/config.php";
|
||||
$themeConfigFile = $this->path . "{$theme}/config.json";
|
||||
if (!File::exists($themeConfigFile)) continue;
|
||||
$themeConfig = include($themeConfigFile);
|
||||
$themeConfig = json_decode(File::get($themeConfigFile), true);
|
||||
if (!isset($themeConfig['configs']) || !is_array($themeConfig)) continue;
|
||||
$themeConfigs[$theme] = $themeConfig;
|
||||
if (config("theme.{$theme}")) continue;
|
||||
@ -60,9 +60,10 @@ class ThemeController extends Controller
|
||||
]);
|
||||
$payload['config'] = json_decode(base64_decode($payload['config']), true);
|
||||
if (!$payload['config'] || !is_array($payload['config'])) abort(500, '参数有误');
|
||||
$themeConfigFile = public_path("theme/{$payload['name']}/config.php");
|
||||
$themeConfigFile = public_path("theme/{$payload['name']}/config.json");
|
||||
if (!File::exists($themeConfigFile)) abort(500, '主题不存在');
|
||||
$themeConfig = include($themeConfigFile);
|
||||
$themeConfig = json_decode(File::get($themeConfigFile), true);
|
||||
if (!isset($themeConfig['configs']) || !is_array($themeConfig)) abort(500, '主题配置文件有误');
|
||||
$validateFields = array_column($themeConfig['configs'], 'field_name');
|
||||
$config = [];
|
||||
foreach ($validateFields as $validateField) {
|
||||
|
@ -71,6 +71,15 @@ class Surfboard
|
||||
$config = str_replace('$subs_domain', $subsDomain, $config);
|
||||
$config = str_replace('$proxies', $proxies, $config);
|
||||
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
||||
|
||||
$upload = round($user['u'] / (1024*1024*1024), 2);
|
||||
$download = round($user['d'] / (1024*1024*1024), 2);
|
||||
$useTraffic = $upload + $download;
|
||||
$totalTraffic = round($user['transfer_enable'] / (1024*1024*1024), 2);
|
||||
$expireDate = $user['expired_at'] === NULL ? '长期有效' : date('Y-m-d H:i:s', $user['expired_at']);
|
||||
$subscribeInfo = "title={$appName}订阅信息, content=上传流量:{$upload}GB\\n下载流量:{$download}GB\\n剩余流量:{$useTraffic}GB\\n套餐流量:{$totalTraffic}GB\\n到期时间:{$expireDate}";
|
||||
$config = str_replace('$subscribe_info', $subscribeInfo, $config);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,15 @@ class Surge
|
||||
$config = str_replace('$subs_domain', $subsDomain, $config);
|
||||
$config = str_replace('$proxies', $proxies, $config);
|
||||
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
||||
|
||||
$upload = round($user['u'] / (1024*1024*1024), 2);
|
||||
$download = round($user['d'] / (1024*1024*1024), 2);
|
||||
$useTraffic = $upload + $download;
|
||||
$totalTraffic = round($user['transfer_enable'] / (1024*1024*1024), 2);
|
||||
$expireDate = $user['expired_at'] === NULL ? '长期有效' : date('Y-m-d H:i:s', $user['expired_at']);
|
||||
$subscribeInfo = "title={$appName}订阅信息, content=上传流量:{$upload}GB\\n下载流量:{$download}GB\\n剩余流量:{$useTraffic}GB\\n套餐流量:{$totalTraffic}GB\\n到期时间:{$expireDate}";
|
||||
$config = str_replace('$subscribe_info', $subscribeInfo, $config);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\User\UserTransfer;
|
||||
use App\Http\Requests\User\UserUpdate;
|
||||
use App\Http\Requests\User\UserChangePassword;
|
||||
use App\Services\AuthService;
|
||||
use App\Services\UserService;
|
||||
use App\Utils\CacheKey;
|
||||
use Illuminate\Http\Request;
|
||||
@ -18,6 +19,30 @@ use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function getActiveSession(Request $request)
|
||||
{
|
||||
$user = User::find($request->user['id']);
|
||||
if (!$user) {
|
||||
abort(500, __('The user does not exist'));
|
||||
}
|
||||
$authService = new AuthService($user);
|
||||
return response([
|
||||
'data' => $authService->getSessions()
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeActiveSession(Request $request)
|
||||
{
|
||||
$user = User::find($request->user['id']);
|
||||
if (!$user) {
|
||||
abort(500, __('The user does not exist'));
|
||||
}
|
||||
$authService = new AuthService($user);
|
||||
return response([
|
||||
'data' => $authService->delSession($request->input('session_id'))
|
||||
]);
|
||||
}
|
||||
|
||||
public function checkLogin(Request $request)
|
||||
{
|
||||
$data = [
|
||||
|
@ -21,11 +21,12 @@ class UserRoute
|
||||
$router->get ('/checkLogin', 'User\\UserController@checkLogin');
|
||||
$router->post('/transfer', 'User\\UserController@transfer');
|
||||
$router->post('/getQuickLoginUrl', 'User\\UserController@getQuickLoginUrl');
|
||||
$router->get ('/getActiveSession', 'User\\UserController@getActiveSession');
|
||||
$router->post('/removeActiveSession', 'User\\UserController@removeActiveSession');
|
||||
// Order
|
||||
$router->post('/order/save', 'User\\OrderController@save');
|
||||
$router->post('/order/checkout', 'User\\OrderController@checkout');
|
||||
$router->get ('/order/check', 'User\\OrderController@check');
|
||||
$router->get ('/order/details', 'User\\OrderController@detail'); // TODO: 1.7.0 remove
|
||||
$router->get ('/order/detail', 'User\\OrderController@detail');
|
||||
$router->get ('/order/fetch', 'User\\OrderController@fetch');
|
||||
$router->get ('/order/getPaymentMethod', 'User\\OrderController@getPaymentMethod');
|
||||
|
@ -14,7 +14,7 @@ class AuthService
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct($user)
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
@ -76,10 +76,23 @@ class AuthService
|
||||
$cacheKey,
|
||||
$sessions
|
||||
)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getSessions()
|
||||
{
|
||||
return (array)Cache::get(CacheKey::get("USER_SESSIONS", $this->user->id), []);
|
||||
}
|
||||
|
||||
public function delSession($sessionId)
|
||||
{
|
||||
$cacheKey = CacheKey::get("USER_SESSIONS", $this->user->id);
|
||||
$sessions = (array)Cache::get($cacheKey, []);
|
||||
unset($sessions[$sessionId]);
|
||||
if (!Cache::put(
|
||||
$cacheKey,
|
||||
$sessions
|
||||
)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +221,14 @@ class ServerService
|
||||
|
||||
public function getRoutes(array $routeIds)
|
||||
{
|
||||
return ServerRoute::select(['id', 'match', 'action', 'action_value'])->whereIn('id', $routeIds)->get();
|
||||
$routes = ServerRoute::select(['id', 'match', 'action', 'action_value'])->whereIn('id', $routeIds)->get();
|
||||
// TODO: remove on 1.8.0
|
||||
foreach ($routes as $k => $route) {
|
||||
$array = json_decode($route->match, true);
|
||||
if (is_array($array)) $routes[$k]['match'] = $array;
|
||||
}
|
||||
// TODO: remove on 1.8.0
|
||||
return $routes;
|
||||
}
|
||||
|
||||
public function getServer($serverId, $serverType)
|
||||
|
@ -18,9 +18,10 @@ class ThemeService
|
||||
|
||||
public function init()
|
||||
{
|
||||
$themeConfigFile = $this->path . "{$this->theme}/config.php";
|
||||
if (!File::exists($themeConfigFile)) return;
|
||||
$themeConfig = include($themeConfigFile);
|
||||
$themeConfigFile = $this->path . "{$this->theme}/config.json";
|
||||
if (!File::exists($themeConfigFile)) abort(500, "{$this->theme}主题不存在");
|
||||
$themeConfig = json_decode(File::get($themeConfigFile), true);
|
||||
if (!isset($themeConfig['configs']) || !is_array($themeConfig)) abort(500, "{$this->theme}主题配置文件有误");
|
||||
$configs = $themeConfig['configs'];
|
||||
$data = [];
|
||||
foreach ($configs as $config) {
|
||||
|
@ -237,5 +237,5 @@ return [
|
||||
| The only modification by laravel config
|
||||
|
|
||||
*/
|
||||
'version' => '1.7.2'
|
||||
'version' => '1.7.2.1671294313058'
|
||||
];
|
||||
|
2
public/assets/admin/components.async.js
vendored
2
public/assets/admin/components.async.js
vendored
File diff suppressed because one or more lines are too long
2
public/assets/admin/components.chunk.css
vendored
2
public/assets/admin/components.chunk.css
vendored
File diff suppressed because one or more lines are too long
2
public/assets/admin/umi.js
vendored
2
public/assets/admin/umi.js
vendored
File diff suppressed because one or more lines are too long
2
public/assets/admin/vendors.async.js
vendored
2
public/assets/admin/vendors.async.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/theme/v2board/assets/umi.js
vendored
2
public/theme/v2board/assets/umi.js
vendored
File diff suppressed because one or more lines are too long
2
public/theme/v2board/assets/vendors.async.js
vendored
2
public/theme/v2board/assets/vendors.async.js
vendored
File diff suppressed because one or more lines are too long
49
public/theme/v2board/config.json
Normal file
49
public/theme/v2board/config.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "v2board",
|
||||
"description": "v2board",
|
||||
"version": "1.7.2",
|
||||
"images": "https://images.unsplash.com/photo-1515405295579-ba7b45403062?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2160&q=80",
|
||||
"configs": [{
|
||||
"label": "主题色",
|
||||
"placeholder": "请选择主题颜色",
|
||||
"field_name": "theme_color",
|
||||
"field_type": "select",
|
||||
"select_options": {
|
||||
"default": "默认(蓝色)",
|
||||
"green": "奶绿色",
|
||||
"black": "黑色",
|
||||
"darkblue": "暗蓝色"
|
||||
},
|
||||
"default_value": "default"
|
||||
}, {
|
||||
"label": "背景",
|
||||
"placeholder": "请输入背景图片URL",
|
||||
"field_name": "background_url",
|
||||
"field_type": "input"
|
||||
}, {
|
||||
"label": "边栏风格",
|
||||
"placeholder": "请选择边栏风格",
|
||||
"field_name": "theme_sidebar",
|
||||
"field_type": "select",
|
||||
"select_options": {
|
||||
"light": "亮",
|
||||
"dark": "暗"
|
||||
},
|
||||
"default_value": "light"
|
||||
}, {
|
||||
"label": "顶部风格",
|
||||
"placeholder": "请选择顶部风格",
|
||||
"field_name": "theme_header",
|
||||
"field_type": "select",
|
||||
"select_options": {
|
||||
"light": "亮",
|
||||
"dark": "暗"
|
||||
},
|
||||
"default_value": "dark"
|
||||
}, {
|
||||
"label": "自定义页脚HTML",
|
||||
"placeholder": "可以实现客服JS代码的加入等",
|
||||
"field_name": "custom_html",
|
||||
"field_type": "textarea"
|
||||
}]
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => 'V2board',
|
||||
'description' => 'V2board默认主题',
|
||||
'version' => '1.5.6',
|
||||
'images' => 'https://images.unsplash.com/photo-1515405295579-ba7b45403062?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2160&q=80',
|
||||
'configs' => [
|
||||
[
|
||||
'label' => '主题色', // 标签
|
||||
'placeholder' => '请选择主题颜色', // 描述
|
||||
'field_name' => 'theme_color', // 字段名 作为数据key使用
|
||||
'field_type' => 'select', // 字段类型: select,input,switch
|
||||
'select_options' => [ // 当字段类型为select时有效
|
||||
'default' => '默认(蓝色)',
|
||||
'green' => '奶绿色',
|
||||
'black' => '黑色',
|
||||
'darkblue' => '暗蓝色',
|
||||
],
|
||||
'default_value' => 'default' // 字段默认值,将会在首次进行初始化
|
||||
], [
|
||||
'label' => '背景',
|
||||
'placeholder' => '请输入背景图片URL',
|
||||
'field_name' => 'background_url',
|
||||
'field_type' => 'input'
|
||||
], [
|
||||
'label' => '边栏风格',
|
||||
'placeholder' => '请选择边栏风格',
|
||||
'field_name' => 'theme_sidebar',
|
||||
'field_type' => 'select',
|
||||
'select_options' => [
|
||||
'light' => '亮',
|
||||
'dark' => '暗'
|
||||
],
|
||||
'default_value' => 'light'
|
||||
], [
|
||||
'label' => '顶部风格',
|
||||
'placeholder' => '请选择顶部风格',
|
||||
'field_name' => 'theme_header',
|
||||
'field_type' => 'select',
|
||||
'select_options' => [
|
||||
'light' => '亮',
|
||||
'dark' => '暗'
|
||||
],
|
||||
'default_value' => 'dark'
|
||||
], [
|
||||
'label' => '自定义页脚HTML',
|
||||
'placeholder' => '可以实现客服JS代码的加入等',
|
||||
'field_name' => 'custom_html',
|
||||
'field_type' => 'textarea'
|
||||
]
|
||||
]
|
||||
];
|
@ -59,19 +59,6 @@
|
||||
<script src="/theme/{{$theme}}/assets/vendors.async.js?v={{$version}}"></script>
|
||||
<script src="/theme/{{$theme}}/assets/components.async.js?v={{$version}}"></script>
|
||||
<script src="/theme/{{$theme}}/assets/umi.js?v={{$version}}"></script>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P1E9Z5LRRK"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-P1E9Z5LRRK');
|
||||
</script>
|
||||
@if (file_exists(public_path("/theme/{$theme}/assets/custom.js")))
|
||||
<script src="/theme/{{$theme}}/assets/custom.js?v={{$version}}"></script>
|
||||
@endif
|
||||
|
11
readme.md
11
readme.md
@ -9,19 +9,16 @@
|
||||
- Laravel
|
||||
|
||||
## Demo
|
||||
[Demo](https://v2board.com)
|
||||
[Demo](https://demo.v2board.com)
|
||||
|
||||
## Document
|
||||
[Click](https://docs.v2board.com)
|
||||
[Click](https://v2board.com)
|
||||
|
||||
## Sponsors
|
||||
Thanks to the open source project license provided by [Jetbrains](https://www.jetbrains.com/)
|
||||
|
||||
## Community
|
||||
Telegram Channel: [@v2board](https://t.me/v2board)
|
||||
Telegram Group: [@v2board_official](https://t.me/v2board_official)
|
||||
🔔Telegram Channel: [@v2board](https://t.me/v2board)
|
||||
|
||||
## How to Feedback
|
||||
We have closed issues due to too much invalid feedback, you can give us your feedback in the following way.
|
||||
- Contact us through Community
|
||||
- Fork Dev branch commit pull request
|
||||
Follow the template in the issue to submit your question correctly, and we will have someone follow up with you.
|
||||
|
@ -12,6 +12,9 @@ test-timeout = 5
|
||||
internet-test-url = http://bing.com
|
||||
proxy-test-url = http://bing.com
|
||||
|
||||
[Panel]
|
||||
SubscribeInfo = $subscribe_info, style=info
|
||||
|
||||
# Surfboard 的服务器和策略组配置方式与 Surge 类似, 可以参考 Surge 的规则配置手册: https://manual.nssurge.com/
|
||||
|
||||
[Proxy]
|
||||
|
@ -36,6 +36,9 @@ hide-crashlytics-request = true
|
||||
use-keyword-filter = false
|
||||
hide-udp = false
|
||||
|
||||
[Panel]
|
||||
SubscribeInfo = $subscribe_info, style=info
|
||||
|
||||
# -----------------------------
|
||||
# Surge 的几种策略配置规范,请参考 https://manual.nssurge.com/policy/proxy.html
|
||||
# 不同的代理策略有*很多*可选参数,请参考上方连接的 Parameters 一段,根据需求自行添加参数。
|
||||
|
@ -31,19 +31,6 @@
|
||||
<script src="/assets/admin/vendors.async.js?v={{$version}}"></script>
|
||||
<script src="/assets/admin/components.async.js?v={{$version}}"></script>
|
||||
<script src="/assets/admin/umi.js?v={{$version}}"></script>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P1E9Z5LRRK"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-P1E9Z5LRRK');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user