1
.gitignore
vendored
@ -18,3 +18,4 @@ composer.phar
|
|||||||
composer.lock
|
composer.lock
|
||||||
yarn.lock
|
yarn.lock
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
|
.DS_Store
|
||||||
|
16
.styleci.yml
@ -1,16 +0,0 @@
|
|||||||
php:
|
|
||||||
preset: laravel
|
|
||||||
enabled:
|
|
||||||
- alpha_ordered_imports
|
|
||||||
disabled:
|
|
||||||
- length_ordered_imports
|
|
||||||
- unused_use
|
|
||||||
finder:
|
|
||||||
not-name:
|
|
||||||
- index.php
|
|
||||||
- server.php
|
|
||||||
js:
|
|
||||||
finder:
|
|
||||||
not-name:
|
|
||||||
- webpack.mix.js
|
|
||||||
css: true
|
|
@ -42,7 +42,9 @@ class CheckOrder extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$orders = Order::get();
|
ini_set('memory_limit', -1);
|
||||||
|
$orders = Order::whereIn('status', [0, 1])
|
||||||
|
->get();
|
||||||
foreach ($orders as $item) {
|
foreach ($orders as $item) {
|
||||||
$orderService = new OrderService($item);
|
$orderService = new OrderService($item);
|
||||||
switch ($item->status) {
|
switch ($item->status) {
|
||||||
|
65
app/Console/Commands/CheckServer.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Services\ServerService;
|
||||||
|
use App\Services\TelegramService;
|
||||||
|
use App\Utils\CacheKey;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class CheckServer extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'check:server';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '节点检查任务';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->checkOffline();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkOffline()
|
||||||
|
{
|
||||||
|
$serverService = new ServerService();
|
||||||
|
$servers = $serverService->getAllServers();
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
if ($server['parent_id']) continue;
|
||||||
|
if ($server['last_check_at'] && (time() - $server['last_check_at']) > 1800) {
|
||||||
|
$telegramService = new TelegramService();
|
||||||
|
$message = sprintf(
|
||||||
|
"节点掉线通知\r\n----\r\n节点名称:%s\r\n节点地址:%s\r\n",
|
||||||
|
$server['name'],
|
||||||
|
$server['host']
|
||||||
|
);
|
||||||
|
$telegramService->sendMessageWithAdmin($message);
|
||||||
|
Cache::forget(CacheKey::get(sprintf("SERVER_%s_LAST_CHECK_AT", strtoupper($server['type'])), $server->id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
|||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class ResetTraffic extends Command
|
class ResetTraffic extends Command
|
||||||
{
|
{
|
||||||
@ -41,6 +42,7 @@ class ResetTraffic extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
DB::beginTransaction();
|
||||||
$resetTrafficMethod = config('v2board.reset_traffic_method', 0);
|
$resetTrafficMethod = config('v2board.reset_traffic_method', 0);
|
||||||
switch ((int)$resetTrafficMethod) {
|
switch ((int)$resetTrafficMethod) {
|
||||||
// 1 a month
|
// 1 a month
|
||||||
@ -52,6 +54,7 @@ class ResetTraffic extends Command
|
|||||||
$this->resetByExpireDay();
|
$this->resetByExpireDay();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
DB::commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resetByMonthFirstDay():void
|
private function resetByMonthFirstDay():void
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Services\PaymentService;
|
use App\Models\Order;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
class Test extends Command
|
class Test extends Command
|
||||||
@ -38,7 +38,5 @@ class Test extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$paymentService = new PaymentService('MGate');
|
|
||||||
var_dump($paymentService->form());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,7 @@ class V2boardStatistics extends Command
|
|||||||
->whereNotIn('status', [0, 2]);
|
->whereNotIn('status', [0, 2]);
|
||||||
$orderCount = $builder->count();
|
$orderCount = $builder->count();
|
||||||
$orderAmount = $builder->sum('total_amount');
|
$orderAmount = $builder->sum('total_amount');
|
||||||
$builder = $builder->where('commission_balance', '!=', 0)
|
$builder = $builder->where('commission_balance', '!=', 0);
|
||||||
->where('commission_status', 0);
|
|
||||||
$commissionCount = $builder->count();
|
$commissionCount = $builder->count();
|
||||||
$commissionAmount = $builder->sum('commission_balance');
|
$commissionAmount = $builder->sum('commission_balance');
|
||||||
$data = [
|
$data = [
|
||||||
|
@ -25,7 +25,7 @@ class Kernel extends ConsoleKernel
|
|||||||
protected function schedule(Schedule $schedule)
|
protected function schedule(Schedule $schedule)
|
||||||
{
|
{
|
||||||
// v2board
|
// v2board
|
||||||
$schedule->command('v2board:statistics')->daily();
|
$schedule->command('v2board:statistics')->dailyAt('0:10');
|
||||||
// check
|
// check
|
||||||
$schedule->command('check:order')->everyMinute();
|
$schedule->command('check:order')->everyMinute();
|
||||||
$schedule->command('check:commission')->everyMinute();
|
$schedule->command('check:commission')->everyMinute();
|
||||||
|
@ -21,6 +21,17 @@ class ConfigController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getThemeTemplate()
|
||||||
|
{
|
||||||
|
$path = public_path('theme/');
|
||||||
|
$files = array_map(function ($item) use ($path) {
|
||||||
|
return str_replace($path, '', $item);
|
||||||
|
}, glob($path . '*'));
|
||||||
|
return response([
|
||||||
|
'data' => $files
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function setTelegramWebhook(Request $request)
|
public function setTelegramWebhook(Request $request)
|
||||||
{
|
{
|
||||||
$telegramService = new TelegramService($request->input('telegram_bot_token'));
|
$telegramService = new TelegramService($request->input('telegram_bot_token'));
|
||||||
@ -72,8 +83,10 @@ class ConfigController extends Controller
|
|||||||
'subscribe' => [
|
'subscribe' => [
|
||||||
'plan_change_enable' => (int)config('v2board.plan_change_enable', 1),
|
'plan_change_enable' => (int)config('v2board.plan_change_enable', 1),
|
||||||
'reset_traffic_method' => (int)config('v2board.reset_traffic_method', 0),
|
'reset_traffic_method' => (int)config('v2board.reset_traffic_method', 0),
|
||||||
'renew_reset_traffic_enable' => (int)config('v2board.renew_reset_traffic_enable', 0),
|
'surplus_enable' => (int)config('v2board.surplus_enable', 1),
|
||||||
'surplus_enable' => (int)config('v2board.surplus_enable', 1)
|
'new_order_event_id' => (int)config('v2board.new_order_event_id', 0),
|
||||||
|
'renew_order_event_id' => (int)config('v2board.renew_order_event_id', 0),
|
||||||
|
'change_order_event_id' => (int)config('v2board.change_order_event_id', 0),
|
||||||
],
|
],
|
||||||
'pay' => [
|
'pay' => [
|
||||||
// alipay
|
// alipay
|
||||||
@ -107,6 +120,7 @@ class ConfigController extends Controller
|
|||||||
'epay_key' => config('v2board.epay_key'),
|
'epay_key' => config('v2board.epay_key'),
|
||||||
],
|
],
|
||||||
'frontend' => [
|
'frontend' => [
|
||||||
|
'frontend_theme' => config('v2board.frontend_theme', 'v2board'),
|
||||||
'frontend_theme_sidebar' => config('v2board.frontend_theme_sidebar', 'light'),
|
'frontend_theme_sidebar' => config('v2board.frontend_theme_sidebar', 'light'),
|
||||||
'frontend_theme_header' => config('v2board.frontend_theme_header', 'dark'),
|
'frontend_theme_header' => config('v2board.frontend_theme_header', 'dark'),
|
||||||
'frontend_theme_color' => config('v2board.frontend_theme_color', 'default'),
|
'frontend_theme_color' => config('v2board.frontend_theme_color', 'default'),
|
||||||
|
@ -77,11 +77,15 @@ class KnowledgeController extends Controller
|
|||||||
public function sort(KnowledgeSort $request)
|
public function sort(KnowledgeSort $request)
|
||||||
{
|
{
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
foreach ($request->input('knowledge_ids') as $k => $v) {
|
try {
|
||||||
if (!Knowledge::find($v)->update(['sort' => $k + 1])) {
|
foreach ($request->input('knowledge_ids') as $k => $v) {
|
||||||
DB::rollBack();
|
$knowledge = Knowledge::find($v);
|
||||||
abort(500, '保存失败');
|
$knowledge->timestamps = false;
|
||||||
|
$knowledge->update(['sort' => $k + 1]);
|
||||||
}
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
abort(500, '保存失败');
|
||||||
}
|
}
|
||||||
DB::commit();
|
DB::commit();
|
||||||
return response([
|
return response([
|
||||||
|
@ -52,8 +52,8 @@ class PlanController extends Controller
|
|||||||
// update user group id and transfer
|
// update user group id and transfer
|
||||||
try {
|
try {
|
||||||
User::where('plan_id', $plan->id)->update([
|
User::where('plan_id', $plan->id)->update([
|
||||||
'group_id' => $plan->group_id,
|
'group_id' => $params['group_id'],
|
||||||
'transfer_enable' => $plan->transfer_enable * 1073741824
|
'transfer_enable' => $params['transfer_enable'] * 1073741824
|
||||||
]);
|
]);
|
||||||
$plan->update($params);
|
$plan->update($params);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
@ -15,16 +15,8 @@ class ManageController extends Controller
|
|||||||
public function getNodes(Request $request)
|
public function getNodes(Request $request)
|
||||||
{
|
{
|
||||||
$serverService = new ServerService();
|
$serverService = new ServerService();
|
||||||
$servers = array_merge(
|
|
||||||
$serverService->getShadowsocksServers(),
|
|
||||||
$serverService->getV2rayServers(),
|
|
||||||
$serverService->getTrojanServers()
|
|
||||||
);
|
|
||||||
$serverService->mergeData($servers);
|
|
||||||
$tmp = array_column($servers, 'sort');
|
|
||||||
array_multisort($tmp, SORT_ASC, $servers);
|
|
||||||
return response([
|
return response([
|
||||||
'data' => $servers
|
'data' => $serverService->getAllServers()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ use App\Http\Requests\Admin\UserGenerate;
|
|||||||
use App\Http\Requests\Admin\UserSendMail;
|
use App\Http\Requests\Admin\UserSendMail;
|
||||||
use App\Http\Requests\Admin\UserUpdate;
|
use App\Http\Requests\Admin\UserUpdate;
|
||||||
use App\Jobs\SendEmailJob;
|
use App\Jobs\SendEmailJob;
|
||||||
|
use App\Services\UserService;
|
||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Order;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Plan;
|
use App\Models\Plan;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
@ -81,8 +81,12 @@ class UserController extends Controller
|
|||||||
if (empty($request->input('id'))) {
|
if (empty($request->input('id'))) {
|
||||||
abort(500, '参数错误');
|
abort(500, '参数错误');
|
||||||
}
|
}
|
||||||
|
$user = User::find($request->input('id'));
|
||||||
|
if ($user->invite_user_id) {
|
||||||
|
$user['invite_user'] = User::find($user->invite_user_id);
|
||||||
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => User::find($request->input('id'))
|
'data' => $user
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +113,14 @@ class UserController extends Controller
|
|||||||
}
|
}
|
||||||
$params['group_id'] = $plan->group_id;
|
$params['group_id'] = $plan->group_id;
|
||||||
}
|
}
|
||||||
|
if ($request->input('invite_user_email')) {
|
||||||
|
$inviteUser = User::where('email', $request->input('invite_user_email'))->first();
|
||||||
|
if ($inviteUser) {
|
||||||
|
$params['invite_user_id'] = $inviteUser->id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$params['invite_user_id'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user->update($params);
|
$user->update($params);
|
||||||
@ -265,30 +277,4 @@ class UserController extends Controller
|
|||||||
'data' => true
|
'data' => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setInviteUser(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'user_id' => 'required|integer',
|
|
||||||
'invite_user' => 'required',
|
|
||||||
], [
|
|
||||||
'user_id.required' => '用户ID不能为空',
|
|
||||||
'user_id.integer' => '用户ID参数有误',
|
|
||||||
'invite_user.required' => '邀请人不能为空'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$user = User::find($request->input('user_id'));
|
|
||||||
if (!$user) abort(500, '用户不存在');
|
|
||||||
if (strpos($request->input('invite_user'), '@') !== -1) {
|
|
||||||
$inviteUser = User::where('email', $request->input('invite_user'))->first();
|
|
||||||
} else {
|
|
||||||
$inviteUser = User::find($request->input('invite_user'));
|
|
||||||
}
|
|
||||||
if (!$inviteUser) abort(500, '邀请人不存在');
|
|
||||||
$user->invite_user_id = $inviteUser->id;
|
|
||||||
|
|
||||||
return response([
|
|
||||||
'data' => $user->save()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use App\Services\UserService;
|
|||||||
use App\Utils\Clash;
|
use App\Utils\Clash;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
class AppController extends Controller
|
class AppController extends Controller
|
||||||
@ -25,21 +26,27 @@ class AppController extends Controller
|
|||||||
$serverService = new ServerService();
|
$serverService = new ServerService();
|
||||||
$servers = $serverService->getAvailableServers($user);
|
$servers = $serverService->getAvailableServers($user);
|
||||||
}
|
}
|
||||||
$config = Yaml::parseFile(base_path() . '/resources/rules/app.clash.yaml');
|
$defaultConfig = base_path() . '/resources/rules/app.clash.yaml';
|
||||||
|
$customConfig = base_path() . '/resources/rules/custom.app.clash.yaml';
|
||||||
|
if (File::exists($customConfig)) {
|
||||||
|
$config = Yaml::parseFile($customConfig);
|
||||||
|
} else {
|
||||||
|
$config = Yaml::parseFile($defaultConfig);
|
||||||
|
}
|
||||||
$proxy = [];
|
$proxy = [];
|
||||||
$proxies = [];
|
$proxies = [];
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if ($item['type'] === 'shadowsocks') {
|
if ($item['type'] === 'shadowsocks') {
|
||||||
array_push($proxy, Clash::buildShadowsocks($user['uuid'], $item));
|
array_push($proxy, Protocols\Clash::buildShadowsocks($user['uuid'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'v2ray') {
|
if ($item['type'] === 'v2ray') {
|
||||||
array_push($proxy, Clash::buildVmess($user['uuid'], $item));
|
array_push($proxy, Protocols\Clash::buildVmess($user['uuid'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === 'trojan') {
|
||||||
array_push($proxy, Clash::buildTrojan($user['uuid'], $item));
|
array_push($proxy, Protocols\Clash::buildTrojan($user['uuid'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,62 +91,4 @@ class AppController extends Controller
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function config(Request $request)
|
|
||||||
{
|
|
||||||
if (empty($request->input('server_id'))) {
|
|
||||||
abort(500, '参数错误');
|
|
||||||
}
|
|
||||||
$user = $request->user;
|
|
||||||
if ($user->expired_at < time() && $user->expired_at !== NULL) {
|
|
||||||
abort(500, '订阅计划已过期');
|
|
||||||
}
|
|
||||||
$server = Server::where('show', 1)
|
|
||||||
->where('id', $request->input('server_id'))
|
|
||||||
->first();
|
|
||||||
if (!$server) {
|
|
||||||
abort(500, '服务器不存在');
|
|
||||||
}
|
|
||||||
$json = json_decode(self::CLIENT_CONFIG);
|
|
||||||
//socks
|
|
||||||
$json->inbound->port = (int)self::SOCKS_PORT;
|
|
||||||
//http
|
|
||||||
$json->inboundDetour[0]->port = (int)self::HTTP_PORT;
|
|
||||||
//other
|
|
||||||
$json->outbound->settings->vnext[0]->address = (string)$server->host;
|
|
||||||
$json->outbound->settings->vnext[0]->port = (int)$server->port;
|
|
||||||
$json->outbound->settings->vnext[0]->users[0]->id = (string)$user->uuid;
|
|
||||||
$json->outbound->settings->vnext[0]->users[0]->alterId = (int)$server->alter_id;
|
|
||||||
$json->outbound->settings->vnext[0]->remark = (string)$server->name;
|
|
||||||
$json->outbound->streamSettings->network = $server->network;
|
|
||||||
if ($server->networkSettings) {
|
|
||||||
switch ($server->network) {
|
|
||||||
case 'tcp':
|
|
||||||
$json->outbound->streamSettings->tcpSettings = json_decode($server->networkSettings);
|
|
||||||
break;
|
|
||||||
case 'kcp':
|
|
||||||
$json->outbound->streamSettings->kcpSettings = json_decode($server->networkSettings);
|
|
||||||
break;
|
|
||||||
case 'ws':
|
|
||||||
$json->outbound->streamSettings->wsSettings = json_decode($server->networkSettings);
|
|
||||||
break;
|
|
||||||
case 'http':
|
|
||||||
$json->outbound->streamSettings->httpSettings = json_decode($server->networkSettings);
|
|
||||||
break;
|
|
||||||
case 'domainsocket':
|
|
||||||
$json->outbound->streamSettings->dsSettings = json_decode($server->networkSettings);
|
|
||||||
break;
|
|
||||||
case 'quic':
|
|
||||||
$json->outbound->streamSettings->quicSettings = json_decode($server->networkSettings);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($request->input('is_global')) {
|
|
||||||
$json->routing->settings->rules[0]->outboundTag = 'proxy';
|
|
||||||
}
|
|
||||||
if ($server->tls) {
|
|
||||||
$json->outbound->streamSettings->security = "tls";
|
|
||||||
}
|
|
||||||
die(json_encode($json, JSON_UNESCAPED_UNICODE));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Client;
|
namespace App\Http\Controllers\Client;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Client\Protocols\V2rayN;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Services\ServerService;
|
use App\Services\ServerService;
|
||||||
use App\Utils\Clash;
|
|
||||||
use App\Utils\QuantumultX;
|
|
||||||
use App\Utils\Shadowrocket;
|
|
||||||
use App\Utils\Surge;
|
|
||||||
use App\Utils\Surfboard;
|
|
||||||
use App\Utils\URLSchemes;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\Server;
|
|
||||||
use App\Utils\Helper;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
use App\Services\UserService;
|
use App\Services\UserService;
|
||||||
|
|
||||||
class ClientController extends Controller
|
class ClientController extends Controller
|
||||||
@ -32,251 +24,18 @@ class ClientController extends Controller
|
|||||||
$serverService = new ServerService();
|
$serverService = new ServerService();
|
||||||
$servers = $serverService->getAvailableServers($user);
|
$servers = $serverService->getAvailableServers($user);
|
||||||
if ($flag) {
|
if ($flag) {
|
||||||
if (strpos($flag, 'quantumult%20x') !== false) {
|
foreach (glob(app_path('Http//Controllers//Client//Protocols') . '/*.php') as $file) {
|
||||||
die($this->quantumultX($user, $servers));
|
$file = 'App\\Http\\Controllers\\Client\\Protocols\\' . basename($file, '.php');
|
||||||
}
|
$class = new $file($user, $servers);
|
||||||
if (strpos($flag, 'quantumult') !== false) {
|
if (strpos($flag, $class->flag) !== false) {
|
||||||
die($this->quantumult($user, $servers));
|
die($class->handle());
|
||||||
}
|
|
||||||
if (strpos($flag, 'clash') !== false) {
|
|
||||||
die($this->clash($user, $servers));
|
|
||||||
}
|
|
||||||
if (strpos($flag, 'surfboard') !== false) {
|
|
||||||
die($this->surfboard($user, $servers));
|
|
||||||
}
|
|
||||||
if (strpos($flag, 'surge') !== false) {
|
|
||||||
die($this->surge($user, $servers));
|
|
||||||
}
|
|
||||||
if (strpos($flag, 'shadowrocket') !== false) {
|
|
||||||
die($this->shadowrocket($user, $servers));
|
|
||||||
}
|
|
||||||
if (strpos($flag, 'shadowsocks') !== false) {
|
|
||||||
die($this->shaodowsocksSIP008($user, $servers));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
die($this->origin($user, $servers));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: Ready to stop support
|
|
||||||
private function quantumult($user, $servers = [])
|
|
||||||
{
|
|
||||||
$uri = '';
|
|
||||||
header('subscription-userinfo: upload=' . $user['u'] . '; download=' . $user['d'] . ';total=' . $user['transfer_enable']);
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
$str = '';
|
|
||||||
$str .= $item['name'] . '= vmess, ' . $item['host'] . ', ' . $item['port'] . ', chacha20-ietf-poly1305, "' . $user['uuid'] . '", over-tls=' . ($item['tls'] ? "true" : "false") . ', certificate=0, group=' . config('v2board.app_name', 'V2Board');
|
|
||||||
if ($item['network'] === 'ws') {
|
|
||||||
$str .= ', obfs=ws';
|
|
||||||
if ($item['networkSettings']) {
|
|
||||||
$wsSettings = json_decode($item['networkSettings'], true);
|
|
||||||
if (isset($wsSettings['path'])) $str .= ', obfs-path="' . $wsSettings['path'] . '"';
|
|
||||||
if (isset($wsSettings['headers']['Host'])) $str .= ', obfs-header="Host:' . $wsSettings['headers']['Host'] . '"';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$uri .= "vmess://" . base64_encode($str) . "\r\n";
|
|
||||||
}
|
}
|
||||||
|
// todo 1.5.3 remove
|
||||||
|
$class = new V2rayN($user, $servers);
|
||||||
|
die($class->handle());
|
||||||
|
die('该客户端暂不支持进行订阅');
|
||||||
}
|
}
|
||||||
return base64_encode($uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function shadowrocket($user, $servers = [])
|
|
||||||
{
|
|
||||||
$uri = '';
|
|
||||||
//display remaining traffic and expire date
|
|
||||||
$upload = round($user['u'] / (1024*1024*1024), 2);
|
|
||||||
$download = round($user['d'] / (1024*1024*1024), 2);
|
|
||||||
$totalTraffic = round($user['transfer_enable'] / (1024*1024*1024), 2);
|
|
||||||
$expiredDate = date('Y-m-d', $user['expired_at']);
|
|
||||||
$uri .= "STATUS=🚀↑:{$upload}GB,↓:{$download}GB,TOT:{$totalTraffic}GB💡Expires:{$expiredDate}\r\n";
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
$uri .= Shadowrocket::buildShadowsocks($user['uuid'], $item);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
$uri .= Shadowrocket::buildVmess($user['uuid'], $item);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'trojan') {
|
|
||||||
$uri .= Shadowrocket::buildTrojan($user['uuid'], $item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base64_encode($uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function quantumultX($user, $servers = [])
|
|
||||||
{
|
|
||||||
$uri = '';
|
|
||||||
header("subscription-userinfo: upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}");
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
$uri .= QuantumultX::buildShadowsocks($user['uuid'], $item);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
$uri .= QuantumultX::buildVmess($user['uuid'], $item);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'trojan') {
|
|
||||||
$uri .= QuantumultX::buildTrojan($user['uuid'], $item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base64_encode($uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function origin($user, $servers = [])
|
|
||||||
{
|
|
||||||
$uri = '';
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
$uri .= URLSchemes::buildShadowsocks($item, $user);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
$uri .= URLSchemes::buildVmess($item, $user);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'trojan') {
|
|
||||||
$uri .= URLSchemes::buildTrojan($item, $user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base64_encode($uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function shaodowsocksSIP008($user, $servers = [])
|
|
||||||
{
|
|
||||||
$configs = [];
|
|
||||||
$subs = [];
|
|
||||||
$subs['servers'] = [];
|
|
||||||
$subs['bytes_used'] = '';
|
|
||||||
$subs['bytes_remaining'] = '';
|
|
||||||
|
|
||||||
$bytesUsed = $user['u'] + $user['d'];
|
|
||||||
$bytesRemaining = $user['transfer_enable'] - $bytesUsed;
|
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
array_push($configs, URLSchemes::buildShadowsocksSIP008($item, $user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$subs['version'] = 1;
|
|
||||||
$subs['bytes_used'] = $bytesUsed;
|
|
||||||
$subs['bytes_remaining'] = $bytesRemaining;
|
|
||||||
$subs['servers'] = array_merge($subs['servers'] ? $subs['servers'] : [], $configs);
|
|
||||||
|
|
||||||
return json_encode($subs, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function surge($user, $servers = [])
|
|
||||||
{
|
|
||||||
$proxies = '';
|
|
||||||
$proxyGroup = '';
|
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
// [Proxy]
|
|
||||||
$proxies .= Surge::buildShadowsocks($user['uuid'], $item);
|
|
||||||
// [Proxy Group]
|
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
// [Proxy]
|
|
||||||
$proxies .= Surge::buildVmess($user['uuid'], $item);
|
|
||||||
// [Proxy Group]
|
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'trojan') {
|
|
||||||
// [Proxy]
|
|
||||||
$proxies .= Surge::buildTrojan($user['uuid'], $item);
|
|
||||||
// [Proxy Group]
|
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$defaultConfig = base_path() . '/resources/rules/default.surge.conf';
|
|
||||||
$customConfig = base_path() . '/resources/rules/custom.surge.conf';
|
|
||||||
if (\File::exists($customConfig)) {
|
|
||||||
$config = file_get_contents("$customConfig");
|
|
||||||
} else {
|
|
||||||
$config = file_get_contents("$defaultConfig");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscription link
|
|
||||||
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
|
||||||
|
|
||||||
$config = str_replace('$subs_link', $subsURL, $config);
|
|
||||||
$config = str_replace('$proxies', $proxies, $config);
|
|
||||||
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function surfboard($user, $servers = [])
|
|
||||||
{
|
|
||||||
$proxies = '';
|
|
||||||
$proxyGroup = '';
|
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
// [Proxy]
|
|
||||||
$proxies .= Surfboard::buildShadowsocks($user['uuid'], $item);
|
|
||||||
// [Proxy Group]
|
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
// [Proxy]
|
|
||||||
$proxies .= Surfboard::buildVmess($user['uuid'], $item);
|
|
||||||
// [Proxy Group]
|
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$defaultConfig = base_path() . '/resources/rules/default.surfboard.conf';
|
|
||||||
$customConfig = base_path() . '/resources/rules/custom.surfboard.conf';
|
|
||||||
if (\File::exists($customConfig)) {
|
|
||||||
$config = file_get_contents("$customConfig");
|
|
||||||
} else {
|
|
||||||
$config = file_get_contents("$defaultConfig");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscription link
|
|
||||||
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
|
||||||
|
|
||||||
$config = str_replace('$subs_link', $subsURL, $config);
|
|
||||||
$config = str_replace('$proxies', $proxies, $config);
|
|
||||||
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function clash($user, $servers = [])
|
|
||||||
{
|
|
||||||
$defaultConfig = base_path() . '/resources/rules/default.clash.yaml';
|
|
||||||
$customConfig = base_path() . '/resources/rules/custom.clash.yaml';
|
|
||||||
if (\File::exists($customConfig)) {
|
|
||||||
$config = Yaml::parseFile($customConfig);
|
|
||||||
} else {
|
|
||||||
$config = Yaml::parseFile($defaultConfig);
|
|
||||||
}
|
|
||||||
$proxy = [];
|
|
||||||
$proxies = [];
|
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
array_push($proxy, Clash::buildShadowsocks($user['uuid'], $item));
|
|
||||||
array_push($proxies, $item['name']);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'v2ray') {
|
|
||||||
array_push($proxy, Clash::buildVmess($user['uuid'], $item));
|
|
||||||
array_push($proxies, $item['name']);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'trojan') {
|
|
||||||
array_push($proxy, Clash::buildTrojan($user['uuid'], $item));
|
|
||||||
array_push($proxies, $item['name']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$config['proxies'] = array_merge($config['proxies'] ? $config['proxies'] : [], $proxy);
|
|
||||||
foreach ($config['proxy-groups'] as $k => $v) {
|
|
||||||
if (!is_array($config['proxy-groups'][$k]['proxies'])) continue;
|
|
||||||
$config['proxy-groups'][$k]['proxies'] = array_merge($config['proxy-groups'][$k]['proxies'], $proxies);
|
|
||||||
}
|
|
||||||
$yaml = Yaml::dump($config);
|
|
||||||
$yaml = str_replace('$app_name', config('v2board.app_name', 'V2Board'), $yaml);
|
|
||||||
return $yaml;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
93
app/Http/Controllers/Client/Protocols/AnXray.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
class AnXray
|
||||||
|
{
|
||||||
|
public $flag = 'anxray';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
$uri = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildShadowsocks($uuid, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$str = str_replace(
|
||||||
|
['+', '/', '='],
|
||||||
|
['-', '_', ''],
|
||||||
|
base64_encode("{$server['cipher']}:{$uuid}")
|
||||||
|
);
|
||||||
|
return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildShadowsocksSIP008($uuid, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"id" => $server['id'],
|
||||||
|
"remarks" => $server['name'],
|
||||||
|
"server" => $server['host'],
|
||||||
|
"server_port" => $server['port'],
|
||||||
|
"password" => $uuid,
|
||||||
|
"method" => $server['cipher']
|
||||||
|
];
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildVmess($uuid, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"encryption" => "none",
|
||||||
|
"type" => urlencode($server['network']),
|
||||||
|
"security" => $server['tls'] ? "tls" : "",
|
||||||
|
"sni" => $server['tls'] ? urlencode(json_decode($server['tlsSettings'], true)['serverName']) : ""
|
||||||
|
];
|
||||||
|
if ((string)$server['network'] === 'ws') {
|
||||||
|
$wsSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($wsSettings['path'])) $config['path'] = urlencode($wsSettings['path']);
|
||||||
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = urlencode($wsSettings['headers']['Host']);
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'grpc') {
|
||||||
|
$grpcSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($grpcSettings['serviceName'])) $config['serviceName'] = urlencode($grpcSettings['serviceName']);
|
||||||
|
}
|
||||||
|
return "vmess://" . $uuid . "@" . $server['host'] . ":" . $server['port'] . "?" . http_build_query($config) . "#" . urlencode($server['name']) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildTrojan($uuid, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$query = http_build_query([
|
||||||
|
'allowInsecure' => $server['allow_insecure'],
|
||||||
|
'peer' => $server['server_name'],
|
||||||
|
'sni' => $server['server_name']
|
||||||
|
]);
|
||||||
|
$uri = "trojan://{$uuid}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
||||||
|
$uri .= "\r\n";
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,61 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
class Clash
|
class Clash
|
||||||
{
|
{
|
||||||
|
public $flag = 'clash';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
header("subscription-userinfo: upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}");
|
||||||
|
$defaultConfig = base_path() . '/resources/rules/default.clash.yaml';
|
||||||
|
$customConfig = base_path() . '/resources/rules/custom.clash.yaml';
|
||||||
|
if (\File::exists($customConfig)) {
|
||||||
|
$config = Yaml::parseFile($customConfig);
|
||||||
|
} else {
|
||||||
|
$config = Yaml::parseFile($defaultConfig);
|
||||||
|
}
|
||||||
|
$proxy = [];
|
||||||
|
$proxies = [];
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
array_push($proxy, self::buildShadowsocks($user['uuid'], $item));
|
||||||
|
array_push($proxies, $item['name']);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
array_push($proxy, self::buildVmess($user['uuid'], $item));
|
||||||
|
array_push($proxies, $item['name']);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
array_push($proxy, self::buildTrojan($user['uuid'], $item));
|
||||||
|
array_push($proxies, $item['name']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$config['proxies'] = array_merge($config['proxies'] ? $config['proxies'] : [], $proxy);
|
||||||
|
foreach ($config['proxy-groups'] as $k => $v) {
|
||||||
|
if (!is_array($config['proxy-groups'][$k]['proxies'])) continue;
|
||||||
|
$config['proxy-groups'][$k]['proxies'] = array_merge($config['proxy-groups'][$k]['proxies'], $proxies);
|
||||||
|
}
|
||||||
|
$yaml = Yaml::dump($config);
|
||||||
|
$yaml = str_replace('$app_name', config('v2board.app_name', 'V2Board'), $yaml);
|
||||||
|
return $yaml;
|
||||||
|
}
|
||||||
|
|
||||||
public static function buildShadowsocks($uuid, $server)
|
public static function buildShadowsocks($uuid, $server)
|
||||||
{
|
{
|
||||||
$array = [];
|
$array = [];
|
||||||
@ -50,6 +101,14 @@ class Clash
|
|||||||
$array['ws-headers'] = ['Host' => $wsSettings['headers']['Host']];
|
$array['ws-headers'] = ['Host' => $wsSettings['headers']['Host']];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($server['network'] === 'grpc') {
|
||||||
|
$array['network'] = 'grpc';
|
||||||
|
if ($server['networkSettings']) {
|
||||||
|
$grpcObject = json_decode($server['networkSettings'], true);
|
||||||
|
$array['grpc-opts'] = [];
|
||||||
|
$array['grpc-opts']['grpc-service-name'] = $grpcObject['serviceName'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
96
app/Http/Controllers/Client/Protocols/Passwall.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
|
class Passwall
|
||||||
|
{
|
||||||
|
public $flag = 'passwall';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
$uri = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildShadowsocks($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$str = str_replace(
|
||||||
|
['+', '/', '='],
|
||||||
|
['-', '_', ''],
|
||||||
|
base64_encode("{$server['cipher']}:{$password}")
|
||||||
|
);
|
||||||
|
return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildVmess($uuid, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"v" => "2",
|
||||||
|
"ps" => $server['name'],
|
||||||
|
"add" => $server['host'],
|
||||||
|
"port" => (string)$server['port'],
|
||||||
|
"id" => $uuid,
|
||||||
|
"aid" => (string)$server['alter_id'],
|
||||||
|
"net" => $server['network'],
|
||||||
|
"type" => "none",
|
||||||
|
"host" => "",
|
||||||
|
"path" => "",
|
||||||
|
"tls" => $server['tls'] ? "tls" : "",
|
||||||
|
];
|
||||||
|
if ($server['tls']) {
|
||||||
|
if ($server['tlsSettings']) {
|
||||||
|
$tlsSettings = json_decode($server['tlsSettings'], true);
|
||||||
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'ws') {
|
||||||
|
$wsSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'grpc') {
|
||||||
|
$grpcSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
|
}
|
||||||
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildTrojan($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$query = http_build_query([
|
||||||
|
'allowInsecure' => $server['allow_insecure'],
|
||||||
|
'peer' => $server['server_name'],
|
||||||
|
'sni' => $server['server_name']
|
||||||
|
]);
|
||||||
|
$uri = "trojan://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
||||||
|
$uri .= "\r\n";
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,40 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
class QuantumultX
|
class QuantumultX
|
||||||
{
|
{
|
||||||
|
public $flag = 'quantumult%20x';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
$uri = '';
|
||||||
|
header("subscription-userinfo: upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}");
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
public static function buildShadowsocks($password, $server)
|
public static function buildShadowsocks($password, $server)
|
||||||
{
|
{
|
||||||
$config = [
|
$config = [
|
96
app/Http/Controllers/Client/Protocols/SSRPlus.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
|
class SSRPlus
|
||||||
|
{
|
||||||
|
public $flag = 'ssrplus';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
$uri = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildShadowsocks($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$str = str_replace(
|
||||||
|
['+', '/', '='],
|
||||||
|
['-', '_', ''],
|
||||||
|
base64_encode("{$server['cipher']}:{$password}")
|
||||||
|
);
|
||||||
|
return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildVmess($uuid, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"v" => "2",
|
||||||
|
"ps" => $server['name'],
|
||||||
|
"add" => $server['host'],
|
||||||
|
"port" => (string)$server['port'],
|
||||||
|
"id" => $uuid,
|
||||||
|
"aid" => (string)$server['alter_id'],
|
||||||
|
"net" => $server['network'],
|
||||||
|
"type" => "none",
|
||||||
|
"host" => "",
|
||||||
|
"path" => "",
|
||||||
|
"tls" => $server['tls'] ? "tls" : "",
|
||||||
|
];
|
||||||
|
if ($server['tls']) {
|
||||||
|
if ($server['tlsSettings']) {
|
||||||
|
$tlsSettings = json_decode($server['tlsSettings'], true);
|
||||||
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'ws') {
|
||||||
|
$wsSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'grpc') {
|
||||||
|
$grpcSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
|
}
|
||||||
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildTrojan($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$query = http_build_query([
|
||||||
|
'allowInsecure' => $server['allow_insecure'],
|
||||||
|
'peer' => $server['server_name'],
|
||||||
|
'sni' => $server['server_name']
|
||||||
|
]);
|
||||||
|
$uri = "trojan://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
||||||
|
$uri .= "\r\n";
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,46 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
class Shadowrocket
|
class Shadowrocket
|
||||||
{
|
{
|
||||||
|
public $flag = 'shadowrocket';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
|
$uri = '';
|
||||||
|
//display remaining traffic and expire date
|
||||||
|
$upload = round($user['u'] / (1024*1024*1024), 2);
|
||||||
|
$download = round($user['d'] / (1024*1024*1024), 2);
|
||||||
|
$totalTraffic = round($user['transfer_enable'] / (1024*1024*1024), 2);
|
||||||
|
$expiredDate = date('Y-m-d', $user['expired_at']);
|
||||||
|
$uri .= "STATUS=🚀↑:{$upload}GB,↓:{$download}GB,TOT:{$totalTraffic}GB💡Expires:{$expiredDate}\r\n";
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function buildShadowsocks($password, $server)
|
public static function buildShadowsocks($password, $server)
|
||||||
{
|
{
|
||||||
$name = rawurlencode($server['name']);
|
$name = rawurlencode($server['name']);
|
||||||
@ -44,6 +80,19 @@ class Shadowrocket
|
|||||||
$config['obfsParam'] = $wsSettings['headers']['Host'];
|
$config['obfsParam'] = $wsSettings['headers']['Host'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($server['network'] === 'grpc') {
|
||||||
|
$config['obfs'] = "grpc";
|
||||||
|
if ($server['networkSettings']) {
|
||||||
|
$grpcSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($grpcSettings['serviceName']) && !empty($grpcSettings['serviceName']))
|
||||||
|
$config['path'] = $grpcSettings['serviceName'];
|
||||||
|
}
|
||||||
|
if (isset($tlsSettings)) {
|
||||||
|
$config['host'] = $tlsSettings['serverName'];
|
||||||
|
} else {
|
||||||
|
$config['host'] = $server['host'];
|
||||||
|
}
|
||||||
|
}
|
||||||
$query = http_build_query($config, '', '&', PHP_QUERY_RFC3986);
|
$query = http_build_query($config, '', '&', PHP_QUERY_RFC3986);
|
||||||
$uri = "vmess://{$userinfo}?{$query}";
|
$uri = "vmess://{$userinfo}?{$query}";
|
||||||
$uri .= "\r\n";
|
$uri .= "\r\n";
|
57
app/Http/Controllers/Client/Protocols/Shadowsocks.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
class Shadowsocks
|
||||||
|
{
|
||||||
|
public $flag = 'shadowsocks';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
|
$configs = [];
|
||||||
|
$subs = [];
|
||||||
|
$subs['servers'] = [];
|
||||||
|
$subs['bytes_used'] = '';
|
||||||
|
$subs['bytes_remaining'] = '';
|
||||||
|
|
||||||
|
$bytesUsed = $user['u'] + $user['d'];
|
||||||
|
$bytesRemaining = $user['transfer_enable'] - $bytesUsed;
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
array_push($configs, self::SIP008($item, $user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$subs['version'] = 1;
|
||||||
|
$subs['bytes_used'] = $bytesUsed;
|
||||||
|
$subs['bytes_remaining'] = $bytesRemaining;
|
||||||
|
$subs['servers'] = array_merge($subs['servers'] ? $subs['servers'] : [], $configs);
|
||||||
|
|
||||||
|
return json_encode($subs, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function SIP008($server, $user)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"id" => $server['id'],
|
||||||
|
"remarks" => $server['name'],
|
||||||
|
"server" => $server['host'],
|
||||||
|
"server_port" => $server['port'],
|
||||||
|
"password" => $user['uuid'],
|
||||||
|
"method" => $server['cipher']
|
||||||
|
];
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,61 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
class Surfboard
|
class Surfboard
|
||||||
{
|
{
|
||||||
|
public $flag = 'surfboard';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
|
$proxies = '';
|
||||||
|
$proxyGroup = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
// [Proxy]
|
||||||
|
$proxies .= Surfboard::buildShadowsocks($user['uuid'], $item);
|
||||||
|
// [Proxy Group]
|
||||||
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
// [Proxy]
|
||||||
|
$proxies .= Surfboard::buildVmess($user['uuid'], $item);
|
||||||
|
// [Proxy Group]
|
||||||
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultConfig = base_path() . '/resources/rules/default.surfboard.conf';
|
||||||
|
$customConfig = base_path() . '/resources/rules/custom.surfboard.conf';
|
||||||
|
if (\File::exists($customConfig)) {
|
||||||
|
$config = file_get_contents("$customConfig");
|
||||||
|
} else {
|
||||||
|
$config = file_get_contents("$defaultConfig");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscription link
|
||||||
|
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
||||||
|
|
||||||
|
$config = str_replace('$subs_link', $subsURL, $config);
|
||||||
|
$config = str_replace('$proxies', $proxies, $config);
|
||||||
|
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function buildShadowsocks($password, $server)
|
public static function buildShadowsocks($password, $server)
|
||||||
{
|
{
|
||||||
$config = [
|
$config = [
|
@ -1,10 +1,66 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
class Surge
|
class Surge
|
||||||
{
|
{
|
||||||
|
public $flag = 'surge';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
|
$proxies = '';
|
||||||
|
$proxyGroup = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
// [Proxy]
|
||||||
|
$proxies .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
// [Proxy Group]
|
||||||
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
// [Proxy]
|
||||||
|
$proxies .= self::buildVmess($user['uuid'], $item);
|
||||||
|
// [Proxy Group]
|
||||||
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
// [Proxy]
|
||||||
|
$proxies .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
// [Proxy Group]
|
||||||
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultConfig = base_path() . '/resources/rules/default.surge.conf';
|
||||||
|
$customConfig = base_path() . '/resources/rules/custom.surge.conf';
|
||||||
|
if (\File::exists($customConfig)) {
|
||||||
|
$config = file_get_contents("$customConfig");
|
||||||
|
} else {
|
||||||
|
$config = file_get_contents("$defaultConfig");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscription link
|
||||||
|
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
||||||
|
|
||||||
|
$config = str_replace('$subs_link', $subsURL, $config);
|
||||||
|
$config = str_replace('$proxies', $proxies, $config);
|
||||||
|
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function buildShadowsocks($password, $server)
|
public static function buildShadowsocks($password, $server)
|
||||||
{
|
{
|
||||||
$config = [
|
$config = [
|
96
app/Http/Controllers/Client/Protocols/V2rayN.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
|
class V2rayN
|
||||||
|
{
|
||||||
|
public $flag = 'v2rayn';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
$uri = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildShadowsocks($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$str = str_replace(
|
||||||
|
['+', '/', '='],
|
||||||
|
['-', '_', ''],
|
||||||
|
base64_encode("{$server['cipher']}:{$password}")
|
||||||
|
);
|
||||||
|
return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildVmess($uuid, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"v" => "2",
|
||||||
|
"ps" => $server['name'],
|
||||||
|
"add" => $server['host'],
|
||||||
|
"port" => (string)$server['port'],
|
||||||
|
"id" => $uuid,
|
||||||
|
"aid" => (string)$server['alter_id'],
|
||||||
|
"net" => $server['network'],
|
||||||
|
"type" => "none",
|
||||||
|
"host" => "",
|
||||||
|
"path" => "",
|
||||||
|
"tls" => $server['tls'] ? "tls" : "",
|
||||||
|
];
|
||||||
|
if ($server['tls']) {
|
||||||
|
if ($server['tlsSettings']) {
|
||||||
|
$tlsSettings = json_decode($server['tlsSettings'], true);
|
||||||
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'ws') {
|
||||||
|
$wsSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'grpc') {
|
||||||
|
$grpcSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
|
}
|
||||||
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildTrojan($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$query = http_build_query([
|
||||||
|
'allowInsecure' => $server['allow_insecure'],
|
||||||
|
'peer' => $server['server_name'],
|
||||||
|
'sni' => $server['server_name']
|
||||||
|
]);
|
||||||
|
$uri = "trojan://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
||||||
|
$uri .= "\r\n";
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
97
app/Http/Controllers/Client/Protocols/V2rayNG.php
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Client\Protocols;
|
||||||
|
|
||||||
|
|
||||||
|
class V2rayNG
|
||||||
|
{
|
||||||
|
public $flag = 'v2rayng';
|
||||||
|
private $servers;
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
public function __construct($user, $servers)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->servers = $servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->servers;
|
||||||
|
$user = $this->user;
|
||||||
|
$uri = '';
|
||||||
|
|
||||||
|
foreach ($servers as $item) {
|
||||||
|
if ($item['type'] === 'v2ray') {
|
||||||
|
$uri .= self::buildVmess($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'shadowsocks') {
|
||||||
|
$uri .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base64_encode($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildShadowsocks($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$str = str_replace(
|
||||||
|
['+', '/', '='],
|
||||||
|
['-', '_', ''],
|
||||||
|
base64_encode("{$server['cipher']}:{$password}")
|
||||||
|
);
|
||||||
|
return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildVmess($uuid, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"v" => "2",
|
||||||
|
"ps" => $server['name'],
|
||||||
|
"add" => $server['host'],
|
||||||
|
"port" => (string)$server['port'],
|
||||||
|
"id" => $uuid,
|
||||||
|
"aid" => (string)$server['alter_id'],
|
||||||
|
"net" => $server['network'],
|
||||||
|
"type" => "none",
|
||||||
|
"host" => "",
|
||||||
|
"path" => "",
|
||||||
|
"tls" => $server['tls'] ? "tls" : "",
|
||||||
|
];
|
||||||
|
if ($server['tls']) {
|
||||||
|
if ($server['tlsSettings']) {
|
||||||
|
$tlsSettings = json_decode($server['tlsSettings'], true);
|
||||||
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'ws') {
|
||||||
|
$wsSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
|
}
|
||||||
|
if ((string)$server['network'] === 'grpc') {
|
||||||
|
$grpcSettings = json_decode($server['networkSettings'], true);
|
||||||
|
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
|
}
|
||||||
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildTrojan($password, $server)
|
||||||
|
{
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
$query = http_build_query([
|
||||||
|
'allowInsecure' => $server['allow_insecure'],
|
||||||
|
'peer' => $server['server_name'],
|
||||||
|
'sni' => $server['server_name']
|
||||||
|
]);
|
||||||
|
$uri = "trojan://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
||||||
|
$uri .= "\r\n";
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -11,8 +11,26 @@ class CommController extends Controller
|
|||||||
{
|
{
|
||||||
return response([
|
return response([
|
||||||
'data' => [
|
'data' => [
|
||||||
'tos_url' => config('v2board.tos_url')
|
'tos_url' => config('v2board.tos_url'),
|
||||||
|
'is_email_verify' => (int)config('v2board.email_verify', 0) ? 1 : 0,
|
||||||
|
'is_invite_force' => (int)config('v2board.invite_force', 0) ? 1 : 0,
|
||||||
|
'email_whitelist_suffix' => (int)config('v2board.email_whitelist_enable', 0)
|
||||||
|
? $this->getEmailSuffix()
|
||||||
|
: 0,
|
||||||
|
'is_recaptcha' => (int)config('v2board.recaptcha_enable', 0) ? 1 : 0,
|
||||||
|
'recaptcha_site_key' => config('v2board.recaptcha_site_key'),
|
||||||
|
'app_description' => config('v2board.app_description'),
|
||||||
|
'app_url' => config('v2board.app_url')
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getEmailSuffix()
|
||||||
|
{
|
||||||
|
$suffix = config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT);
|
||||||
|
if (!is_array($suffix)) {
|
||||||
|
return preg_split('/,/', $suffix);
|
||||||
|
}
|
||||||
|
return $suffix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class PaymentController extends Controller
|
|||||||
if (!$this->handle($verify['trade_no'], $verify['callback_no'])) {
|
if (!$this->handle($verify['trade_no'], $verify['callback_no'])) {
|
||||||
abort(500, 'handle error');
|
abort(500, 'handle error');
|
||||||
}
|
}
|
||||||
die('success');
|
die(isset($paymentService->customResult) ? $paymentService->customResult : 'success');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
abort(500, 'fail');
|
abort(500, 'fail');
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,7 @@ class TelegramController extends Controller
|
|||||||
}
|
}
|
||||||
$telegramService = new TelegramService();
|
$telegramService = new TelegramService();
|
||||||
$telegramService->sendMessage($msg->chat_id, "#`{$ticketId}` 的工单已回复成功", 'markdown');
|
$telegramService->sendMessage($msg->chat_id, "#`{$ticketId}` 的工单已回复成功", 'markdown');
|
||||||
|
$telegramService->sendMessageWithAdmin("#`{$ticketId}` 的工单已由 {$user->email} 进行回复", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class AuthController extends Controller
|
|||||||
$recaptcha = new ReCaptcha(config('v2board.recaptcha_key'));
|
$recaptcha = new ReCaptcha(config('v2board.recaptcha_key'));
|
||||||
$recaptchaResp = $recaptcha->verify($request->input('recaptcha_data'));
|
$recaptchaResp = $recaptcha->verify($request->input('recaptcha_data'));
|
||||||
if (!$recaptchaResp->isSuccess()) {
|
if (!$recaptchaResp->isSuccess()) {
|
||||||
abort(500, '验证码有误');
|
abort(500, __('Invalid code is incorrect'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((int)config('v2board.email_whitelist_enable', 0)) {
|
if ((int)config('v2board.email_whitelist_enable', 0)) {
|
||||||
@ -32,36 +32,36 @@ class AuthController extends Controller
|
|||||||
$request->input('email'),
|
$request->input('email'),
|
||||||
config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT))
|
config('v2board.email_whitelist_suffix', Dict::EMAIL_WHITELIST_SUFFIX_DEFAULT))
|
||||||
) {
|
) {
|
||||||
abort(500, '邮箱后缀不处于白名单中');
|
abort(500, __('Email suffix is not in the Whitelist'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((int)config('v2board.email_gmail_limit_enable', 0)) {
|
if ((int)config('v2board.email_gmail_limit_enable', 0)) {
|
||||||
$prefix = explode('@', $request->input('email'))[0];
|
$prefix = explode('@', $request->input('email'))[0];
|
||||||
if (strpos($prefix, '.') !== false || strpos($prefix, '+') !== false) {
|
if (strpos($prefix, '.') !== false || strpos($prefix, '+') !== false) {
|
||||||
abort(500, '不支持Gmail别名邮箱');
|
abort(500, __('Gmail alias is not supported'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((int)config('v2board.stop_register', 0)) {
|
if ((int)config('v2board.stop_register', 0)) {
|
||||||
abort(500, '本站已关闭注册');
|
abort(500, __('Registration has closed'));
|
||||||
}
|
}
|
||||||
if ((int)config('v2board.invite_force', 0)) {
|
if ((int)config('v2board.invite_force', 0)) {
|
||||||
if (empty($request->input('invite_code'))) {
|
if (empty($request->input('invite_code'))) {
|
||||||
abort(500, '必须使用邀请码才可以注册');
|
abort(500, __('You must use the invitation code to register'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((int)config('v2board.email_verify', 0)) {
|
if ((int)config('v2board.email_verify', 0)) {
|
||||||
if (empty($request->input('email_code'))) {
|
if (empty($request->input('email_code'))) {
|
||||||
abort(500, '邮箱验证码不能为空');
|
abort(500, __('Email verification code cannot be empty'));
|
||||||
}
|
}
|
||||||
if (Cache::get(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email'))) !== $request->input('email_code')) {
|
if (Cache::get(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email'))) !== $request->input('email_code')) {
|
||||||
abort(500, '邮箱验证码有误');
|
abort(500, __('Incorrect email verification code'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$email = $request->input('email');
|
$email = $request->input('email');
|
||||||
$password = $request->input('password');
|
$password = $request->input('password');
|
||||||
$exist = User::where('email', $email)->first();
|
$exist = User::where('email', $email)->first();
|
||||||
if ($exist) {
|
if ($exist) {
|
||||||
abort(500, '邮箱已存在系统中');
|
abort(500, __('Email already exists'));
|
||||||
}
|
}
|
||||||
$user = new User();
|
$user = new User();
|
||||||
$user->email = $email;
|
$user->email = $email;
|
||||||
@ -74,7 +74,7 @@ class AuthController extends Controller
|
|||||||
->first();
|
->first();
|
||||||
if (!$inviteCode) {
|
if (!$inviteCode) {
|
||||||
if ((int)config('v2board.invite_force', 0)) {
|
if ((int)config('v2board.invite_force', 0)) {
|
||||||
abort(500, '邀请码无效');
|
abort(500, __('Invalid invitation code'));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$user->invite_user_id = $inviteCode->user_id ? $inviteCode->user_id : null;
|
$user->invite_user_id = $inviteCode->user_id ? $inviteCode->user_id : null;
|
||||||
@ -97,7 +97,7 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, '注册失败');
|
abort(500, __('Register failed'));
|
||||||
}
|
}
|
||||||
if ((int)config('v2board.email_verify', 0)) {
|
if ((int)config('v2board.email_verify', 0)) {
|
||||||
Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
|
Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
|
||||||
@ -116,18 +116,18 @@ class AuthController extends Controller
|
|||||||
|
|
||||||
$user = User::where('email', $email)->first();
|
$user = User::where('email', $email)->first();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, '用户名或密码错误');
|
abort(500, __('Incorrect email or password'));
|
||||||
}
|
}
|
||||||
if (!Helper::multiPasswordVerify(
|
if (!Helper::multiPasswordVerify(
|
||||||
$user->password_algo,
|
$user->password_algo,
|
||||||
$password,
|
$password,
|
||||||
$user->password)
|
$user->password)
|
||||||
) {
|
) {
|
||||||
abort(500, '用户名或密码错误');
|
abort(500, __('Incorrect email or password'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user->banned) {
|
if ($user->banned) {
|
||||||
abort(500, '该账户已被停止使用');
|
abort(500, __('Your account has been suspended'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
@ -165,14 +165,14 @@ class AuthController extends Controller
|
|||||||
$key = CacheKey::get('TEMP_TOKEN', $request->input('verify'));
|
$key = CacheKey::get('TEMP_TOKEN', $request->input('verify'));
|
||||||
$userId = Cache::get($key);
|
$userId = Cache::get($key);
|
||||||
if (!$userId) {
|
if (!$userId) {
|
||||||
abort(500, '令牌有误');
|
abort(500, __('Token error'));
|
||||||
}
|
}
|
||||||
$user = User::find($userId);
|
$user = User::find($userId);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, '用户不存在');
|
abort(500, __('The user does not '));
|
||||||
}
|
}
|
||||||
if ($user->banned) {
|
if ($user->banned) {
|
||||||
abort(500, '该账户已被停止使用');
|
abort(500, __('Your account has been suspended'));
|
||||||
}
|
}
|
||||||
$request->session()->put('email', $user->email);
|
$request->session()->put('email', $user->email);
|
||||||
$request->session()->put('id', $user->id);
|
$request->session()->put('id', $user->id);
|
||||||
@ -190,7 +190,7 @@ class AuthController extends Controller
|
|||||||
{
|
{
|
||||||
$user = User::where('token', $request->input('token'))->first();
|
$user = User::where('token', $request->input('token'))->first();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, '令牌有误');
|
abort(500, __('Token error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$code = Helper::guid();
|
$code = Helper::guid();
|
||||||
@ -204,11 +204,12 @@ class AuthController extends Controller
|
|||||||
public function getQuickLoginUrl(Request $request)
|
public function getQuickLoginUrl(Request $request)
|
||||||
{
|
{
|
||||||
$authData = explode(':', base64_decode($request->input('auth_data')));
|
$authData = explode(':', base64_decode($request->input('auth_data')));
|
||||||
|
if (!isset($authData[0])) abort(403, __('Token error'));
|
||||||
$user = User::where('email', $authData[0])
|
$user = User::where('email', $authData[0])
|
||||||
->where('password', $authData[1])
|
->where('password', $authData[1])
|
||||||
->first();
|
->first();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, '令牌有误');
|
abort(500, __('Token error'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$code = Helper::guid();
|
$code = Helper::guid();
|
||||||
@ -241,16 +242,16 @@ class AuthController extends Controller
|
|||||||
public function forget(AuthForget $request)
|
public function forget(AuthForget $request)
|
||||||
{
|
{
|
||||||
if (Cache::get(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email'))) !== $request->input('email_code')) {
|
if (Cache::get(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email'))) !== $request->input('email_code')) {
|
||||||
abort(500, '邮箱验证码有误');
|
abort(500, __('Incorrect email verification code'));
|
||||||
}
|
}
|
||||||
$user = User::where('email', $request->input('email'))->first();
|
$user = User::where('email', $request->input('email'))->first();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, '该邮箱不存在系统中');
|
abort(500, __('This email is not registered in the system'));
|
||||||
}
|
}
|
||||||
$user->password = password_hash($request->input('password'), PASSWORD_DEFAULT);
|
$user->password = password_hash($request->input('password'), PASSWORD_DEFAULT);
|
||||||
$user->password_algo = NULL;
|
$user->password_algo = NULL;
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, '重置失败');
|
abort(500, __('Reset failed'));
|
||||||
}
|
}
|
||||||
Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
|
Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
|
||||||
return response([
|
return response([
|
||||||
|
@ -17,6 +17,7 @@ use ReCaptcha\ReCaptcha;
|
|||||||
|
|
||||||
class CommController extends Controller
|
class CommController extends Controller
|
||||||
{
|
{
|
||||||
|
// TODO: remove on 1.5.5
|
||||||
public function config()
|
public function config()
|
||||||
{
|
{
|
||||||
return response([
|
return response([
|
||||||
@ -47,15 +48,15 @@ class CommController extends Controller
|
|||||||
$recaptcha = new ReCaptcha(config('v2board.recaptcha_key'));
|
$recaptcha = new ReCaptcha(config('v2board.recaptcha_key'));
|
||||||
$recaptchaResp = $recaptcha->verify($request->input('recaptcha_data'));
|
$recaptchaResp = $recaptcha->verify($request->input('recaptcha_data'));
|
||||||
if (!$recaptchaResp->isSuccess()) {
|
if (!$recaptchaResp->isSuccess()) {
|
||||||
abort(500, '验证码有误');
|
abort(500, __('Invalid code is incorrect'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$email = $request->input('email');
|
$email = $request->input('email');
|
||||||
if (Cache::get(CacheKey::get('LAST_SEND_EMAIL_VERIFY_TIMESTAMP', $email))) {
|
if (Cache::get(CacheKey::get('LAST_SEND_EMAIL_VERIFY_TIMESTAMP', $email))) {
|
||||||
abort(500, '验证码已发送,请过一会再请求');
|
abort(500, __('Email verification code has been sent, please request again later'));
|
||||||
}
|
}
|
||||||
$code = rand(100000, 999999);
|
$code = rand(100000, 999999);
|
||||||
$subject = config('v2board.app_name', 'V2Board') . '邮箱验证码';
|
$subject = config('v2board.app_name', 'V2Board') . __('Email verification code');
|
||||||
|
|
||||||
SendEmailJob::dispatch([
|
SendEmailJob::dispatch([
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
|
@ -11,25 +11,25 @@ class CouponController extends Controller
|
|||||||
public function check(Request $request)
|
public function check(Request $request)
|
||||||
{
|
{
|
||||||
if (empty($request->input('code'))) {
|
if (empty($request->input('code'))) {
|
||||||
abort(500, __('user.coupon.check.coupon_not_empty'));
|
abort(500, __('Coupon cannot be empty'));
|
||||||
}
|
}
|
||||||
$coupon = Coupon::where('code', $request->input('code'))->first();
|
$coupon = Coupon::where('code', $request->input('code'))->first();
|
||||||
if (!$coupon) {
|
if (!$coupon) {
|
||||||
abort(500, __('user.coupon.check.coupon_invalid'));
|
abort(500, __('Invalid coupon'));
|
||||||
}
|
}
|
||||||
if ($coupon->limit_use <= 0 && $coupon->limit_use !== NULL) {
|
if ($coupon->limit_use <= 0 && $coupon->limit_use !== NULL) {
|
||||||
abort(500, __('user.coupon.check.coupon_not_available_by_number'));
|
abort(500, __('This coupon is no longer available'));
|
||||||
}
|
}
|
||||||
if (time() < $coupon->started_at) {
|
if (time() < $coupon->started_at) {
|
||||||
abort(500, __('user.coupon.check.coupon_not_available_by_time'));
|
abort(500, __('This coupon has not yet started'));
|
||||||
}
|
}
|
||||||
if (time() > $coupon->ended_at) {
|
if (time() > $coupon->ended_at) {
|
||||||
abort(500, __('user.coupon.check.coupon_expired'));
|
abort(500, __('This coupon has expired'));
|
||||||
}
|
}
|
||||||
if ($coupon->limit_plan_ids) {
|
if ($coupon->limit_plan_ids) {
|
||||||
$limitPlanIds = json_decode($coupon->limit_plan_ids);
|
$limitPlanIds = json_decode($coupon->limit_plan_ids);
|
||||||
if (!in_array($request->input('plan_id'), $limitPlanIds)) {
|
if (!in_array($request->input('plan_id'), $limitPlanIds)) {
|
||||||
abort(500, __('user.coupon.check.coupon_limit_plan'));
|
abort(500, __('The coupon code cannot be used for this subscription'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
|
@ -14,7 +14,7 @@ class InviteController extends Controller
|
|||||||
public function save(Request $request)
|
public function save(Request $request)
|
||||||
{
|
{
|
||||||
if (InviteCode::where('user_id', $request->session()->get('id'))->where('status', 0)->count() >= config('v2board.invite_gen_limit', 5)) {
|
if (InviteCode::where('user_id', $request->session()->get('id'))->where('status', 0)->count() >= config('v2board.invite_gen_limit', 5)) {
|
||||||
abort(500, __('user.invite.save.invite_create_limit'));
|
abort(500, __('The maximum number of creations has been reached'));
|
||||||
}
|
}
|
||||||
$inviteCode = new InviteCode();
|
$inviteCode = new InviteCode();
|
||||||
$inviteCode->user_id = $request->session()->get('id');
|
$inviteCode->user_id = $request->session()->get('id');
|
||||||
|
@ -17,18 +17,23 @@ class KnowledgeController extends Controller
|
|||||||
->where('show', 1)
|
->where('show', 1)
|
||||||
->first()
|
->first()
|
||||||
->toArray();
|
->toArray();
|
||||||
if (!$knowledge) abort(500, __('user.knowledge.fetch.knowledge_not_exist'));
|
if (!$knowledge) abort(500, __('Article does not exist'));
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
$userService = new UserService();
|
$userService = new UserService();
|
||||||
if ($userService->isAvailable($user)) {
|
if ($userService->isAvailable($user)) {
|
||||||
$appleId = config('v2board.apple_id');
|
$appleId = config('v2board.apple_id');
|
||||||
$appleIdPassword = config('v2board.apple_id_password');
|
$appleIdPassword = config('v2board.apple_id_password');
|
||||||
} else {
|
} else {
|
||||||
$appleId = __('user.knowledge.fetch.apple_id_must_be_plan');
|
$appleId = __('No active subscription. Unable to use our provided Apple ID');
|
||||||
$appleIdPassword = __('user.knowledge.fetch.apple_id_must_be_plan');
|
$appleIdPassword = __('No active subscription. Unable to use our provided Apple ID');
|
||||||
$this->formatAccessData($knowledge['body']);
|
$this->formatAccessData($knowledge['body']);
|
||||||
}
|
}
|
||||||
$subscribeUrl = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
$subscribeUrl = config('v2board.app_url', env('APP_URL'));
|
||||||
|
$subscribeUrls = explode(',', config('v2board.subscribe_url'));
|
||||||
|
if ($subscribeUrls) {
|
||||||
|
$subscribeUrl = $subscribeUrls[rand(0, count($subscribeUrls) - 1)];
|
||||||
|
}
|
||||||
|
$subscribeUrl = "{$subscribeUrl}/api/v1/client/subscribe?token={$user['token']}";
|
||||||
$knowledge['body'] = str_replace('{{siteName}}', config('v2board.app_name', 'V2Board'), $knowledge['body']);
|
$knowledge['body'] = str_replace('{{siteName}}', config('v2board.app_name', 'V2Board'), $knowledge['body']);
|
||||||
$knowledge['body'] = str_replace('{{appleId}}', $appleId, $knowledge['body']);
|
$knowledge['body'] = str_replace('{{appleId}}', $appleId, $knowledge['body']);
|
||||||
$knowledge['body'] = str_replace('{{appleIdPassword}}', $appleIdPassword, $knowledge['body']);
|
$knowledge['body'] = str_replace('{{appleIdPassword}}', $appleIdPassword, $knowledge['body']);
|
||||||
@ -63,7 +68,7 @@ class KnowledgeController extends Controller
|
|||||||
function getBetween($input, $start, $end){$substr = substr($input, strlen($start)+strpos($input, $start),(strlen($input) - strpos($input, $end))*(-1));return $substr;}
|
function getBetween($input, $start, $end){$substr = substr($input, strlen($start)+strpos($input, $start),(strlen($input) - strpos($input, $end))*(-1));return $substr;}
|
||||||
$accessData = getBetween($body, '<!--access start-->', '<!--access end-->');
|
$accessData = getBetween($body, '<!--access start-->', '<!--access end-->');
|
||||||
if ($accessData) {
|
if ($accessData) {
|
||||||
$body = str_replace($accessData, '<div class="v2board-no-access">'. __('user.knowledge.formatAccessData.no_access') .'</div>', $body);
|
$body = str_replace($accessData, '<div class="v2board-no-access">'. __('You must have a valid subscription to view content in this area') .'</div>', $body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,12 @@ class OrderController extends Controller
|
|||||||
->where('trade_no', $request->input('trade_no'))
|
->where('trade_no', $request->input('trade_no'))
|
||||||
->first();
|
->first();
|
||||||
if (!$order) {
|
if (!$order) {
|
||||||
abort(500, __('user.order.details.order_not_exist'));
|
abort(500, __('Order does not exist or has been paid'));
|
||||||
}
|
}
|
||||||
$order['plan'] = Plan::find($order->plan_id);
|
$order['plan'] = Plan::find($order->plan_id);
|
||||||
$order['try_out_plan_id'] = (int)config('v2board.try_out_plan_id');
|
$order['try_out_plan_id'] = (int)config('v2board.try_out_plan_id');
|
||||||
if (!$order['plan']) {
|
if (!$order['plan']) {
|
||||||
abort(500, __('user.order.details.plan_not_exist'));
|
abort(500, __('Subscription plan does not exist'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => $order
|
'data' => $order
|
||||||
@ -68,38 +68,38 @@ class OrderController extends Controller
|
|||||||
{
|
{
|
||||||
$userService = new UserService();
|
$userService = new UserService();
|
||||||
if ($userService->isNotCompleteOrderByUserId($request->session()->get('id'))) {
|
if ($userService->isNotCompleteOrderByUserId($request->session()->get('id'))) {
|
||||||
abort(500, __('user.order.save.exist_open_order'));
|
abort(500, __('You have an unpaid or pending order, please try again later or cancel it'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$plan = Plan::find($request->input('plan_id'));
|
$plan = Plan::find($request->input('plan_id'));
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
|
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
abort(500, __('user.order.save.plan_not_exist'));
|
abort(500, __('Subscription plan does not exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!$plan->show && !$plan->renew) || (!$plan->show && $user->plan_id !== $plan->id)) {
|
if ((!$plan->show && !$plan->renew) || (!$plan->show && $user->plan_id !== $plan->id)) {
|
||||||
if ($request->input('cycle') !== 'reset_price') {
|
if ($request->input('cycle') !== 'reset_price') {
|
||||||
abort(500, __('user.order.save.plan_stop_sell'));
|
abort(500, __('This subscription has been sold out, please choose another subscription'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$plan->renew && $user->plan_id == $plan->id && $request->input('cycle') !== 'reset_price') {
|
if (!$plan->renew && $user->plan_id == $plan->id && $request->input('cycle') !== 'reset_price') {
|
||||||
abort(500, __('user.order.save.plan_stop_renew'));
|
abort(500, __('This subscription cannot be renewed, please change to another subscription'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($plan[$request->input('cycle')] === NULL) {
|
if ($plan[$request->input('cycle')] === NULL) {
|
||||||
abort(500, __('user.order.save.plan_stop'));
|
abort(500, __('This payment cycle cannot be purchased, please choose another cycle'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->input('cycle') === 'reset_price') {
|
if ($request->input('cycle') === 'reset_price') {
|
||||||
if ($user->expired_at <= time() || !$user->plan_id) {
|
if ($user->expired_at <= time() || !$user->plan_id) {
|
||||||
abort(500, __('user.order.save.plan_exist_not_buy_package'));
|
abort(500, __('Subscription has expired or no active subscription, unable to purchase Data Reset Package'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$plan->show && $plan->renew && !$userService->isAvailable($user)) {
|
if (!$plan->show && $plan->renew && !$userService->isAvailable($user)) {
|
||||||
abort(500, __('user.order.save.plan_expired'));
|
abort(500, __('This subscription has expired, please change to another subscription'));
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
@ -115,7 +115,7 @@ class OrderController extends Controller
|
|||||||
$couponService = new CouponService($request->input('coupon_code'));
|
$couponService = new CouponService($request->input('coupon_code'));
|
||||||
if (!$couponService->use($order)) {
|
if (!$couponService->use($order)) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
abort(500, __('user.order.save.coupon_use_failed'));
|
abort(500, __('Coupon failed'));
|
||||||
}
|
}
|
||||||
$order->coupon_id = $couponService->getId();
|
$order->coupon_id = $couponService->getId();
|
||||||
}
|
}
|
||||||
@ -130,14 +130,14 @@ class OrderController extends Controller
|
|||||||
if ($remainingBalance > 0) {
|
if ($remainingBalance > 0) {
|
||||||
if (!$userService->addBalance($order->user_id, - $order->total_amount)) {
|
if (!$userService->addBalance($order->user_id, - $order->total_amount)) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
abort(500, __('user.order.save.insufficient_balance'));
|
abort(500, __('Insufficient balance'));
|
||||||
}
|
}
|
||||||
$order->balance_amount = $order->total_amount;
|
$order->balance_amount = $order->total_amount;
|
||||||
$order->total_amount = 0;
|
$order->total_amount = 0;
|
||||||
} else {
|
} else {
|
||||||
if (!$userService->addBalance($order->user_id, - $user->balance)) {
|
if (!$userService->addBalance($order->user_id, - $user->balance)) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
abort(500, __('user.order.save.insufficient_balance'));
|
abort(500, __('Insufficient balance'));
|
||||||
}
|
}
|
||||||
$order->balance_amount = $user->balance;
|
$order->balance_amount = $user->balance;
|
||||||
$order->total_amount = $order->total_amount - $user->balance;
|
$order->total_amount = $order->total_amount - $user->balance;
|
||||||
@ -146,7 +146,7 @@ class OrderController extends Controller
|
|||||||
|
|
||||||
if (!$order->save()) {
|
if (!$order->save()) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
abort(500, __('user.order.save.order_create_failed'));
|
abort(500, __('Failed to create order'));
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
@ -165,7 +165,7 @@ class OrderController extends Controller
|
|||||||
->where('status', 0)
|
->where('status', 0)
|
||||||
->first();
|
->first();
|
||||||
if (!$order) {
|
if (!$order) {
|
||||||
abort(500, __('user.order.checkout.order_not_exist_or_paid'));
|
abort(500, __('Order does not exist or has been paid'));
|
||||||
}
|
}
|
||||||
// free process
|
// free process
|
||||||
if ($order->total_amount <= 0) {
|
if ($order->total_amount <= 0) {
|
||||||
@ -178,7 +178,7 @@ class OrderController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$payment = Payment::find($method);
|
$payment = Payment::find($method);
|
||||||
if (!$payment || $payment->enable !== 1) abort(500, __('user.order.checkout.pay_method_not_use'));
|
if (!$payment || $payment->enable !== 1) abort(500, __('Payment method is not available'));
|
||||||
$paymentService = new PaymentService($payment->payment, $payment->id);
|
$paymentService = new PaymentService($payment->payment, $payment->id);
|
||||||
$result = $paymentService->pay([
|
$result = $paymentService->pay([
|
||||||
'trade_no' => $tradeNo,
|
'trade_no' => $tradeNo,
|
||||||
@ -200,7 +200,7 @@ class OrderController extends Controller
|
|||||||
->where('user_id', $request->session()->get('id'))
|
->where('user_id', $request->session()->get('id'))
|
||||||
->first();
|
->first();
|
||||||
if (!$order) {
|
if (!$order) {
|
||||||
abort(500, __('user.order.check.order_not_exist'));
|
abort(500, __('Order does not exist'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => $order->status
|
'data' => $order->status
|
||||||
@ -224,20 +224,20 @@ class OrderController extends Controller
|
|||||||
public function cancel(Request $request)
|
public function cancel(Request $request)
|
||||||
{
|
{
|
||||||
if (empty($request->input('trade_no'))) {
|
if (empty($request->input('trade_no'))) {
|
||||||
abort(500, __('user.order.cancel.params_wrong'));
|
abort(500, __('Invalid parameter'));
|
||||||
}
|
}
|
||||||
$order = Order::where('trade_no', $request->input('trade_no'))
|
$order = Order::where('trade_no', $request->input('trade_no'))
|
||||||
->where('user_id', $request->session()->get('id'))
|
->where('user_id', $request->session()->get('id'))
|
||||||
->first();
|
->first();
|
||||||
if (!$order) {
|
if (!$order) {
|
||||||
abort(500, __('user.order.cancel.order_not_exist'));
|
abort(500, __('Order does not exist'));
|
||||||
}
|
}
|
||||||
if ($order->status !== 0) {
|
if ($order->status !== 0) {
|
||||||
abort(500, __('user.order.cancel.only_cancel_pending_order'));
|
abort(500, __('You can only cancel pending orders'));
|
||||||
}
|
}
|
||||||
$orderService = new OrderService($order);
|
$orderService = new OrderService($order);
|
||||||
if (!$orderService->cancel()) {
|
if (!$orderService->cancel()) {
|
||||||
abort(500, __('user.order.cancel.cancel_failed'));
|
abort(500, __('Cancel failed'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => true
|
'data' => true
|
||||||
|
@ -14,7 +14,7 @@ class PlanController extends Controller
|
|||||||
$plan = Plan::where('id', $request->input('id'))
|
$plan = Plan::where('id', $request->input('id'))
|
||||||
->first();
|
->first();
|
||||||
if (!$plan) {
|
if (!$plan) {
|
||||||
abort(500, __('user.plan.fetch.plan_not_exist'));
|
abort(500, __('Subscription plan does not exist'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => $plan
|
'data' => $plan
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
namespace App\Http\Controllers\User;
|
namespace App\Http\Controllers\User;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
use App\Services\TelegramService;
|
use App\Services\TelegramService;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class TelegramController extends Controller
|
class TelegramController extends Controller
|
||||||
{
|
{
|
||||||
@ -17,4 +19,9 @@ class TelegramController extends Controller
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function unbind(Request $request)
|
||||||
|
{
|
||||||
|
$user = User::where('user_id', $request->session()->get('id'))->first();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class TicketController extends Controller
|
|||||||
->where('user_id', $request->session()->get('id'))
|
->where('user_id', $request->session()->get('id'))
|
||||||
->first();
|
->first();
|
||||||
if (!$ticket) {
|
if (!$ticket) {
|
||||||
abort(500, __('user.ticket.fetch.ticket_not_exist'));
|
abort(500, __('Ticket does not exist'));
|
||||||
}
|
}
|
||||||
$ticket['message'] = TicketMessage::where('ticket_id', $ticket->id)->get();
|
$ticket['message'] = TicketMessage::where('ticket_id', $ticket->id)->get();
|
||||||
for ($i = 0; $i < count($ticket['message']); $i++) {
|
for ($i = 0; $i < count($ticket['message']); $i++) {
|
||||||
@ -56,7 +56,7 @@ class TicketController extends Controller
|
|||||||
{
|
{
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
if ((int)Ticket::where('status', 0)->where('user_id', $request->session()->get('id'))->count()) {
|
if ((int)Ticket::where('status', 0)->where('user_id', $request->session()->get('id'))->count()) {
|
||||||
abort(500, __('user.ticket.save.exist_other_open_ticket'));
|
abort(500, __('There are other unresolved tickets'));
|
||||||
}
|
}
|
||||||
$ticket = Ticket::create(array_merge($request->only([
|
$ticket = Ticket::create(array_merge($request->only([
|
||||||
'subject',
|
'subject',
|
||||||
@ -67,7 +67,7 @@ class TicketController extends Controller
|
|||||||
]));
|
]));
|
||||||
if (!$ticket) {
|
if (!$ticket) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
abort(500, __('user.ticket.save.ticket_create_failed'));
|
abort(500, __('Failed to open ticket'));
|
||||||
}
|
}
|
||||||
$ticketMessage = TicketMessage::create([
|
$ticketMessage = TicketMessage::create([
|
||||||
'user_id' => $request->session()->get('id'),
|
'user_id' => $request->session()->get('id'),
|
||||||
@ -76,7 +76,7 @@ class TicketController extends Controller
|
|||||||
]);
|
]);
|
||||||
if (!$ticketMessage) {
|
if (!$ticketMessage) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
abort(500, __('user.ticket.save.ticket_create_failed'));
|
abort(500, __('Failed to open ticket'));
|
||||||
}
|
}
|
||||||
DB::commit();
|
DB::commit();
|
||||||
$this->sendNotify($ticket, $ticketMessage);
|
$this->sendNotify($ticket, $ticketMessage);
|
||||||
@ -88,22 +88,22 @@ class TicketController extends Controller
|
|||||||
public function reply(Request $request)
|
public function reply(Request $request)
|
||||||
{
|
{
|
||||||
if (empty($request->input('id'))) {
|
if (empty($request->input('id'))) {
|
||||||
abort(500, __('user.ticket.reply.params_wrong'));
|
abort(500, __('Invalid parameter'));
|
||||||
}
|
}
|
||||||
if (empty($request->input('message'))) {
|
if (empty($request->input('message'))) {
|
||||||
abort(500, __('user.ticket.reply.message_not_empty'));
|
abort(500, __('Message cannot be empty'));
|
||||||
}
|
}
|
||||||
$ticket = Ticket::where('id', $request->input('id'))
|
$ticket = Ticket::where('id', $request->input('id'))
|
||||||
->where('user_id', $request->session()->get('id'))
|
->where('user_id', $request->session()->get('id'))
|
||||||
->first();
|
->first();
|
||||||
if (!$ticket) {
|
if (!$ticket) {
|
||||||
abort(500, __('user.ticket.reply.ticket_not_exist'));
|
abort(500, __('Ticket does not exist'));
|
||||||
}
|
}
|
||||||
if ($ticket->status) {
|
if ($ticket->status) {
|
||||||
abort(500, __('user.ticket.reply.ticket_close_not_reply'));
|
abort(500, __('The ticket is closed and cannot be replied'));
|
||||||
}
|
}
|
||||||
if ($request->session()->get('id') == $this->getLastMessage($ticket->id)->user_id) {
|
if ($request->session()->get('id') == $this->getLastMessage($ticket->id)->user_id) {
|
||||||
abort(500, __('user.ticket.reply.wait_reply'));
|
abort(500, __('Please wait for the technical enginneer to reply'));
|
||||||
}
|
}
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
$ticketMessage = TicketMessage::create([
|
$ticketMessage = TicketMessage::create([
|
||||||
@ -114,7 +114,7 @@ class TicketController extends Controller
|
|||||||
$ticket->last_reply_user_id = $request->session()->get('id');
|
$ticket->last_reply_user_id = $request->session()->get('id');
|
||||||
if (!$ticketMessage || !$ticket->save()) {
|
if (!$ticketMessage || !$ticket->save()) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
abort(500, __('user.ticket.reply.ticket_reply_failed'));
|
abort(500, __('Ticket reply failed'));
|
||||||
}
|
}
|
||||||
DB::commit();
|
DB::commit();
|
||||||
$this->sendNotify($ticket, $ticketMessage);
|
$this->sendNotify($ticket, $ticketMessage);
|
||||||
@ -127,17 +127,17 @@ class TicketController extends Controller
|
|||||||
public function close(Request $request)
|
public function close(Request $request)
|
||||||
{
|
{
|
||||||
if (empty($request->input('id'))) {
|
if (empty($request->input('id'))) {
|
||||||
abort(500, __('user.ticket.close.params_wrong'));
|
abort(500, __('Invalid parameter'));
|
||||||
}
|
}
|
||||||
$ticket = Ticket::where('id', $request->input('id'))
|
$ticket = Ticket::where('id', $request->input('id'))
|
||||||
->where('user_id', $request->session()->get('id'))
|
->where('user_id', $request->session()->get('id'))
|
||||||
->first();
|
->first();
|
||||||
if (!$ticket) {
|
if (!$ticket) {
|
||||||
abort(500, __('user.ticket.close.ticket_not_exist'));
|
abort(500, __('Ticket does not exist'));
|
||||||
}
|
}
|
||||||
$ticket->status = 1;
|
$ticket->status = 1;
|
||||||
if (!$ticket->save()) {
|
if (!$ticket->save()) {
|
||||||
abort(500, __('user.ticket.close.close_failed'));
|
abort(500, __('Close failed'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => true
|
'data' => true
|
||||||
@ -163,15 +163,15 @@ class TicketController extends Controller
|
|||||||
Dict::WITHDRAW_METHOD_WHITELIST_DEFAULT
|
Dict::WITHDRAW_METHOD_WHITELIST_DEFAULT
|
||||||
)
|
)
|
||||||
)) {
|
)) {
|
||||||
abort(500, __('user.ticket.withdraw.not_support_withdraw_method'));
|
abort(500, __('Unsupported withdrawal method'));
|
||||||
}
|
}
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
$limit = config('v2board.commission_withdraw_limit', 100);
|
$limit = config('v2board.commission_withdraw_limit', 100);
|
||||||
if ($limit > ($user->commission_balance / 100)) {
|
if ($limit > ($user->commission_balance / 100)) {
|
||||||
abort(500, __('user.ticket.withdraw.system_require_withdraw_limit', ['limit' => $limit]));
|
abort(500, __('The current required minimum withdrawal commission is', ['limit' => $limit]));
|
||||||
}
|
}
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
$subject = __('user.ticket.withdraw.ticket_subject');
|
$subject = __('[Commission Withdrawal Request] This ticket is opened by the system');
|
||||||
$ticket = Ticket::create([
|
$ticket = Ticket::create([
|
||||||
'subject' => $subject,
|
'subject' => $subject,
|
||||||
'level' => 2,
|
'level' => 2,
|
||||||
@ -180,12 +180,12 @@ class TicketController extends Controller
|
|||||||
]);
|
]);
|
||||||
if (!$ticket) {
|
if (!$ticket) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
abort(500, __('user.ticket.withdraw.ticket_create_failed'));
|
abort(500, __('Failed to open ticket'));
|
||||||
}
|
}
|
||||||
$message = __('user.ticket.withdraw.ticket_message', [
|
$message = sprintf("%s\r\n%s",
|
||||||
'method' => $request->input('withdraw_method'),
|
__('Withdrawal method') . ":" . $request->input('withdraw_method'),
|
||||||
'account' => $request->input('withdraw_account')
|
__('Withdrawal account') . ":" . $request->input('withdraw_account')
|
||||||
]);
|
);
|
||||||
$ticketMessage = TicketMessage::create([
|
$ticketMessage = TicketMessage::create([
|
||||||
'user_id' => $request->session()->get('id'),
|
'user_id' => $request->session()->get('id'),
|
||||||
'ticket_id' => $ticket->id,
|
'ticket_id' => $ticket->id,
|
||||||
@ -193,7 +193,7 @@ class TicketController extends Controller
|
|||||||
]);
|
]);
|
||||||
if (!$ticketMessage) {
|
if (!$ticketMessage) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
abort(500, __('user.ticket.withdraw.ticket_create_failed'));
|
abort(500, __('Failed to open ticket'));
|
||||||
}
|
}
|
||||||
DB::commit();
|
DB::commit();
|
||||||
$this->sendNotify($ticket, $ticketMessage);
|
$this->sendNotify($ticket, $ticketMessage);
|
||||||
|
@ -29,19 +29,19 @@ class UserController extends Controller
|
|||||||
{
|
{
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, __('user.user.changePassword.user_not_exist'));
|
abort(500, __('The user does not exist'));
|
||||||
}
|
}
|
||||||
if (!Helper::multiPasswordVerify(
|
if (!Helper::multiPasswordVerify(
|
||||||
$user->password_algo,
|
$user->password_algo,
|
||||||
$request->input('old_password'),
|
$request->input('old_password'),
|
||||||
$user->password)
|
$user->password)
|
||||||
) {
|
) {
|
||||||
abort(500, __('user.user.changePassword.old_password_wrong'));
|
abort(500, __('The old password is wrong'));
|
||||||
}
|
}
|
||||||
$user->password = password_hash($request->input('new_password'), PASSWORD_DEFAULT);
|
$user->password = password_hash($request->input('new_password'), PASSWORD_DEFAULT);
|
||||||
$user->password_algo = NULL;
|
$user->password_algo = NULL;
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, __('user.user.changePassword.save_failed'));
|
abort(500, __('Save failed'));
|
||||||
}
|
}
|
||||||
$request->session()->flush();
|
$request->session()->flush();
|
||||||
return response([
|
return response([
|
||||||
@ -70,7 +70,7 @@ class UserController extends Controller
|
|||||||
])
|
])
|
||||||
->first();
|
->first();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, __('user.user.info.user_not_exist'));
|
abort(500, __('The user does not exist'));
|
||||||
}
|
}
|
||||||
$user['avatar_url'] = 'https://cdn.v2ex.com/gravatar/' . md5($user->email) . '?s=64&d=identicon';
|
$user['avatar_url'] = 'https://cdn.v2ex.com/gravatar/' . md5($user->email) . '?s=64&d=identicon';
|
||||||
return response([
|
return response([
|
||||||
@ -110,15 +110,20 @@ class UserController extends Controller
|
|||||||
])
|
])
|
||||||
->first();
|
->first();
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, __('user.user.getSubscribe.user_not_exist'));
|
abort(500, __('The user does not exist'));
|
||||||
}
|
}
|
||||||
if ($user->plan_id) {
|
if ($user->plan_id) {
|
||||||
$user['plan'] = Plan::find($user->plan_id);
|
$user['plan'] = Plan::find($user->plan_id);
|
||||||
if (!$user['plan']) {
|
if (!$user['plan']) {
|
||||||
abort(500, __('user.user.getSubscribe.plan_not_exist'));
|
abort(500, __('Subscription plan does not exist'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$user['subscribe_url'] = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
$subscribeUrl = config('v2board.app_url', env('APP_URL'));
|
||||||
|
$subscribeUrls = explode(',', config('v2board.subscribe_url'));
|
||||||
|
if ($subscribeUrls) {
|
||||||
|
$subscribeUrl = $subscribeUrls[rand(0, count($subscribeUrls) - 1)];
|
||||||
|
}
|
||||||
|
$user['subscribe_url'] = "{$subscribeUrl}/api/v1/client/subscribe?token={$user['token']}";
|
||||||
$user['reset_day'] = $this->getResetDay($user);
|
$user['reset_day'] = $this->getResetDay($user);
|
||||||
return response([
|
return response([
|
||||||
'data' => $user
|
'data' => $user
|
||||||
@ -129,12 +134,12 @@ class UserController extends Controller
|
|||||||
{
|
{
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, __('user.user.resetSecurity.user_not_exist'));
|
abort(500, __('The user does not exist'));
|
||||||
}
|
}
|
||||||
$user->uuid = Helper::guid(true);
|
$user->uuid = Helper::guid(true);
|
||||||
$user->token = Helper::guid();
|
$user->token = Helper::guid();
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, __('user.user.resetSecurity.reset_failed'));
|
abort(500, __('Reset failed'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user->token
|
'data' => config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user->token
|
||||||
@ -150,12 +155,12 @@ class UserController extends Controller
|
|||||||
|
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, __('user.user.update.user_not_exist'));
|
abort(500, __('The user does not exist'));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$user->update($updateData);
|
$user->update($updateData);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
abort(500, __('user.user.update.save_failed'));
|
abort(500, __('Save failed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response([
|
return response([
|
||||||
@ -167,15 +172,15 @@ class UserController extends Controller
|
|||||||
{
|
{
|
||||||
$user = User::find($request->session()->get('id'));
|
$user = User::find($request->session()->get('id'));
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
abort(500, __('user.user.transfer.user_not_exist'));
|
abort(500, __('The user does not exist'));
|
||||||
}
|
}
|
||||||
if ($request->input('transfer_amount') > $user->commission_balance) {
|
if ($request->input('transfer_amount') > $user->commission_balance) {
|
||||||
abort(500, __('user.user.transfer.insufficient_commission_balance'));
|
abort(500, __('Insufficient commission balance'));
|
||||||
}
|
}
|
||||||
$user->commission_balance = $user->commission_balance - $request->input('transfer_amount');
|
$user->commission_balance = $user->commission_balance - $request->input('transfer_amount');
|
||||||
$user->balance = $user->balance + $request->input('transfer_amount');
|
$user->balance = $user->balance + $request->input('transfer_amount');
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, __('user.user.transfer.transfer_failed'));
|
abort(500, __('Transfer failed'));
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => true
|
'data' => true
|
||||||
|
@ -17,20 +17,14 @@ class User
|
|||||||
{
|
{
|
||||||
if ($request->input('auth_data')) {
|
if ($request->input('auth_data')) {
|
||||||
$authData = explode(':', base64_decode($request->input('auth_data')));
|
$authData = explode(':', base64_decode($request->input('auth_data')));
|
||||||
|
if (!isset($authData[1]) || !isset($authData[0])) abort(403, '鉴权失败,请重新登入');
|
||||||
$user = \App\Models\User::where('password', $authData[1])
|
$user = \App\Models\User::where('password', $authData[1])
|
||||||
->where('email', $authData[0])
|
->where('email', $authData[0])
|
||||||
->first();
|
->first();
|
||||||
if ($user) {
|
if (!$user) abort(403, '鉴权失败,请重新登入');
|
||||||
$request->session()->put('email', $user->email);
|
$request->session()->put('email', $user->email);
|
||||||
$request->session()->put('id', $user->id);
|
$request->session()->put('id', $user->id);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// if ($request->input('lang')) {
|
|
||||||
// $request->session()->put('lang', $request->input('lang'));
|
|
||||||
// }
|
|
||||||
// if ($request->session()->get('lang')) {
|
|
||||||
// App::setLocale($request->session()->get('lang'));
|
|
||||||
// }
|
|
||||||
if (!$request->session()->get('id')) {
|
if (!$request->session()->get('id')) {
|
||||||
abort(403, '未登录或登陆已过期');
|
abort(403, '未登录或登陆已过期');
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class ConfigSave extends FormRequest
|
|||||||
'app_name' => '',
|
'app_name' => '',
|
||||||
'app_description' => '',
|
'app_description' => '',
|
||||||
'app_url' => 'nullable|url',
|
'app_url' => 'nullable|url',
|
||||||
'subscribe_url' => 'nullable|url',
|
'subscribe_url' => 'nullable',
|
||||||
'try_out_enable' => 'in:0,1',
|
'try_out_enable' => 'in:0,1',
|
||||||
'try_out_plan_id' => 'integer',
|
'try_out_plan_id' => 'integer',
|
||||||
'try_out_hour' => 'numeric',
|
'try_out_hour' => 'numeric',
|
||||||
@ -45,8 +45,10 @@ class ConfigSave extends FormRequest
|
|||||||
// subscribe
|
// subscribe
|
||||||
'plan_change_enable' => 'in:0,1',
|
'plan_change_enable' => 'in:0,1',
|
||||||
'reset_traffic_method' => 'in:0,1',
|
'reset_traffic_method' => 'in:0,1',
|
||||||
'renew_reset_traffic_enable' => 'in:0,1',
|
|
||||||
'surplus_enable' => 'in:0,1',
|
'surplus_enable' => 'in:0,1',
|
||||||
|
'new_order_event_id' => 'in:0,1',
|
||||||
|
'renew_order_event_id' => 'in:0,1',
|
||||||
|
'change_order_event_id' => 'in:0,1',
|
||||||
// server
|
// server
|
||||||
'server_token' => 'nullable|min:16',
|
'server_token' => 'nullable|min:16',
|
||||||
'server_license' => 'nullable',
|
'server_license' => 'nullable',
|
||||||
@ -83,6 +85,7 @@ class ConfigSave extends FormRequest
|
|||||||
'epay_pid' => '',
|
'epay_pid' => '',
|
||||||
'epay_key' => '',
|
'epay_key' => '',
|
||||||
// frontend
|
// frontend
|
||||||
|
'frontend_theme' => '',
|
||||||
'frontend_theme_sidebar' => 'in:dark,light',
|
'frontend_theme_sidebar' => 'in:dark,light',
|
||||||
'frontend_theme_header' => 'in:dark,light',
|
'frontend_theme_header' => 'in:dark,light',
|
||||||
'frontend_theme_color' => 'in:default,darkblue,black',
|
'frontend_theme_color' => 'in:default,darkblue,black',
|
||||||
|
@ -25,7 +25,7 @@ class ServerV2raySave extends FormRequest
|
|||||||
'tags' => 'nullable|array',
|
'tags' => 'nullable|array',
|
||||||
'rate' => 'required|numeric',
|
'rate' => 'required|numeric',
|
||||||
'alter_id' => 'required|integer',
|
'alter_id' => 'required|integer',
|
||||||
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic',
|
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic,grpc',
|
||||||
'networkSettings' => '',
|
'networkSettings' => '',
|
||||||
'ruleSettings' => '',
|
'ruleSettings' => '',
|
||||||
'tlsSettings' => '',
|
'tlsSettings' => '',
|
||||||
|
@ -14,7 +14,7 @@ class UserFetch extends FormRequest
|
|||||||
public function rules()
|
public function rules()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'filter.*.key' => 'required|in:id,email,transfer_enable,d,expired_at,uuid,token,invite_by_email,invite_user_id,plan_id,banned',
|
'filter.*.key' => 'required|in:id,email,transfer_enable,d,expired_at,uuid,token,invite_by_email,invite_user_id,plan_id,banned,remarks',
|
||||||
'filter.*.condition' => 'required|in:>,<,=,>=,<=,模糊,!=',
|
'filter.*.condition' => 'required|in:>,<,=,>=,<=,模糊,!=',
|
||||||
'filter.*.value' => 'required'
|
'filter.*.value' => 'required'
|
||||||
];
|
];
|
||||||
|
@ -27,6 +27,7 @@ class UserUpdate extends FormRequest
|
|||||||
'u' => 'integer',
|
'u' => 'integer',
|
||||||
'd' => 'integer',
|
'd' => 'integer',
|
||||||
'balance' => 'integer',
|
'balance' => 'integer',
|
||||||
|
'commission_type' => 'integer',
|
||||||
'commission_balance' => 'integer',
|
'commission_balance' => 'integer',
|
||||||
'remarks' => 'nullable'
|
'remarks' => 'nullable'
|
||||||
];
|
];
|
||||||
|
@ -23,11 +23,11 @@ class AuthForget extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email.required' => '邮箱不能为空',
|
'email.required' => __('Email can not be empty'),
|
||||||
'email.email' => '邮箱格式不正确',
|
'email.email' => __('Email format is incorrect'),
|
||||||
'password.required' => '密码不能为空',
|
'password.required' => __('Password can not be empty'),
|
||||||
'password.min' => '密码必须大于8位数',
|
'password.min' => __('Password must be greater than 8 digits'),
|
||||||
'email_code.required' => '邮箱验证码不能为空'
|
'email_code.required' => __('Email verification code cannot be empty')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,10 @@ class AuthLogin extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email.required' => '邮箱不能为空',
|
'email.required' => __('Email can not be empty'),
|
||||||
'email.email' => '邮箱格式不正确',
|
'email.email' => __('Email format is incorrect'),
|
||||||
'password.required' => '密码不能为空',
|
'password.required' => __('Password can not be empty'),
|
||||||
'password.min' => '密码必须大于8位数'
|
'password.min' => __('Password must be greater than 8 digits')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,10 @@ class AuthRegister extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email.required' => '邮箱不能为空',
|
'email.required' => __('Email can not be empty'),
|
||||||
'email.email' => '邮箱格式不正确',
|
'email.email' => __('Email format is incorrect'),
|
||||||
'password.required' => '密码不能为空',
|
'password.required' => __('Password can not be empty'),
|
||||||
'password.min' => '密码必须大于8位数'
|
'password.min' => __('Password must be greater than 8 digits')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ class CommSendEmailVerify extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'email.required' => '邮箱不能为空',
|
'email.required' => __('Email can not be empty'),
|
||||||
'email.email' => '邮箱格式不正确'
|
'email.email' => __('Email format is incorrect')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ class OrderSave extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'plan_id.required' => '套餐ID不能为空',
|
'plan_id.required' => __('Plan ID cannot be empty'),
|
||||||
'cycle.required' => '套餐周期不能为空',
|
'cycle.required' => __('Plan cycle cannot be empty'),
|
||||||
'cycle.in' => '套餐周期有误'
|
'cycle.in' => __('Wrong plan cycle')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@ class TicketSave extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'subject.required' => '工单主题不能为空',
|
'subject.required' => __('Ticket subject cannot be empty'),
|
||||||
'level.required' => '工单级别不能为空',
|
'level.required' => __('Ticket level cannot be empty'),
|
||||||
'level.in' => '工单级别格式不正确',
|
'level.in' => __('Incorrect ticket level format'),
|
||||||
'message.required' => '消息不能为空'
|
'message.required' => __('Message cannot be empty')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,8 @@ class TicketWithdraw extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'withdraw_method.required' => '提现方式不能为空',
|
'withdraw_method.required' => __('The withdrawal method cannot be empty'),
|
||||||
'withdraw_method.in' => '提现方式不支持',
|
'withdraw_account.required' => __('The withdrawal account cannot be empty')
|
||||||
'withdraw_account.required' => '提现账号不能为空'
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ class UserChangePassword extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'old_password.required' => '旧密码不能为空',
|
'old_password.required' => __('Old password cannot be empty'),
|
||||||
'new_password.required' => '新密码不能为空',
|
'new_password.required' => __('New password cannot be empty'),
|
||||||
'new_password.min' => '密码必须大于8位数'
|
'new_password.min' => __('Password must be greater than 8 digits')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ class UserTransfer extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'transfer_amount.required' => '划转金额不能为空',
|
'transfer_amount.required' => __('The transfer amount cannot be empty'),
|
||||||
'transfer_amount.integer' => __('user.user.transfer.params_wrong'),
|
'transfer_amount.integer' => __('The transfer amount parameter is wrong'),
|
||||||
'transfer_amount.min' => __('user.user.transfer.params_wrong')
|
'transfer_amount.min' => __('The transfer amount parameter is wrong')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@ class UserUpdate extends FormRequest
|
|||||||
public function messages()
|
public function messages()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'show.in' => '过期提醒格式不正确',
|
'show.in' => __('Incorrect format of expiration reminder'),
|
||||||
'renew.in' => '流量提醒格式不正确'
|
'renew.in' => __('Incorrect traffic alert format')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ class AdminRoute
|
|||||||
$router->get ('/config/fetch', 'Admin\\ConfigController@fetch');
|
$router->get ('/config/fetch', 'Admin\\ConfigController@fetch');
|
||||||
$router->post('/config/save', 'Admin\\ConfigController@save');
|
$router->post('/config/save', 'Admin\\ConfigController@save');
|
||||||
$router->get ('/config/getEmailTemplate', 'Admin\\ConfigController@getEmailTemplate');
|
$router->get ('/config/getEmailTemplate', 'Admin\\ConfigController@getEmailTemplate');
|
||||||
|
$router->get ('/config/getThemeTemplate', 'Admin\\ConfigController@getThemeTemplate');
|
||||||
$router->post('/config/setTelegramWebhook', 'Admin\\ConfigController@setTelegramWebhook');
|
$router->post('/config/setTelegramWebhook', 'Admin\\ConfigController@setTelegramWebhook');
|
||||||
// Plan
|
// Plan
|
||||||
$router->get ('/plan/fetch', 'Admin\\PlanController@fetch');
|
$router->get ('/plan/fetch', 'Admin\\PlanController@fetch');
|
||||||
|
84
app/Payments/WechatPayNative.php
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Payments;
|
||||||
|
|
||||||
|
use Omnipay\Omnipay;
|
||||||
|
use Omnipay\WechatPay\Helper;
|
||||||
|
|
||||||
|
class WechatPayNative {
|
||||||
|
public function __construct($config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
$this->customResult = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function form()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'app_id' => [
|
||||||
|
'label' => 'APPID',
|
||||||
|
'description' => '绑定微信支付商户的APPID',
|
||||||
|
'type' => 'input',
|
||||||
|
],
|
||||||
|
'mch_id' => [
|
||||||
|
'label' => '商户号',
|
||||||
|
'description' => '微信支付商户号',
|
||||||
|
'type' => 'input',
|
||||||
|
],
|
||||||
|
'api_key' => [
|
||||||
|
'label' => 'APIKEY(v1)',
|
||||||
|
'description' => '',
|
||||||
|
'type' => 'input',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pay($order)
|
||||||
|
{
|
||||||
|
$gateway = Omnipay::create('WechatPay_Native');
|
||||||
|
$gateway->setAppId($this->config['app_id']);
|
||||||
|
$gateway->setMchId($this->config['mch_id']);
|
||||||
|
$gateway->setApiKey($this->config['api_key']);
|
||||||
|
$gateway->setNotifyUrl($order['notify_url']);
|
||||||
|
|
||||||
|
$params = [
|
||||||
|
'body' => $order['trade_no'],
|
||||||
|
'out_trade_no' => $order['trade_no'],
|
||||||
|
'total_fee' => $order['total_amount'],
|
||||||
|
'spbill_create_ip' => '0.0.0.0',
|
||||||
|
'fee_type' => 'CNY'
|
||||||
|
];
|
||||||
|
|
||||||
|
$request = $gateway->purchase($params);
|
||||||
|
$response = $request->send();
|
||||||
|
$response = $response->getData();
|
||||||
|
if ($response['return_code'] !== 'SUCCESS') {
|
||||||
|
abort(500, $response['return_msg']);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'type' => 0,
|
||||||
|
'data' => $response['code_url']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notify($params)
|
||||||
|
{
|
||||||
|
$data = Helper::xml2array(file_get_contents('php://input'));
|
||||||
|
$gateway = Omnipay::create('WechatPay');
|
||||||
|
$gateway->setAppId($this->config['app_id']);
|
||||||
|
$gateway->setMchId($this->config['mch_id']);
|
||||||
|
$gateway->setApiKey($this->config['api_key']);
|
||||||
|
$response = $gateway->completePurchase([
|
||||||
|
'request_params' => file_get_contents('php://input')
|
||||||
|
])->send();
|
||||||
|
|
||||||
|
if (!$response->isPaid()) {
|
||||||
|
die('FAIL');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'trade_no' => $data['out_trade_no'],
|
||||||
|
'callback_no' => $data['transaction_id']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,6 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
//
|
$this->app['view']->addNamespace('theme', public_path() . '/theme');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ class OrderService
|
|||||||
'three_year_price' => 36
|
'three_year_price' => 36
|
||||||
];
|
];
|
||||||
public $order;
|
public $order;
|
||||||
|
public $user;
|
||||||
|
|
||||||
public function __construct(Order $order)
|
public function __construct(Order $order)
|
||||||
{
|
{
|
||||||
@ -27,11 +28,11 @@ class OrderService
|
|||||||
public function open()
|
public function open()
|
||||||
{
|
{
|
||||||
$order = $this->order;
|
$order = $this->order;
|
||||||
$user = User::find($order->user_id);
|
$this->user = User::find($order->user_id);
|
||||||
$plan = Plan::find($order->plan_id);
|
$plan = Plan::find($order->plan_id);
|
||||||
|
|
||||||
if ($order->refund_amount) {
|
if ($order->refund_amount) {
|
||||||
$user->balance = $user->balance + $order->refund_amount;
|
$this->user->balance = $this->user->balance + $order->refund_amount;
|
||||||
}
|
}
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
if ($order->surplus_order_ids) {
|
if ($order->surplus_order_ids) {
|
||||||
@ -46,18 +47,28 @@ class OrderService
|
|||||||
}
|
}
|
||||||
switch ((string)$order->cycle) {
|
switch ((string)$order->cycle) {
|
||||||
case 'onetime_price':
|
case 'onetime_price':
|
||||||
$this->buyByOneTime($user, $plan);
|
$this->buyByOneTime($plan);
|
||||||
break;
|
break;
|
||||||
case 'reset_price':
|
case 'reset_price':
|
||||||
$this->buyByResetTraffic($user);
|
$this->buyByResetTraffic();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$this->buyByCycle($order, $user, $plan);
|
$this->buyByCycle($order, $plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int)config('v2board.renew_reset_traffic_enable', 0)) $this->buyByResetTraffic($user);
|
switch ((int)$order->type) {
|
||||||
|
case 1:
|
||||||
|
$this->openEvent(config('v2board.new_order_event_id', 0));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$this->openEvent(config('v2board.renew_order_event_id', 0));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$this->openEvent(config('v2board.change_order_event_id', 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$user->save()) {
|
if (!$this->user->save()) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
abort(500, '开通失败');
|
abort(500, '开通失败');
|
||||||
}
|
}
|
||||||
@ -121,13 +132,26 @@ class OrderService
|
|||||||
$order->total_amount = $order->total_amount - $order->discount_amount;
|
$order->total_amount = $order->total_amount - $order->discount_amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setInvite(User $user)
|
public function setInvite(User $user):void
|
||||||
{
|
{
|
||||||
$order = $this->order;
|
$order = $this->order;
|
||||||
if ($user->invite_user_id && $order->total_amount > 0) {
|
if ($user->invite_user_id && $order->total_amount > 0) {
|
||||||
$order->invite_user_id = $user->invite_user_id;
|
$order->invite_user_id = $user->invite_user_id;
|
||||||
$commissionFirstTime = (int)config('v2board.commission_first_time_enable', 1);
|
$isCommission = false;
|
||||||
if (!$commissionFirstTime || ($commissionFirstTime && !$this->haveValidOrder($user))) {
|
switch ((int)$user->commission_type) {
|
||||||
|
case 0:
|
||||||
|
$commissionFirstTime = (int)config('v2board.commission_first_time_enable', 1);
|
||||||
|
$isCommission = (!$commissionFirstTime || ($commissionFirstTime && !$this->haveValidOrder($user)));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$isCommission = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$isCommission = !$this->haveValidOrder($user);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isCommission) {
|
||||||
$inviter = User::find($user->invite_user_id);
|
$inviter = User::find($user->invite_user_id);
|
||||||
if ($inviter && $inviter->commission_rate) {
|
if ($inviter && $inviter->commission_rate) {
|
||||||
$order->commission_balance = $order->total_amount * ($inviter->commission_rate / 100);
|
$order->commission_balance = $order->total_amount * ($inviter->commission_rate / 100);
|
||||||
@ -191,7 +215,7 @@ class OrderService
|
|||||||
if ($item->cycle === 'onetime_price') continue;
|
if ($item->cycle === 'onetime_price') continue;
|
||||||
if ($this->orderIsUsed($item)) continue;
|
if ($this->orderIsUsed($item)) continue;
|
||||||
$orderSurplusMonth = $orderSurplusMonth + self::STR_TO_TIME[$item->cycle];
|
$orderSurplusMonth = $orderSurplusMonth + self::STR_TO_TIME[$item->cycle];
|
||||||
$orderSurplusAmount = $orderSurplusAmount + ($item['total_amount'] + $item['balance_amount']);
|
$orderSurplusAmount = $orderSurplusAmount + ($item['total_amount'] + $item['balance_amount'] + $item['surplus_amount'] - $item['refund_amount']);
|
||||||
}
|
}
|
||||||
if (!$orderSurplusMonth || !$orderSurplusAmount) return;
|
if (!$orderSurplusMonth || !$orderSurplusAmount) return;
|
||||||
$monthUnitPrice = $orderSurplusAmount / $orderSurplusMonth;
|
$monthUnitPrice = $orderSurplusAmount / $orderSurplusMonth;
|
||||||
@ -220,35 +244,35 @@ class OrderService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function buyByResetTraffic(User $user)
|
private function buyByResetTraffic()
|
||||||
{
|
{
|
||||||
$user->u = 0;
|
$this->user->u = 0;
|
||||||
$user->d = 0;
|
$this->user->d = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buyByCycle(Order $order, User $user, Plan $plan)
|
private function buyByCycle(Order $order, Plan $plan)
|
||||||
{
|
{
|
||||||
// change plan process
|
// change plan process
|
||||||
if ((int)$order->type === 3) {
|
if ((int)$order->type === 3) {
|
||||||
$user->expired_at = time();
|
$this->user->expired_at = time();
|
||||||
}
|
}
|
||||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
$this->user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||||
// 从一次性转换到循环
|
// 从一次性转换到循环
|
||||||
if ($user->expired_at === NULL) $this->buyByResetTraffic($user);
|
if ($this->user->expired_at === NULL) $this->buyByResetTraffic();
|
||||||
// 新购
|
// 新购
|
||||||
if ($order->type === 1) $this->buyByResetTraffic($user);
|
if ($order->type === 1) $this->buyByResetTraffic();
|
||||||
$user->plan_id = $plan->id;
|
$this->user->plan_id = $plan->id;
|
||||||
$user->group_id = $plan->group_id;
|
$this->user->group_id = $plan->group_id;
|
||||||
$user->expired_at = $this->getTime($order->cycle, $user->expired_at);
|
$this->user->expired_at = $this->getTime($order->cycle, $this->user->expired_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buyByOneTime(User $user, Plan $plan)
|
private function buyByOneTime(Plan $plan)
|
||||||
{
|
{
|
||||||
$this->buyByResetTraffic($user);
|
$this->buyByResetTraffic();
|
||||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
$this->user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||||
$user->plan_id = $plan->id;
|
$this->user->plan_id = $plan->id;
|
||||||
$user->group_id = $plan->group_id;
|
$this->user->group_id = $plan->group_id;
|
||||||
$user->expired_at = NULL;
|
$this->user->expired_at = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTime($str, $timestamp)
|
private function getTime($str, $timestamp)
|
||||||
@ -271,4 +295,15 @@ class OrderService
|
|||||||
return strtotime('+36 month', $timestamp);
|
return strtotime('+36 month', $timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function openEvent($eventId)
|
||||||
|
{
|
||||||
|
switch ((int) $eventId) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$this->buyByResetTraffic();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,12 @@ use App\Models\Payment;
|
|||||||
|
|
||||||
class PaymentService
|
class PaymentService
|
||||||
{
|
{
|
||||||
|
public $method;
|
||||||
|
public $customResult;
|
||||||
|
protected $class;
|
||||||
|
protected $config;
|
||||||
|
protected $payment;
|
||||||
|
|
||||||
public function __construct($method, $id = NULL, $uuid = NULL)
|
public function __construct($method, $id = NULL, $uuid = NULL)
|
||||||
{
|
{
|
||||||
$this->method = $method;
|
$this->method = $method;
|
||||||
@ -22,6 +28,7 @@ class PaymentService
|
|||||||
$this->config['uuid'] = $payment['uuid'];
|
$this->config['uuid'] = $payment['uuid'];
|
||||||
};
|
};
|
||||||
$this->payment = new $this->class($this->config);
|
$this->payment = new $this->class($this->config);
|
||||||
|
if (isset($this->payment->customResult)) $this->customResult = $this->payment->customResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notify($params)
|
public function notify($params)
|
||||||
|
@ -8,8 +8,6 @@ use App\Models\User;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\ServerTrojan;
|
use App\Models\ServerTrojan;
|
||||||
use App\Utils\CacheKey;
|
use App\Utils\CacheKey;
|
||||||
use App\Utils\Helper;
|
|
||||||
use App\Utils\URLSchemes;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
class ServerService
|
class ServerService
|
||||||
@ -29,7 +27,6 @@ class ServerService
|
|||||||
$v2ray[$i]['type'] = 'v2ray';
|
$v2ray[$i]['type'] = 'v2ray';
|
||||||
$groupId = json_decode($v2ray[$i]['group_id']);
|
$groupId = json_decode($v2ray[$i]['group_id']);
|
||||||
if (in_array($user->group_id, $groupId)) {
|
if (in_array($user->group_id, $groupId)) {
|
||||||
$v2ray[$i]['link'] = URLSchemes::buildVmess($v2ray[$i], $user);
|
|
||||||
if ($v2ray[$i]['parent_id']) {
|
if ($v2ray[$i]['parent_id']) {
|
||||||
$v2ray[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $v2ray[$i]['parent_id']));
|
$v2ray[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $v2ray[$i]['parent_id']));
|
||||||
} else {
|
} else {
|
||||||
@ -54,7 +51,6 @@ class ServerService
|
|||||||
for ($i = 0; $i < count($trojan); $i++) {
|
for ($i = 0; $i < count($trojan); $i++) {
|
||||||
$trojan[$i]['type'] = 'trojan';
|
$trojan[$i]['type'] = 'trojan';
|
||||||
$groupId = json_decode($trojan[$i]['group_id']);
|
$groupId = json_decode($trojan[$i]['group_id']);
|
||||||
$trojan[$i]['link'] = URLSchemes::buildTrojan($trojan[$i], $user);
|
|
||||||
if (in_array($user->group_id, $groupId)) {
|
if (in_array($user->group_id, $groupId)) {
|
||||||
if ($trojan[$i]['parent_id']) {
|
if ($trojan[$i]['parent_id']) {
|
||||||
$trojan[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $trojan[$i]['parent_id']));
|
$trojan[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $trojan[$i]['parent_id']));
|
||||||
@ -78,7 +74,6 @@ class ServerService
|
|||||||
for ($i = 0; $i < count($shadowsocks); $i++) {
|
for ($i = 0; $i < count($shadowsocks); $i++) {
|
||||||
$shadowsocks[$i]['type'] = 'shadowsocks';
|
$shadowsocks[$i]['type'] = 'shadowsocks';
|
||||||
$groupId = json_decode($shadowsocks[$i]['group_id']);
|
$groupId = json_decode($shadowsocks[$i]['group_id']);
|
||||||
$shadowsocks[$i]['link'] = URLSchemes::buildShadowsocks($shadowsocks[$i], $user);
|
|
||||||
if (in_array($user->group_id, $groupId)) {
|
if (in_array($user->group_id, $groupId)) {
|
||||||
if ($shadowsocks[$i]['parent_id']) {
|
if ($shadowsocks[$i]['parent_id']) {
|
||||||
$shadowsocks[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $shadowsocks[$i]['parent_id']));
|
$shadowsocks[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $shadowsocks[$i]['parent_id']));
|
||||||
@ -196,6 +191,9 @@ class ServerService
|
|||||||
case 'quic':
|
case 'quic':
|
||||||
$json->inbound->streamSettings->quicSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->quicSettings = json_decode($server->networkSettings);
|
||||||
break;
|
break;
|
||||||
|
case 'grpc':
|
||||||
|
$json->inbound->streamSettings->grpcSettings = json_decode($server->networkSettings);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,4 +356,17 @@ class ServerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllServers()
|
||||||
|
{
|
||||||
|
$servers = array_merge(
|
||||||
|
$this->getShadowsocksServers(),
|
||||||
|
$this->getV2rayServers(),
|
||||||
|
$this->getTrojanServers()
|
||||||
|
);
|
||||||
|
$this->mergeData($servers);
|
||||||
|
$tmp = array_column($servers, 'sort');
|
||||||
|
array_multisort($tmp, SORT_ASC, $servers);
|
||||||
|
return $servers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\InviteCode;
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\Ticket;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class UserService
|
class UserService
|
||||||
{
|
{
|
||||||
@ -52,7 +55,7 @@ class UserService
|
|||||||
|
|
||||||
public function addBalance(int $userId, int $balance):bool
|
public function addBalance(int $userId, int $balance):bool
|
||||||
{
|
{
|
||||||
$user = User::find($userId);
|
$user = User::lockForUpdate()->find($userId);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace App\Utils;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\User;
|
|
||||||
|
|
||||||
class URLSchemes
|
|
||||||
{
|
|
||||||
public static function buildShadowsocks($server, User $user)
|
|
||||||
{
|
|
||||||
$name = rawurlencode($server['name']);
|
|
||||||
$str = str_replace(
|
|
||||||
['+', '/', '='],
|
|
||||||
['-', '_', ''],
|
|
||||||
base64_encode("{$server['cipher']}:{$user['uuid']}")
|
|
||||||
);
|
|
||||||
return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function buildShadowsocksSIP008($server, User $user)
|
|
||||||
{
|
|
||||||
$config = [
|
|
||||||
"id" => $server['id'],
|
|
||||||
"remarks" => $server['name'],
|
|
||||||
"server" => $server['host'],
|
|
||||||
"server_port" => $server['port'],
|
|
||||||
"password" => $user['uuid'],
|
|
||||||
"method" => $server['cipher']
|
|
||||||
];
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function buildVmess($server, User $user)
|
|
||||||
{
|
|
||||||
$config = [
|
|
||||||
"v" => "2",
|
|
||||||
"ps" => $server['name'],
|
|
||||||
"add" => $server['host'],
|
|
||||||
"port" => (string)$server['port'],
|
|
||||||
"id" => $user['uuid'],
|
|
||||||
"aid" => (string)$server['alter_id'],
|
|
||||||
"net" => $server['network'],
|
|
||||||
"type" => "none",
|
|
||||||
"host" => "",
|
|
||||||
"path" => "",
|
|
||||||
"tls" => $server['tls'] ? "tls" : ""
|
|
||||||
];
|
|
||||||
if ((string)$server['network'] === 'ws') {
|
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
|
||||||
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
|
||||||
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
|
||||||
}
|
|
||||||
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function buildTrojan($server, User $user)
|
|
||||||
{
|
|
||||||
$name = rawurlencode($server['name']);
|
|
||||||
$query = http_build_query([
|
|
||||||
'allowInsecure' => $server['allow_insecure'],
|
|
||||||
'peer' => $server['server_name'],
|
|
||||||
'sni' => $server['server_name']
|
|
||||||
]);
|
|
||||||
$uri = "trojan://{$user['uuid']}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
|
||||||
$uri .= "\r\n";
|
|
||||||
return $uri;
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,6 +15,7 @@
|
|||||||
"laravel/framework": "^6.0",
|
"laravel/framework": "^6.0",
|
||||||
"laravel/tinker": "^1.0",
|
"laravel/tinker": "^1.0",
|
||||||
"lokielse/omnipay-alipay": "3.0.6",
|
"lokielse/omnipay-alipay": "3.0.6",
|
||||||
|
"lokielse/omnipay-wechatpay": "^3.0",
|
||||||
"php-curl-class/php-curl-class": "^8.6",
|
"php-curl-class/php-curl-class": "^8.6",
|
||||||
"stripe/stripe-php": "^7.36.1",
|
"stripe/stripe-php": "^7.36.1",
|
||||||
"symfony/yaml": "^4.3"
|
"symfony/yaml": "^4.3"
|
||||||
@ -64,11 +65,5 @@
|
|||||||
"post-create-project-cmd": [
|
"post-create-project-cmd": [
|
||||||
"@php artisan key:generate --ansi"
|
"@php artisan key:generate --ansi"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"repositories": {
|
|
||||||
"packagist": {
|
|
||||||
"type": "composer",
|
|
||||||
"url": "https://mirrors.aliyun.com/composer/"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,5 +236,5 @@ return [
|
|||||||
| The only modification by laravel config
|
| The only modification by laravel config
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'version' => '1.5.1.1621339182281'
|
'version' => '1.5.2.1626426358299'
|
||||||
];
|
];
|
||||||
|
@ -321,6 +321,7 @@ CREATE TABLE `v2_user` (
|
|||||||
`password_algo` char(10) DEFAULT NULL,
|
`password_algo` char(10) DEFAULT NULL,
|
||||||
`balance` int(11) NOT NULL DEFAULT '0',
|
`balance` int(11) NOT NULL DEFAULT '0',
|
||||||
`discount` int(11) DEFAULT NULL,
|
`discount` int(11) DEFAULT NULL,
|
||||||
|
`commission_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0: system 1: cycle 2: onetime',
|
||||||
`commission_rate` int(11) DEFAULT NULL,
|
`commission_rate` int(11) DEFAULT NULL,
|
||||||
`commission_balance` int(11) NOT NULL DEFAULT '0',
|
`commission_balance` int(11) NOT NULL DEFAULT '0',
|
||||||
`t` int(11) NOT NULL DEFAULT '0',
|
`t` int(11) NOT NULL DEFAULT '0',
|
||||||
@ -347,4 +348,4 @@ CREATE TABLE `v2_user` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
-- 2021-05-06 16:14:04
|
-- 2021-07-13 13:50:52
|
||||||
|
@ -411,3 +411,17 @@ ALTER TABLE `v2_order`
|
|||||||
|
|
||||||
ALTER TABLE `v2_payment`
|
ALTER TABLE `v2_payment`
|
||||||
ADD `uuid` char(32) NOT NULL AFTER `id`;
|
ADD `uuid` char(32) NOT NULL AFTER `id`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_user`
|
||||||
|
ADD UNIQUE `email_deleted_at` (`email`, `deleted_at`),
|
||||||
|
DROP INDEX `email`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_user`
|
||||||
|
DROP `deleted_at`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_user`
|
||||||
|
ADD UNIQUE `email` (`email`),
|
||||||
|
DROP INDEX `email_deleted_at`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_user`
|
||||||
|
ADD `commission_type` tinyint NOT NULL DEFAULT '0' COMMENT '0: system 1: cycle 2: onetime' AFTER `discount`;
|
||||||
|
21
package.json
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "npm run development",
|
|
||||||
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
|
||||||
"watch": "npm run development -- --watch",
|
|
||||||
"watch-poll": "npm run watch -- --watch-poll",
|
|
||||||
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
|
||||||
"prod": "npm run production",
|
|
||||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"axios": "^0.19",
|
|
||||||
"cross-env": "^5.1",
|
|
||||||
"laravel-mix": "^4.0.7",
|
|
||||||
"lodash": "^4.17.13",
|
|
||||||
"resolve-url-loader": "^2.3.1",
|
|
||||||
"sass": "^1.15.2",
|
|
||||||
"sass-loader": "^7.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
2
public/assets/admin/umi.css
vendored
2
public/assets/admin/umi.js
vendored
1
public/assets/user/components.async.js
vendored
1
public/assets/user/umi.js
vendored
1
public/theme/v2board/assets/components.async.js
vendored
Normal file
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 237 KiB |
Before Width: | Height: | Size: 680 KiB After Width: | Height: | Size: 680 KiB |
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 832 KiB After Width: | Height: | Size: 832 KiB |