mirror of
https://github.com/v2board/v2board.git
synced 2025-06-23 02:29:57 +08:00
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\CommissionLog;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@ -59,27 +60,66 @@ class CheckCommission extends Command
|
|||||||
|
|
||||||
public function autoPayCommission()
|
public function autoPayCommission()
|
||||||
{
|
{
|
||||||
$order = Order::where('commission_status', 1)
|
$orders = Order::where('commission_status', 1)
|
||||||
->where('invite_user_id', '!=', NULL)
|
->where('invite_user_id', '!=', NULL)
|
||||||
->get();
|
->get();
|
||||||
foreach ($order as $item) {
|
foreach ($orders as $order) {
|
||||||
$inviter = User::find($item->invite_user_id);
|
|
||||||
if (!$inviter) continue;
|
|
||||||
if ((int)config('v2board.withdraw_close_enable', 0)) {
|
|
||||||
$inviter->balance = $inviter->balance + $item->commission_balance;
|
|
||||||
} else {
|
|
||||||
$inviter->commission_balance = $inviter->commission_balance + $item->commission_balance;
|
|
||||||
}
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
if ($inviter->save()) {
|
if (!$this->payHandle($order->invite_user_id, $order)) {
|
||||||
$item->commission_status = 2;
|
DB::rollBack();
|
||||||
if (!$item->save()) {
|
continue;
|
||||||
DB::rollBack();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DB::commit();
|
|
||||||
}
|
}
|
||||||
|
$order->commission_status = 2;
|
||||||
|
if (!$order->save()) {
|
||||||
|
DB::rollBack();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DB::commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function payHandle($inviteUserId, Order $order)
|
||||||
|
{
|
||||||
|
if ((int)config('v2board.commission_distribution_enable', 0)) {
|
||||||
|
$level = 3;
|
||||||
|
$commissionShareLevels = [
|
||||||
|
0 => (int)config('v2board.commission_distribution_l1'),
|
||||||
|
1 => (int)config('v2board.commission_distribution_l2'),
|
||||||
|
2 => (int)config('v2board.commission_distribution_l3')
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$level = 3;
|
||||||
|
$commissionShareLevels = [
|
||||||
|
0 => 100
|
||||||
|
];
|
||||||
|
}
|
||||||
|
for ($l = 0; $l < $level; $l++) {
|
||||||
|
$inviter = User::find($inviteUserId);
|
||||||
|
if (!$inviter) continue;
|
||||||
|
if (!isset($commissionShareLevels[$l])) continue;
|
||||||
|
$commissionBalance = $order->commission_balance * ($commissionShareLevels[$l] / 100);
|
||||||
|
if ((int)config('v2board.withdraw_close_enable', 0)) {
|
||||||
|
$inviter->balance = $inviter->balance + $commissionBalance;
|
||||||
|
} else {
|
||||||
|
$inviter->commission_balance = $inviter->commission_balance + $commissionBalance;
|
||||||
|
}
|
||||||
|
if (!$inviter->save()) {
|
||||||
|
DB::rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!CommissionLog::create([
|
||||||
|
'invite_user_id' => $inviteUserId,
|
||||||
|
'user_id' => $order->user_id,
|
||||||
|
'trade_no' => $order->trade_no,
|
||||||
|
'order_amount' => $order->total_amount,
|
||||||
|
'get_amount' => $commissionBalance
|
||||||
|
])) {
|
||||||
|
DB::rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$inviteUserId = $inviter->invite_user_id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Jobs\OrderHandleJob;
|
||||||
use App\Services\OrderService;
|
use App\Services\OrderService;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
@ -45,20 +46,8 @@ class CheckOrder extends Command
|
|||||||
ini_set('memory_limit', -1);
|
ini_set('memory_limit', -1);
|
||||||
$orders = Order::whereIn('status', [0, 1])
|
$orders = Order::whereIn('status', [0, 1])
|
||||||
->get();
|
->get();
|
||||||
foreach ($orders as $item) {
|
foreach ($orders as $order) {
|
||||||
$orderService = new OrderService($item);
|
OrderHandleJob::dispatch($order->trade_no);
|
||||||
switch ($item->status) {
|
|
||||||
// cancel
|
|
||||||
case 0:
|
|
||||||
if (strtotime($item->created_at) <= (time() - 1800)) {
|
|
||||||
$orderService->cancel();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
$orderService->open();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Plan;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
@ -42,24 +43,45 @@ class ResetTraffic extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
DB::beginTransaction();
|
ini_set('memory_limit', -1);
|
||||||
$resetTrafficMethod = config('v2board.reset_traffic_method', 0);
|
foreach (Plan::get() as $plan) {
|
||||||
switch ((int)$resetTrafficMethod) {
|
switch ($plan->reset_traffic_method) {
|
||||||
// 1 a month
|
case null: {
|
||||||
case 0:
|
$resetTrafficMethod = config('v2board.reset_traffic_method', 0);
|
||||||
$this->resetByMonthFirstDay();
|
switch ((int)$resetTrafficMethod) {
|
||||||
break;
|
// month first day
|
||||||
// expire day
|
case 0:
|
||||||
case 1:
|
$this->resetByMonthFirstDay($this->builder);
|
||||||
$this->resetByExpireDay();
|
break;
|
||||||
break;
|
// expire day
|
||||||
|
case 1:
|
||||||
|
$this->resetByExpireDay($this->builder);
|
||||||
|
break;
|
||||||
|
// no action
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0: {
|
||||||
|
$builder = $this->builder->where('plan_id', $plan->id);
|
||||||
|
$this->resetByMonthFirstDay($builder);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
$builder = $this->builder->where('plan_id', $plan->id);
|
||||||
|
$this->resetByExpireDay($builder);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DB::commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resetByMonthFirstDay():void
|
private function resetByMonthFirstDay($builder):void
|
||||||
{
|
{
|
||||||
$builder = $this->builder;
|
|
||||||
if ((string)date('d') === '01') {
|
if ((string)date('d') === '01') {
|
||||||
$builder->update([
|
$builder->update([
|
||||||
'u' => 0,
|
'u' => 0,
|
||||||
@ -68,9 +90,8 @@ class ResetTraffic extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resetByExpireDay():void
|
private function resetByExpireDay($builder):void
|
||||||
{
|
{
|
||||||
$builder = $this->builder;
|
|
||||||
$lastDay = date('d', strtotime('last day of +0 months'));
|
$lastDay = date('d', strtotime('last day of +0 months'));
|
||||||
$users = [];
|
$users = [];
|
||||||
foreach ($builder->get() as $item) {
|
foreach ($builder->get() as $item) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Services\MailService;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\MailLog;
|
use App\Models\MailLog;
|
||||||
@ -41,23 +42,9 @@ class SendRemindMail extends Command
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$users = User::all();
|
$users = User::all();
|
||||||
|
$mailService = new MailService();
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
if ($user->remind_expire) $this->remindExpire($user);
|
if ($user->remind_expire) $mailService->remindExpire($user);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function remindExpire($user)
|
|
||||||
{
|
|
||||||
if ($user->expired_at !== NULL && ($user->expired_at - 86400) < time() && $user->expired_at > time()) {
|
|
||||||
SendEmailJob::dispatch([
|
|
||||||
'email' => $user->email,
|
|
||||||
'subject' => '在' . config('v2board.app_name', 'V2board') . '的服务即将到期',
|
|
||||||
'template_name' => 'remindExpire',
|
|
||||||
'template_value' => [
|
|
||||||
'name' => config('v2board.app_name', 'V2Board'),
|
|
||||||
'url' => config('v2board.app_url')
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Utils\Helper;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Matriphe\Larinfo;
|
||||||
|
|
||||||
class Test extends Command
|
class Test extends Command
|
||||||
{
|
{
|
||||||
|
@ -47,13 +47,12 @@ class V2boardInstall extends Command
|
|||||||
$this->info(" \ \ / / __) | _ \ / _ \ / _` | '__/ _` | ");
|
$this->info(" \ \ / / __) | _ \ / _ \ / _` | '__/ _` | ");
|
||||||
$this->info(" \ V / / __/| |_) | (_) | (_| | | | (_| | ");
|
$this->info(" \ V / / __/| |_) | (_) | (_| | | | (_| | ");
|
||||||
$this->info(" \_/ |_____|____/ \___/ \__,_|_| \__,_| ");
|
$this->info(" \_/ |_____|____/ \___/ \__,_|_| \__,_| ");
|
||||||
if (\File::exists(base_path() . '/.lock')) {
|
if (\File::exists(base_path() . '/.env')) {
|
||||||
abort(500, 'V2board 已安装,如需重新安装请删除目录下.lock文件');
|
abort(500, 'V2board 已安装,如需重新安装请删除目录下.lock文件');
|
||||||
}
|
}
|
||||||
if (!\File::exists(base_path() . '/.env')) {
|
|
||||||
if (!copy(base_path() . '/.env.example', base_path() . '/.env')) {
|
if (!copy(base_path() . '/.env.example', base_path() . '/.env')) {
|
||||||
abort(500, '复制环境文件失败,请检查目录权限');
|
abort(500, '复制环境文件失败,请检查目录权限');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$this->saveToEnv([
|
$this->saveToEnv([
|
||||||
'APP_KEY' => 'base64:' . base64_encode(Encrypter::generateKey('AES-256-CBC')),
|
'APP_KEY' => 'base64:' . base64_encode(Encrypter::generateKey('AES-256-CBC')),
|
||||||
|
@ -42,16 +42,16 @@ class V2boardStatistics extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$this->statOrder();
|
$this->statOrder();
|
||||||
$this->statServer();
|
$this->statServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function statOrder()
|
private function statOrder()
|
||||||
{
|
{
|
||||||
$endAt = strtotime(date('Y-m-d'));
|
$endAt = strtotime(date('Y-m-d'));
|
||||||
$startAt = strtotime('-1 day', $endAt);
|
$startAt = strtotime('-1 day', $endAt);
|
||||||
$builder = Order::where('created_at', '>=', $startAt)
|
$builder = Order::where('paid_at', '>=', $startAt)
|
||||||
->where('created_at', '<', $endAt)
|
->where('paid_at', '<', $endAt)
|
||||||
->whereNotIn('status', [0, 2]);
|
->whereNotIn('status', [0, 2]);
|
||||||
$orderCount = $builder->count();
|
$orderCount = $builder->count();
|
||||||
$orderAmount = $builder->sum('total_amount');
|
$orderAmount = $builder->sum('total_amount');
|
||||||
|
@ -51,11 +51,12 @@ class V2boardUpdate extends Command
|
|||||||
}
|
}
|
||||||
$this->info('正在导入数据库请稍等...');
|
$this->info('正在导入数据库请稍等...');
|
||||||
foreach ($sql as $item) {
|
foreach ($sql as $item) {
|
||||||
|
if (!$item) continue;
|
||||||
try {
|
try {
|
||||||
DB::select(DB::raw($item));
|
DB::select(DB::raw($item));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->info('更新完毕');
|
$this->info('更新完毕,请重新启动队列服务。');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
app/Console/Kernel.php
Executable file → Normal file
4
app/Console/Kernel.php
Executable file → Normal file
@ -31,9 +31,11 @@ class Kernel extends ConsoleKernel
|
|||||||
$schedule->command('check:commission')->everyMinute();
|
$schedule->command('check:commission')->everyMinute();
|
||||||
// reset
|
// reset
|
||||||
$schedule->command('reset:traffic')->daily();
|
$schedule->command('reset:traffic')->daily();
|
||||||
$schedule->command('reset:serverLog')->quarterly();
|
$schedule->command('reset:serverLog')->quarterly()->at('0:15');
|
||||||
// send
|
// send
|
||||||
$schedule->command('send:remindMail')->dailyAt('11:30');
|
$schedule->command('send:remindMail')->dailyAt('11:30');
|
||||||
|
// horizon metrics
|
||||||
|
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Exceptions;
|
namespace App\Exceptions;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
{
|
{
|
||||||
@ -29,10 +29,12 @@ class Handler extends ExceptionHandler
|
|||||||
/**
|
/**
|
||||||
* Report or log an exception.
|
* Report or log an exception.
|
||||||
*
|
*
|
||||||
* @param \Exception $exception
|
* @param \Throwable $exception
|
||||||
* @return void
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \Throwable
|
||||||
*/
|
*/
|
||||||
public function report(Exception $exception)
|
public function report(Throwable $exception)
|
||||||
{
|
{
|
||||||
parent::report($exception);
|
parent::report($exception);
|
||||||
}
|
}
|
||||||
@ -40,16 +42,14 @@ class Handler extends ExceptionHandler
|
|||||||
/**
|
/**
|
||||||
* Render an exception into an HTTP response.
|
* Render an exception into an HTTP response.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param \Exception $exception
|
* @param \Throwable $exception
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
|
*
|
||||||
|
* @throws \Throwable
|
||||||
*/
|
*/
|
||||||
public function render($request, Exception $exception)
|
public function render($request, Throwable $exception)
|
||||||
{
|
{
|
||||||
if($exception instanceof \Illuminate\Http\Exceptions\ThrottleRequestsException) {
|
|
||||||
abort(429, '请求频繁,请稍后再试');
|
|
||||||
}
|
|
||||||
return parent::render($request, $exception);
|
return parent::render($request, $exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,11 @@ class ConfigController extends Controller
|
|||||||
'commission_auto_check_enable' => config('v2board.commission_auto_check_enable', 1),
|
'commission_auto_check_enable' => config('v2board.commission_auto_check_enable', 1),
|
||||||
'commission_withdraw_limit' => config('v2board.commission_withdraw_limit', 100),
|
'commission_withdraw_limit' => config('v2board.commission_withdraw_limit', 100),
|
||||||
'commission_withdraw_method' => config('v2board.commission_withdraw_method', Dict::WITHDRAW_METHOD_WHITELIST_DEFAULT),
|
'commission_withdraw_method' => config('v2board.commission_withdraw_method', Dict::WITHDRAW_METHOD_WHITELIST_DEFAULT),
|
||||||
'withdraw_close_enable' => config('v2board.withdraw_close_enable', 0)
|
'withdraw_close_enable' => config('v2board.withdraw_close_enable', 0),
|
||||||
|
'commission_distribution_enable' => config('v2board.commission_distribution_enable', 0),
|
||||||
|
'commission_distribution_l1' => config('v2board.commission_distribution_l1'),
|
||||||
|
'commission_distribution_l2' => config('v2board.commission_distribution_l2'),
|
||||||
|
'commission_distribution_l3' => config('v2board.commission_distribution_l3')
|
||||||
],
|
],
|
||||||
'site' => [
|
'site' => [
|
||||||
'safe_mode_enable' => (int)config('v2board.safe_mode_enable', 0),
|
'safe_mode_enable' => (int)config('v2board.safe_mode_enable', 0),
|
||||||
@ -136,9 +140,6 @@ class ConfigController extends Controller
|
|||||||
'server_v2ray_domain' => config('v2board.server_v2ray_domain'),
|
'server_v2ray_domain' => config('v2board.server_v2ray_domain'),
|
||||||
'server_v2ray_protocol' => config('v2board.server_v2ray_protocol'),
|
'server_v2ray_protocol' => config('v2board.server_v2ray_protocol'),
|
||||||
],
|
],
|
||||||
'tutorial' => [
|
|
||||||
'apple_id' => config('v2board.apple_id')
|
|
||||||
],
|
|
||||||
'email' => [
|
'email' => [
|
||||||
'email_template' => config('v2board.email_template', 'default'),
|
'email_template' => config('v2board.email_template', 'default'),
|
||||||
'email_host' => config('v2board.email_host'),
|
'email_host' => config('v2board.email_host'),
|
||||||
@ -166,7 +167,7 @@ class ConfigController extends Controller
|
|||||||
|
|
||||||
public function save(ConfigSave $request)
|
public function save(ConfigSave $request)
|
||||||
{
|
{
|
||||||
$data = $request->input();
|
$data = $request->validated();
|
||||||
$array = \Config::get('v2board');
|
$array = \Config::get('v2board');
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
if (!in_array($k, array_keys($request->validated()))) {
|
if (!in_array($k, array_keys($request->validated()))) {
|
||||||
|
@ -24,42 +24,12 @@ class CouponController extends Controller
|
|||||||
$total = $builder->count();
|
$total = $builder->count();
|
||||||
$coupons = $builder->forPage($current, $pageSize)
|
$coupons = $builder->forPage($current, $pageSize)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
foreach ($coupons as $k => $v) {
|
|
||||||
if ($coupons[$k]['limit_plan_ids']) $coupons[$k]['limit_plan_ids'] = json_decode($coupons[$k]['limit_plan_ids']);
|
|
||||||
}
|
|
||||||
return response([
|
return response([
|
||||||
'data' => $coupons,
|
'data' => $coupons,
|
||||||
'total' => $total
|
'total' => $total
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(CouponSave $request)
|
|
||||||
{
|
|
||||||
$params = $request->validated();
|
|
||||||
if (isset($params['limit_plan_ids'])) {
|
|
||||||
$params['limit_plan_ids'] = json_encode($params['limit_plan_ids']);
|
|
||||||
}
|
|
||||||
if (!$request->input('id')) {
|
|
||||||
if (!isset($params['code'])) {
|
|
||||||
$params['code'] = Helper::randomChar(8);
|
|
||||||
}
|
|
||||||
if (!Coupon::create($params)) {
|
|
||||||
abort(500, '创建失败');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
Coupon::find($request->input('id'))->update($params);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
abort(500, '保存失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response([
|
|
||||||
'data' => true
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function generate(CouponGenerate $request)
|
public function generate(CouponGenerate $request)
|
||||||
{
|
{
|
||||||
if ($request->input('generate_count')) {
|
if ($request->input('generate_count')) {
|
||||||
@ -68,9 +38,6 @@ class CouponController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$params = $request->validated();
|
$params = $request->validated();
|
||||||
if (isset($params['limit_plan_ids'])) {
|
|
||||||
$params['limit_plan_ids'] = json_encode($params['limit_plan_ids']);
|
|
||||||
}
|
|
||||||
if (!$request->input('id')) {
|
if (!$request->input('id')) {
|
||||||
if (!isset($params['code'])) {
|
if (!isset($params['code'])) {
|
||||||
$params['code'] = Helper::randomChar(8);
|
$params['code'] = Helper::randomChar(8);
|
||||||
@ -95,10 +62,8 @@ class CouponController extends Controller
|
|||||||
{
|
{
|
||||||
$coupons = [];
|
$coupons = [];
|
||||||
$coupon = $request->validated();
|
$coupon = $request->validated();
|
||||||
if (isset($coupon['limit_plan_ids'])) {
|
|
||||||
$coupon['limit_plan_ids'] = json_encode($coupon['limit_plan_ids']);
|
|
||||||
}
|
|
||||||
$coupon['created_at'] = $coupon['updated_at'] = time();
|
$coupon['created_at'] = $coupon['updated_at'] = time();
|
||||||
|
$coupon['limit_plan_ids'] = json_encode($coupon['limit_plan_ids']);
|
||||||
unset($coupon['generate_count']);
|
unset($coupon['generate_count']);
|
||||||
for ($i = 0;$i < $request->input('generate_count');$i++) {
|
for ($i = 0;$i < $request->input('generate_count');$i++) {
|
||||||
$coupon['code'] = Helper::randomChar(8);
|
$coupon['code'] = Helper::randomChar(8);
|
||||||
@ -118,7 +83,7 @@ class CouponController extends Controller
|
|||||||
$endTime = date('Y-m-d H:i:s', $coupon['ended_at']);
|
$endTime = date('Y-m-d H:i:s', $coupon['ended_at']);
|
||||||
$limitUse = $coupon['limit_use'] ?? '不限制';
|
$limitUse = $coupon['limit_use'] ?? '不限制';
|
||||||
$createTime = date('Y-m-d H:i:s', $coupon['created_at']);
|
$createTime = date('Y-m-d H:i:s', $coupon['created_at']);
|
||||||
$limitPlanIds = $coupon['limit_plan_ids'] ?? '不限制';
|
$limitPlanIds = implode("/", json_decode($coupon['limit_plan_ids'], true)) ?? '不限制';
|
||||||
$data .= "{$coupon['name']},{$type},{$value},{$startTime},{$endTime},{$limitUse},{$limitPlanIds},{$coupon['code']},{$createTime}\r\n";
|
$data .= "{$coupon['name']},{$type},{$value},{$startTime},{$endTime},{$limitUse},{$limitPlanIds},{$coupon['code']},{$createTime}\r\n";
|
||||||
}
|
}
|
||||||
echo $data;
|
echo $data;
|
||||||
|
@ -6,6 +6,7 @@ use App\Http\Requests\Admin\OrderAssign;
|
|||||||
use App\Http\Requests\Admin\OrderUpdate;
|
use App\Http\Requests\Admin\OrderUpdate;
|
||||||
use App\Http\Requests\Admin\OrderFetch;
|
use App\Http\Requests\Admin\OrderFetch;
|
||||||
use App\Services\OrderService;
|
use App\Services\OrderService;
|
||||||
|
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;
|
||||||
@ -63,10 +64,45 @@ class OrderController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function paid(Request $request)
|
||||||
|
{
|
||||||
|
$order = Order::where('trade_no', $request->input('trade_no'))
|
||||||
|
->first();
|
||||||
|
if (!$order) {
|
||||||
|
abort(500, '订单不存在');
|
||||||
|
}
|
||||||
|
if ($order->status !== 0) abort(500, '只能对待支付的订单进行操作');
|
||||||
|
|
||||||
|
$orderService = new OrderService($order);
|
||||||
|
if (!$orderService->paid('manual_operation')) {
|
||||||
|
abort(500, '更新失败');
|
||||||
|
}
|
||||||
|
return response([
|
||||||
|
'data' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel(Request $request)
|
||||||
|
{
|
||||||
|
$order = Order::where('trade_no', $request->input('trade_no'))
|
||||||
|
->first();
|
||||||
|
if (!$order) {
|
||||||
|
abort(500, '订单不存在');
|
||||||
|
}
|
||||||
|
if ($order->status !== 0) abort(500, '只能对待支付的订单进行操作');
|
||||||
|
|
||||||
|
$orderService = new OrderService($order);
|
||||||
|
if (!$orderService->cancel()) {
|
||||||
|
abort(500, '更新失败');
|
||||||
|
}
|
||||||
|
return response([
|
||||||
|
'data' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function update(OrderUpdate $request)
|
public function update(OrderUpdate $request)
|
||||||
{
|
{
|
||||||
$params = $request->only([
|
$params = $request->only([
|
||||||
'status',
|
|
||||||
'commission_status'
|
'commission_status'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -76,16 +112,6 @@ class OrderController extends Controller
|
|||||||
abort(500, '订单不存在');
|
abort(500, '订单不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($params['status']) && (int)$params['status'] === 2) {
|
|
||||||
$orderService = new OrderService($order);
|
|
||||||
if (!$orderService->cancel()) {
|
|
||||||
abort(500, '更新失败');
|
|
||||||
}
|
|
||||||
return response([
|
|
||||||
'data' => true
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$order->update($params);
|
$order->update($params);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@ -97,26 +123,6 @@ class OrderController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function repair(Request $request)
|
|
||||||
{
|
|
||||||
if (empty($request->input('trade_no'))) {
|
|
||||||
abort(500, '参数错误');
|
|
||||||
}
|
|
||||||
$order = Order::where('trade_no', $request->input('trade_no'))
|
|
||||||
->where('status', 0)
|
|
||||||
->first();
|
|
||||||
if (!$order) {
|
|
||||||
abort(500, '订单不存在或订单已支付');
|
|
||||||
}
|
|
||||||
$order->status = 1;
|
|
||||||
if (!$order->save()) {
|
|
||||||
abort(500, '保存失败');
|
|
||||||
}
|
|
||||||
return response([
|
|
||||||
'data' => true
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function assign(OrderAssign $request)
|
public function assign(OrderAssign $request)
|
||||||
{
|
{
|
||||||
$plan = Plan::find($request->input('plan_id'));
|
$plan = Plan::find($request->input('plan_id'));
|
||||||
@ -130,6 +136,11 @@ class OrderController extends Controller
|
|||||||
abort(500, '该订阅不存在');
|
abort(500, '该订阅不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$userService = new UserService();
|
||||||
|
if ($userService->isNotCompleteOrderByUserId($user->id)) {
|
||||||
|
abort(500, '该用户还有待支付的订单,无法分配');
|
||||||
|
}
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
$order = new Order();
|
$order = new Order();
|
||||||
$orderService = new OrderService($order);
|
$orderService = new OrderService($order);
|
||||||
|
@ -42,6 +42,9 @@ class PaymentController extends Controller
|
|||||||
|
|
||||||
public function save(Request $request)
|
public function save(Request $request)
|
||||||
{
|
{
|
||||||
|
if (!config('v2board.app_url')) {
|
||||||
|
abort(500, '请在站点配置中配置站点地址');
|
||||||
|
}
|
||||||
if ($request->input('id')) {
|
if ($request->input('id')) {
|
||||||
$payment = Payment::find($request->input('id'));
|
$payment = Payment::find($request->input('id'));
|
||||||
if (!$payment) abort(500, '支付方式不存在');
|
if (!$payment) abort(500, '支付方式不存在');
|
||||||
@ -58,7 +61,7 @@ class PaymentController extends Controller
|
|||||||
'name' => $request->input('name'),
|
'name' => $request->input('name'),
|
||||||
'payment' => $request->input('payment'),
|
'payment' => $request->input('payment'),
|
||||||
'config' => $request->input('config'),
|
'config' => $request->input('config'),
|
||||||
'uuid' => Helper::guid()
|
'uuid' => Helper::randomChar(8)
|
||||||
])) {
|
])) {
|
||||||
abort(500, '保存失败');
|
abort(500, '保存失败');
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Http\Controllers\Admin\Server;
|
namespace App\Http\Controllers\Admin\Server;
|
||||||
|
|
||||||
use App\Models\Plan;
|
use App\Models\Plan;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\ServerGroup;
|
use App\Models\ServerGroup;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -50,10 +50,9 @@ class GroupController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$servers = Server::all();
|
$servers = ServerV2ray::all();
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
$groupId = json_decode($server->group_id);
|
if (in_array($request->input('id'), $server->group_id)) {
|
||||||
if (in_array($request->input('id'), $groupId)) {
|
|
||||||
abort(500, '该组已被节点所使用,无法删除');
|
abort(500, '该组已被节点所使用,无法删除');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Admin\Server;
|
namespace App\Http\Controllers\Admin\Server;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\ServerShadowsocks;
|
use App\Models\ServerShadowsocks;
|
||||||
use App\Models\ServerTrojan;
|
use App\Models\ServerTrojan;
|
||||||
use App\Services\ServerService;
|
use App\Services\ServerService;
|
||||||
@ -32,7 +32,7 @@ class ManageController extends Controller
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'v2ray':
|
case 'v2ray':
|
||||||
if (!Server::find($v['value'])->update(['sort' => $k + 1])) {
|
if (!ServerV2ray::find($v['value'])->update(['sort' => $k + 1])) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
abort(500, '保存失败');
|
abort(500, '保存失败');
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,6 @@ class ShadowsocksController extends Controller
|
|||||||
public function save(ServerShadowsocksSave $request)
|
public function save(ServerShadowsocksSave $request)
|
||||||
{
|
{
|
||||||
$params = $request->validated();
|
$params = $request->validated();
|
||||||
$params['group_id'] = json_encode($params['group_id']);
|
|
||||||
if (isset($params['tags'])) {
|
|
||||||
$params['tags'] = json_encode($params['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->input('id')) {
|
if ($request->input('id')) {
|
||||||
$server = ServerShadowsocks::find($request->input('id'));
|
$server = ServerShadowsocks::find($request->input('id'));
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
|
@ -14,11 +14,6 @@ class TrojanController extends Controller
|
|||||||
public function save(ServerTrojanSave $request)
|
public function save(ServerTrojanSave $request)
|
||||||
{
|
{
|
||||||
$params = $request->validated();
|
$params = $request->validated();
|
||||||
$params['group_id'] = json_encode($params['group_id']);
|
|
||||||
if (isset($params['tags'])) {
|
|
||||||
$params['tags'] = json_encode($params['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->input('id')) {
|
if ($request->input('id')) {
|
||||||
$server = ServerTrojan::find($request->input('id'));
|
$server = ServerTrojan::find($request->input('id'));
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
|
@ -7,44 +7,16 @@ use App\Http\Requests\Admin\ServerV2rayUpdate;
|
|||||||
use App\Services\ServerService;
|
use App\Services\ServerService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
|
|
||||||
class V2rayController extends Controller
|
class V2rayController extends Controller
|
||||||
{
|
{
|
||||||
public function save(ServerV2raySave $request)
|
public function save(ServerV2raySave $request)
|
||||||
{
|
{
|
||||||
$params = $request->validated();
|
$params = $request->validated();
|
||||||
$params['group_id'] = json_encode($params['group_id']);
|
|
||||||
if (isset($params['tags'])) {
|
|
||||||
$params['tags'] = json_encode($params['tags']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($params['dnsSettings'])) {
|
|
||||||
if (!is_object(json_decode($params['dnsSettings']))) {
|
|
||||||
abort(500, 'DNS规则配置格式不正确');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($params['ruleSettings'])) {
|
|
||||||
if (!is_object(json_decode($params['ruleSettings']))) {
|
|
||||||
abort(500, '审计规则配置格式不正确');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($params['networkSettings'])) {
|
|
||||||
if (!is_object(json_decode($params['networkSettings']))) {
|
|
||||||
abort(500, '传输协议配置格式不正确');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($params['tlsSettings'])) {
|
|
||||||
if (!is_object(json_decode($params['tlsSettings']))) {
|
|
||||||
abort(500, 'TLS配置格式不正确');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->input('id')) {
|
if ($request->input('id')) {
|
||||||
$server = Server::find($request->input('id'));
|
$server = ServerV2ray::find($request->input('id'));
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
abort(500, '服务器不存在');
|
abort(500, '服务器不存在');
|
||||||
}
|
}
|
||||||
@ -58,7 +30,7 @@ class V2rayController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Server::create($params)) {
|
if (!ServerV2ray::create($params)) {
|
||||||
abort(500, '创建失败');
|
abort(500, '创建失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +42,7 @@ class V2rayController extends Controller
|
|||||||
public function drop(Request $request)
|
public function drop(Request $request)
|
||||||
{
|
{
|
||||||
if ($request->input('id')) {
|
if ($request->input('id')) {
|
||||||
$server = Server::find($request->input('id'));
|
$server = ServerV2ray::find($request->input('id'));
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
abort(500, '节点ID不存在');
|
abort(500, '节点ID不存在');
|
||||||
}
|
}
|
||||||
@ -86,7 +58,7 @@ class V2rayController extends Controller
|
|||||||
'show',
|
'show',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$server = Server::find($request->input('id'));
|
$server = ServerV2ray::find($request->input('id'));
|
||||||
|
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
abort(500, '该服务器不存在');
|
abort(500, '该服务器不存在');
|
||||||
@ -104,12 +76,12 @@ class V2rayController extends Controller
|
|||||||
|
|
||||||
public function copy(Request $request)
|
public function copy(Request $request)
|
||||||
{
|
{
|
||||||
$server = Server::find($request->input('id'));
|
$server = ServerV2ray::find($request->input('id'));
|
||||||
$server->show = 0;
|
$server->show = 0;
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
abort(500, '服务器不存在');
|
abort(500, '服务器不存在');
|
||||||
}
|
}
|
||||||
if (!Server::create($server->toArray())) {
|
if (!ServerV2ray::create($server->toArray())) {
|
||||||
abort(500, '复制失败');
|
abort(500, '复制失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use App\Services\ServerService;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\ServerGroup;
|
use App\Models\ServerGroup;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\Plan;
|
use App\Models\Plan;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Ticket;
|
use App\Models\Ticket;
|
||||||
@ -91,7 +91,7 @@ class StatController extends Controller
|
|||||||
{
|
{
|
||||||
$servers = [
|
$servers = [
|
||||||
'shadowsocks' => ServerShadowsocks::where('parent_id', null)->get()->toArray(),
|
'shadowsocks' => ServerShadowsocks::where('parent_id', null)->get()->toArray(),
|
||||||
'vmess' => Server::where('parent_id', null)->get()->toArray(),
|
'vmess' => ServerV2ray::where('parent_id', null)->get()->toArray(),
|
||||||
'trojan' => ServerTrojan::where('parent_id', null)->get()->toArray()
|
'trojan' => ServerTrojan::where('parent_id', null)->get()->toArray()
|
||||||
];
|
];
|
||||||
$timestamp = strtotime('-1 day', strtotime(date('Y-m-d')));
|
$timestamp = strtotime('-1 day', strtotime(date('Y-m-d')));
|
||||||
|
@ -68,7 +68,7 @@ class UserController extends Controller
|
|||||||
$res[$i]['plan_name'] = $plan[$k]['name'];
|
$res[$i]['plan_name'] = $plan[$k]['name'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$res[$i]['subscribe_url'] = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $res[$i]['token'];
|
$res[$i]['subscribe_url'] = Helper::getSubscribeHost() . '/api/v1/client/subscribe?token=' . $res[$i]['token'];
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => $res,
|
'data' => $res,
|
||||||
|
@ -7,7 +7,7 @@ use App\Services\ServerService;
|
|||||||
use App\Services\UserService;
|
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\ServerV2ray;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ namespace App\Http\Controllers\Client\Protocols;
|
|||||||
|
|
||||||
class AnXray
|
class AnXray
|
||||||
{
|
{
|
||||||
public $flag = 'anxray';
|
public $flag = 'axxray';
|
||||||
private $servers;
|
private $servers;
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
@ -64,15 +64,21 @@ class AnXray
|
|||||||
"encryption" => "none",
|
"encryption" => "none",
|
||||||
"type" => urlencode($server['network']),
|
"type" => urlencode($server['network']),
|
||||||
"security" => $server['tls'] ? "tls" : "",
|
"security" => $server['tls'] ? "tls" : "",
|
||||||
"sni" => $server['tls'] ? urlencode(json_decode($server['tlsSettings'], true)['serverName']) : ""
|
|
||||||
];
|
];
|
||||||
|
if ($server['tls']) {
|
||||||
|
if ($server['tlsSettings']) {
|
||||||
|
$tlsSettings = $server['tlsSettings'];
|
||||||
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
|
$config['sni'] = urlencode($tlsSettings['serverName']);
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((string)$server['network'] === 'ws') {
|
if ((string)$server['network'] === 'ws') {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path'])) $config['path'] = urlencode($wsSettings['path']);
|
if (isset($wsSettings['path'])) $config['path'] = urlencode($wsSettings['path']);
|
||||||
if (isset($wsSettings['headers']['Host'])) $config['host'] = urlencode($wsSettings['headers']['Host']);
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = urlencode($wsSettings['headers']['Host']);
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'grpc') {
|
if ((string)$server['network'] === 'grpc') {
|
||||||
$grpcSettings = json_decode($server['networkSettings'], true);
|
$grpcSettings = $server['networkSettings'];
|
||||||
if (isset($grpcSettings['serviceName'])) $config['serviceName'] = urlencode($grpcSettings['serviceName']);
|
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";
|
return "vmess://" . $uuid . "@" . $server['host'] . ":" . $server['port'] . "?" . http_build_query($config) . "#" . urlencode($server['name']) . "\r\n";
|
||||||
|
@ -20,7 +20,10 @@ class Clash
|
|||||||
{
|
{
|
||||||
$servers = $this->servers;
|
$servers = $this->servers;
|
||||||
$user = $this->user;
|
$user = $this->user;
|
||||||
|
$appName = config('v2board.app_name', 'V2Board');
|
||||||
header("subscription-userinfo: upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}");
|
header("subscription-userinfo: upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}");
|
||||||
|
header('profile-update-interval: 24');
|
||||||
|
header("content-disposition: filename={$appName}");
|
||||||
$defaultConfig = base_path() . '/resources/rules/default.clash.yaml';
|
$defaultConfig = base_path() . '/resources/rules/default.clash.yaml';
|
||||||
$customConfig = base_path() . '/resources/rules/custom.clash.yaml';
|
$customConfig = base_path() . '/resources/rules/custom.clash.yaml';
|
||||||
if (\File::exists($customConfig)) {
|
if (\File::exists($customConfig)) {
|
||||||
@ -51,6 +54,11 @@ class Clash
|
|||||||
if (!is_array($config['proxy-groups'][$k]['proxies'])) continue;
|
if (!is_array($config['proxy-groups'][$k]['proxies'])) continue;
|
||||||
$config['proxy-groups'][$k]['proxies'] = array_merge($config['proxy-groups'][$k]['proxies'], $proxies);
|
$config['proxy-groups'][$k]['proxies'] = array_merge($config['proxy-groups'][$k]['proxies'], $proxies);
|
||||||
}
|
}
|
||||||
|
// Force the current subscription domain to be a direct rule
|
||||||
|
$subsDomain = $_SERVER['SERVER_NAME'];
|
||||||
|
$subsDomainRule = "DOMAIN,{$subsDomain},DIRECT";
|
||||||
|
array_unshift($config['rules'], $subsDomainRule);
|
||||||
|
|
||||||
$yaml = Yaml::dump($config);
|
$yaml = Yaml::dump($config);
|
||||||
$yaml = str_replace('$app_name', config('v2board.app_name', 'V2Board'), $yaml);
|
$yaml = str_replace('$app_name', config('v2board.app_name', 'V2Board'), $yaml);
|
||||||
return $yaml;
|
return $yaml;
|
||||||
@ -84,7 +92,7 @@ class Clash
|
|||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
$array['tls'] = true;
|
$array['tls'] = true;
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
||||||
$array['skip-cert-verify'] = ($tlsSettings['allowInsecure'] ? true : false);
|
$array['skip-cert-verify'] = ($tlsSettings['allowInsecure'] ? true : false);
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
@ -94,7 +102,7 @@ class Clash
|
|||||||
if ($server['network'] === 'ws') {
|
if ($server['network'] === 'ws') {
|
||||||
$array['network'] = 'ws';
|
$array['network'] = 'ws';
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
||||||
$array['ws-path'] = $wsSettings['path'];
|
$array['ws-path'] = $wsSettings['path'];
|
||||||
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
||||||
@ -104,7 +112,7 @@ class Clash
|
|||||||
if ($server['network'] === 'grpc') {
|
if ($server['network'] === 'grpc') {
|
||||||
$array['network'] = 'grpc';
|
$array['network'] = 'grpc';
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$grpcObject = json_decode($server['networkSettings'], true);
|
$grpcObject = $server['networkSettings'];
|
||||||
$array['grpc-opts'] = [];
|
$array['grpc-opts'] = [];
|
||||||
$array['grpc-opts']['grpc-service-name'] = $grpcObject['serviceName'];
|
$array['grpc-opts']['grpc-service-name'] = $grpcObject['serviceName'];
|
||||||
}
|
}
|
||||||
|
@ -63,19 +63,19 @@ class Passwall
|
|||||||
];
|
];
|
||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
$config['sni'] = $tlsSettings['serverName'];
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'ws') {
|
if ((string)$server['network'] === 'ws') {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'grpc') {
|
if ((string)$server['network'] === 'grpc') {
|
||||||
$grpcSettings = json_decode($server['networkSettings'], true);
|
$grpcSettings = $server['networkSettings'];
|
||||||
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
if (isset($grpcSettings['serviceName'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
}
|
}
|
||||||
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ class QuantumultX
|
|||||||
if ($server['network'] === 'tcp')
|
if ($server['network'] === 'tcp')
|
||||||
array_push($config, 'obfs=over-tls');
|
array_push($config, 'obfs=over-tls');
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
||||||
array_push($config, 'tls-verification=' . ($tlsSettings['allowInsecure'] ? 'false' : 'true'));
|
array_push($config, 'tls-verification=' . ($tlsSettings['allowInsecure'] ? 'false' : 'true'));
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
@ -79,7 +79,7 @@ class QuantumultX
|
|||||||
else
|
else
|
||||||
array_push($config, 'obfs=ws');
|
array_push($config, 'obfs=ws');
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
||||||
array_push($config, "obfs-uri={$wsSettings['path']}");
|
array_push($config, "obfs-uri={$wsSettings['path']}");
|
||||||
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']) && !isset($host))
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']) && !isset($host))
|
||||||
|
@ -63,19 +63,19 @@ class SSRPlus
|
|||||||
];
|
];
|
||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
$config['sni'] = $tlsSettings['serverName'];
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'ws') {
|
if ((string)$server['network'] === 'ws') {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'grpc') {
|
if ((string)$server['network'] === 'grpc') {
|
||||||
$grpcSettings = json_decode($server['networkSettings'], true);
|
$grpcSettings = $server['networkSettings'];
|
||||||
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
if (isset($grpcSettings['serviceName'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
}
|
}
|
||||||
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ class Shadowrocket
|
|||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
$config['tls'] = 1;
|
$config['tls'] = 1;
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
||||||
$config['allowInsecure'] = (int)$tlsSettings['allowInsecure'];
|
$config['allowInsecure'] = (int)$tlsSettings['allowInsecure'];
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
@ -73,7 +73,7 @@ class Shadowrocket
|
|||||||
if ($server['network'] === 'ws') {
|
if ($server['network'] === 'ws') {
|
||||||
$config['obfs'] = "websocket";
|
$config['obfs'] = "websocket";
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
||||||
$config['path'] = $wsSettings['path'];
|
$config['path'] = $wsSettings['path'];
|
||||||
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
||||||
@ -83,7 +83,7 @@ class Shadowrocket
|
|||||||
if ($server['network'] === 'grpc') {
|
if ($server['network'] === 'grpc') {
|
||||||
$config['obfs'] = "grpc";
|
$config['obfs'] = "grpc";
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$grpcSettings = json_decode($server['networkSettings'], true);
|
$grpcSettings = $server['networkSettings'];
|
||||||
if (isset($grpcSettings['serviceName']) && !empty($grpcSettings['serviceName']))
|
if (isset($grpcSettings['serviceName']) && !empty($grpcSettings['serviceName']))
|
||||||
$config['path'] = $grpcSettings['serviceName'];
|
$config['path'] = $grpcSettings['serviceName'];
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,19 @@ class Surfboard
|
|||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if ($item['type'] === 'shadowsocks') {
|
if ($item['type'] === 'shadowsocks') {
|
||||||
// [Proxy]
|
// [Proxy]
|
||||||
$proxies .= Surfboard::buildShadowsocks($user['uuid'], $item);
|
$proxies .= self::buildShadowsocks($user['uuid'], $item);
|
||||||
// [Proxy Group]
|
// [Proxy Group]
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'v2ray') {
|
if ($item['type'] === 'v2ray') {
|
||||||
// [Proxy]
|
// [Proxy]
|
||||||
$proxies .= Surfboard::buildVmess($user['uuid'], $item);
|
$proxies .= self::buildVmess($user['uuid'], $item);
|
||||||
|
// [Proxy Group]
|
||||||
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
|
}
|
||||||
|
if ($item['type'] === 'trojan') {
|
||||||
|
// [Proxy]
|
||||||
|
$proxies .= self::buildTrojan($user['uuid'], $item);
|
||||||
// [Proxy Group]
|
// [Proxy Group]
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
@ -48,8 +54,10 @@ class Surfboard
|
|||||||
|
|
||||||
// Subscription link
|
// Subscription link
|
||||||
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
||||||
|
$subsDomain = $_SERVER['SERVER_NAME'];
|
||||||
|
|
||||||
$config = str_replace('$subs_link', $subsURL, $config);
|
$config = str_replace('$subs_link', $subsURL, $config);
|
||||||
|
$config = str_replace('$subs_domain', $subsDomain, $config);
|
||||||
$config = str_replace('$proxies', $proxies, $config);
|
$config = str_replace('$proxies', $proxies, $config);
|
||||||
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
||||||
return $config;
|
return $config;
|
||||||
@ -88,7 +96,7 @@ class Surfboard
|
|||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
array_push($config, 'tls=true');
|
array_push($config, 'tls=true');
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
||||||
array_push($config, 'skip-cert-verify=' . ($tlsSettings['allowInsecure'] ? 'true' : 'false'));
|
array_push($config, 'skip-cert-verify=' . ($tlsSettings['allowInsecure'] ? 'true' : 'false'));
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
@ -98,7 +106,7 @@ class Surfboard
|
|||||||
if ($server['network'] === 'ws') {
|
if ($server['network'] === 'ws') {
|
||||||
array_push($config, 'ws=true');
|
array_push($config, 'ws=true');
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
||||||
array_push($config, "ws-path={$wsSettings['path']}");
|
array_push($config, "ws-path={$wsSettings['path']}");
|
||||||
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
||||||
@ -110,4 +118,24 @@ class Surfboard
|
|||||||
$uri .= "\r\n";
|
$uri .= "\r\n";
|
||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function buildTrojan($password, $server)
|
||||||
|
{
|
||||||
|
$config = [
|
||||||
|
"{$server['name']}=trojan",
|
||||||
|
"{$server['host']}",
|
||||||
|
"{$server['port']}",
|
||||||
|
"password={$password}",
|
||||||
|
$server['server_name'] ? "sni={$server['server_name']}" : "",
|
||||||
|
'tfo=true',
|
||||||
|
'udp-relay=true'
|
||||||
|
];
|
||||||
|
if (!empty($server['allow_insecure'])) {
|
||||||
|
array_push($config, $server['allow_insecure'] ? 'skip-cert-verify=true' : 'skip-cert-verify=false');
|
||||||
|
}
|
||||||
|
$config = array_filter($config);
|
||||||
|
$uri = implode(',', $config);
|
||||||
|
$uri .= "\r\n";
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,10 @@ class Surge
|
|||||||
|
|
||||||
// Subscription link
|
// Subscription link
|
||||||
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
$subsURL = config('v2board.subscribe_url', config('v2board.app_url', env('APP_URL'))) . '/api/v1/client/subscribe?token=' . $user['token'];
|
||||||
|
$subsDomain = $_SERVER['SERVER_NAME'];
|
||||||
|
|
||||||
$config = str_replace('$subs_link', $subsURL, $config);
|
$config = str_replace('$subs_link', $subsURL, $config);
|
||||||
|
$config = str_replace('$subs_domain', $subsDomain, $config);
|
||||||
$config = str_replace('$proxies', $proxies, $config);
|
$config = str_replace('$proxies', $proxies, $config);
|
||||||
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
$config = str_replace('$proxy_group', rtrim($proxyGroup, ', '), $config);
|
||||||
return $config;
|
return $config;
|
||||||
@ -92,7 +94,7 @@ class Surge
|
|||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
array_push($config, 'tls=true');
|
array_push($config, 'tls=true');
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure']))
|
||||||
array_push($config, 'skip-cert-verify=' . ($tlsSettings['allowInsecure'] ? 'true' : 'false'));
|
array_push($config, 'skip-cert-verify=' . ($tlsSettings['allowInsecure'] ? 'true' : 'false'));
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
@ -102,7 +104,7 @@ class Surge
|
|||||||
if ($server['network'] === 'ws') {
|
if ($server['network'] === 'ws') {
|
||||||
array_push($config, 'ws=true');
|
array_push($config, 'ws=true');
|
||||||
if ($server['networkSettings']) {
|
if ($server['networkSettings']) {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
if (isset($wsSettings['path']) && !empty($wsSettings['path']))
|
||||||
array_push($config, "ws-path={$wsSettings['path']}");
|
array_push($config, "ws-path={$wsSettings['path']}");
|
||||||
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host']))
|
||||||
|
@ -63,19 +63,19 @@ class V2rayN
|
|||||||
];
|
];
|
||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
$config['sni'] = $tlsSettings['serverName'];
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'ws') {
|
if ((string)$server['network'] === 'ws') {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'grpc') {
|
if ((string)$server['network'] === 'grpc') {
|
||||||
$grpcSettings = json_decode($server['networkSettings'], true);
|
$grpcSettings = $server['networkSettings'];
|
||||||
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
if (isset($grpcSettings['serviceName'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
}
|
}
|
||||||
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -63,19 +63,19 @@ class V2rayNG
|
|||||||
];
|
];
|
||||||
if ($server['tls']) {
|
if ($server['tls']) {
|
||||||
if ($server['tlsSettings']) {
|
if ($server['tlsSettings']) {
|
||||||
$tlsSettings = json_decode($server['tlsSettings'], true);
|
$tlsSettings = $server['tlsSettings'];
|
||||||
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
if (isset($tlsSettings['serverName']) && !empty($tlsSettings['serverName']))
|
||||||
$config['sni'] = $tlsSettings['serverName'];
|
$config['sni'] = $tlsSettings['serverName'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'ws') {
|
if ((string)$server['network'] === 'ws') {
|
||||||
$wsSettings = json_decode($server['networkSettings'], true);
|
$wsSettings = $server['networkSettings'];
|
||||||
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
if (isset($wsSettings['path'])) $config['path'] = $wsSettings['path'];
|
||||||
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
if (isset($wsSettings['headers']['Host'])) $config['host'] = $wsSettings['headers']['Host'];
|
||||||
}
|
}
|
||||||
if ((string)$server['network'] === 'grpc') {
|
if ((string)$server['network'] === 'grpc') {
|
||||||
$grpcSettings = json_decode($server['networkSettings'], true);
|
$grpcSettings = $server['networkSettings'];
|
||||||
if (isset($grpcSettings['path'])) $config['path'] = $grpcSettings['serviceName'];
|
if (isset($grpcSettings['serviceName'])) $config['path'] = $grpcSettings['serviceName'];
|
||||||
}
|
}
|
||||||
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
return "vmess://" . base64_encode(json_encode($config)) . "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ class PaymentController extends Controller
|
|||||||
}
|
}
|
||||||
if ($order->status === 1) return true;
|
if ($order->status === 1) return true;
|
||||||
$orderService = new OrderService($order);
|
$orderService = new OrderService($order);
|
||||||
if (!$orderService->success($callbackNo)) {
|
if (!$orderService->paid($callbackNo)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$telegramService = new TelegramService();
|
$telegramService = new TelegramService();
|
||||||
|
@ -102,10 +102,15 @@ class AuthController extends Controller
|
|||||||
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')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'token' => $user->token,
|
||||||
|
'auth_data' => base64_encode("{$user->email}:{$user->password}")
|
||||||
|
];
|
||||||
$request->session()->put('email', $user->email);
|
$request->session()->put('email', $user->email);
|
||||||
$request->session()->put('id', $user->id);
|
$request->session()->put('id', $user->id);
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'data' => true
|
'data' => $data
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +125,7 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
if (!Helper::multiPasswordVerify(
|
if (!Helper::multiPasswordVerify(
|
||||||
$user->password_algo,
|
$user->password_algo,
|
||||||
|
$user->password_salt,
|
||||||
$password,
|
$password,
|
||||||
$user->password)
|
$user->password)
|
||||||
) {
|
) {
|
||||||
@ -250,6 +256,7 @@ class AuthController extends Controller
|
|||||||
}
|
}
|
||||||
$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;
|
||||||
|
$user->password_salt = NULL;
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, __('Reset failed'));
|
abort(500, __('Reset failed'));
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use App\Utils\CacheKey;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\ServerLog;
|
use App\Models\ServerLog;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -35,13 +35,13 @@ class DeepbworkController extends Controller
|
|||||||
public function user(Request $request)
|
public function user(Request $request)
|
||||||
{
|
{
|
||||||
$nodeId = $request->input('node_id');
|
$nodeId = $request->input('node_id');
|
||||||
$server = Server::find($nodeId);
|
$server = ServerV2ray::find($nodeId);
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
abort(500, 'fail');
|
abort(500, 'fail');
|
||||||
}
|
}
|
||||||
Cache::put(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $server->id), time(), 3600);
|
Cache::put(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $server->id), time(), 3600);
|
||||||
$serverService = new ServerService();
|
$serverService = new ServerService();
|
||||||
$users = $serverService->getAvailableUsers(json_decode($server->group_id));
|
$users = $serverService->getAvailableUsers($server->group_id);
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
$user->v2ray_user = [
|
$user->v2ray_user = [
|
||||||
@ -64,7 +64,7 @@ class DeepbworkController extends Controller
|
|||||||
public function submit(Request $request)
|
public function submit(Request $request)
|
||||||
{
|
{
|
||||||
// Log::info('serverSubmitData:' . $request->input('node_id') . ':' . file_get_contents('php://input'));
|
// Log::info('serverSubmitData:' . $request->input('node_id') . ':' . file_get_contents('php://input'));
|
||||||
$server = Server::find($request->input('node_id'));
|
$server = ServerV2ray::find($request->input('node_id'));
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
return response([
|
return response([
|
||||||
'ret' => 0,
|
'ret' => 0,
|
||||||
@ -76,23 +76,11 @@ class DeepbworkController extends Controller
|
|||||||
Cache::put(CacheKey::get('SERVER_V2RAY_ONLINE_USER', $server->id), count($data), 3600);
|
Cache::put(CacheKey::get('SERVER_V2RAY_ONLINE_USER', $server->id), count($data), 3600);
|
||||||
Cache::put(CacheKey::get('SERVER_V2RAY_LAST_PUSH_AT', $server->id), time(), 3600);
|
Cache::put(CacheKey::get('SERVER_V2RAY_LAST_PUSH_AT', $server->id), time(), 3600);
|
||||||
$userService = new UserService();
|
$userService = new UserService();
|
||||||
DB::beginTransaction();
|
foreach ($data as $item) {
|
||||||
try {
|
$u = $item['u'] * $server->rate;
|
||||||
foreach ($data as $item) {
|
$d = $item['d'] * $server->rate;
|
||||||
$u = $item['u'] * $server->rate;
|
$userService->trafficFetch($u, $d, $item['user_id'], $server, 'vmess');
|
||||||
$d = $item['d'] * $server->rate;
|
|
||||||
if (!$userService->trafficFetch($u, $d, $item['user_id'], $server, 'vmess')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
DB::rollBack();
|
|
||||||
return response([
|
|
||||||
'ret' => 0,
|
|
||||||
'msg' => 'user fetch fail'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
DB::commit();
|
|
||||||
|
|
||||||
return response([
|
return response([
|
||||||
'ret' => 1,
|
'ret' => 1,
|
||||||
|
@ -1,158 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Server;
|
|
||||||
|
|
||||||
use App\Services\ServerService;
|
|
||||||
use App\Services\UserService;
|
|
||||||
use App\Utils\CacheKey;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\Plan;
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\ServerLog;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* V2ray Poseidon
|
|
||||||
* Github: https://github.com/ColetteContreras/trojan-poseidon
|
|
||||||
*/
|
|
||||||
class PoseidonController extends Controller
|
|
||||||
{
|
|
||||||
public $poseidonVersion;
|
|
||||||
|
|
||||||
public function __construct(Request $request)
|
|
||||||
{
|
|
||||||
$this->poseidonVersion = $request->input('poseidon_version');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 后端获取用户
|
|
||||||
public function user(Request $request)
|
|
||||||
{
|
|
||||||
if ($r = $this->verifyToken($request)) { return $r; }
|
|
||||||
|
|
||||||
$nodeId = $request->input('node_id');
|
|
||||||
$server = Server::find($nodeId);
|
|
||||||
if (!$server) {
|
|
||||||
return $this->error("server could not be found", 404);
|
|
||||||
}
|
|
||||||
Cache::put(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $server->id), time(), 3600);
|
|
||||||
$serverService = new ServerService();
|
|
||||||
$users = $serverService->getAvailableUsers(json_decode($server->group_id));
|
|
||||||
$result = [];
|
|
||||||
foreach ($users as $user) {
|
|
||||||
$user->v2ray_user = [
|
|
||||||
"uuid" => $user->uuid,
|
|
||||||
"email" => sprintf("%s@v2board.user", $user->uuid),
|
|
||||||
"alter_id" => $server->alter_id,
|
|
||||||
"level" => 0,
|
|
||||||
];
|
|
||||||
unset($user['uuid']);
|
|
||||||
unset($user['email']);
|
|
||||||
array_push($result, $user);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->success($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 后端提交数据
|
|
||||||
public function submit(Request $request)
|
|
||||||
{
|
|
||||||
if ($r = $this->verifyToken($request)) { return $r; }
|
|
||||||
$server = Server::find($request->input('node_id'));
|
|
||||||
if (!$server) {
|
|
||||||
return $this->error("server could not be found", 404);
|
|
||||||
}
|
|
||||||
$data = file_get_contents('php://input');
|
|
||||||
$data = json_decode($data, true);
|
|
||||||
Cache::put(CacheKey::get('SERVER_V2RAY_ONLINE_USER', $server->id), count($data), 3600);
|
|
||||||
Cache::put(CacheKey::get('SERVER_V2RAY_LAST_PUSH_AT', $server->id), time(), 3600);
|
|
||||||
$userService = new UserService();
|
|
||||||
foreach ($data as $item) {
|
|
||||||
$u = $item['u'] * $server->rate;
|
|
||||||
$d = $item['d'] * $server->rate;
|
|
||||||
if (!$userService->trafficFetch($u, $d, $item['user_id'], $server, 'vmess')) {
|
|
||||||
return $this->error("user fetch fail", 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->success('');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 后端获取配置
|
|
||||||
public function config(Request $request)
|
|
||||||
{
|
|
||||||
if ($r = $this->verifyToken($request)) { return $r; }
|
|
||||||
|
|
||||||
$nodeId = $request->input('node_id');
|
|
||||||
$localPort = $request->input('local_port');
|
|
||||||
if (empty($nodeId) || empty($localPort)) {
|
|
||||||
return $this->error('invalid parameters', 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$serverService = new ServerService();
|
|
||||||
try {
|
|
||||||
$json = $serverService->getV2RayConfig($nodeId, $localPort);
|
|
||||||
$json->poseidon = [
|
|
||||||
'license_key' => (string)config('v2board.server_license'),
|
|
||||||
];
|
|
||||||
if ($this->poseidonVersion >= 'v1.5.0') {
|
|
||||||
// don't need it after v1.5.0
|
|
||||||
unset($json->inboundDetour);
|
|
||||||
unset($json->stats);
|
|
||||||
unset($json->api);
|
|
||||||
array_shift($json->routing->rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($json->policy->levels as &$level) {
|
|
||||||
$level->handshake = 2;
|
|
||||||
$level->uplinkOnly = 2;
|
|
||||||
$level->downlinkOnly = 2;
|
|
||||||
$level->connIdle = 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->success($json);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return $this->error($e->getMessage(), 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function verifyToken(Request $request)
|
|
||||||
{
|
|
||||||
$token = $request->input('token');
|
|
||||||
if (empty($token)) {
|
|
||||||
return $this->error("token must be set");
|
|
||||||
}
|
|
||||||
if ($token !== config('v2board.server_token')) {
|
|
||||||
return $this->error("invalid token");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function error($msg, int $status = 400) {
|
|
||||||
return response([
|
|
||||||
'msg' => $msg,
|
|
||||||
], $status);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function success($data) {
|
|
||||||
$req = request();
|
|
||||||
// Only for "GET" method
|
|
||||||
if (!$req->isMethod('GET') || !$data) {
|
|
||||||
return response([
|
|
||||||
'msg' => 'ok',
|
|
||||||
'data' => $data,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$etag = sha1(json_encode($data));
|
|
||||||
if ($etag == $req->header("IF-NONE-MATCH")) {
|
|
||||||
return response(null, 304);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response([
|
|
||||||
'msg' => 'ok',
|
|
||||||
'data' => $data,
|
|
||||||
])->header('ETAG', $etag);
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,10 +8,6 @@ use App\Services\UserService;
|
|||||||
use App\Utils\CacheKey;
|
use App\Utils\CacheKey;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\ServerLog;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -41,7 +37,7 @@ class ShadowsocksTidalabController extends Controller
|
|||||||
}
|
}
|
||||||
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $server->id), time(), 3600);
|
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $server->id), time(), 3600);
|
||||||
$serverService = new ServerService();
|
$serverService = new ServerService();
|
||||||
$users = $serverService->getAvailableUsers(json_decode($server->group_id));
|
$users = $serverService->getAvailableUsers($server->group_id);
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
array_push($result, [
|
array_push($result, [
|
||||||
@ -72,23 +68,11 @@ class ShadowsocksTidalabController extends Controller
|
|||||||
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_ONLINE_USER', $server->id), count($data), 3600);
|
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_ONLINE_USER', $server->id), count($data), 3600);
|
||||||
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_LAST_PUSH_AT', $server->id), time(), 3600);
|
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_LAST_PUSH_AT', $server->id), time(), 3600);
|
||||||
$userService = new UserService();
|
$userService = new UserService();
|
||||||
DB::beginTransaction();
|
foreach ($data as $item) {
|
||||||
try {
|
$u = $item['u'] * $server->rate;
|
||||||
foreach ($data as $item) {
|
$d = $item['d'] * $server->rate;
|
||||||
$u = $item['u'] * $server->rate;
|
$userService->trafficFetch($u, $d, $item['user_id'], $server, 'shadowsocks');
|
||||||
$d = $item['d'] * $server->rate;
|
|
||||||
if (!$userService->trafficFetch((float)$u, (float)$d, (int)$item['user_id'], $server, 'shadowsocks')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
DB::rollBack();
|
|
||||||
return response([
|
|
||||||
'ret' => 0,
|
|
||||||
'msg' => 'user fetch fail'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
DB::commit();
|
|
||||||
|
|
||||||
return response([
|
return response([
|
||||||
'ret' => 1,
|
'ret' => 1,
|
||||||
|
@ -41,7 +41,7 @@ class TrojanTidalabController extends Controller
|
|||||||
}
|
}
|
||||||
Cache::put(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $server->id), time(), 3600);
|
Cache::put(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $server->id), time(), 3600);
|
||||||
$serverService = new ServerService();
|
$serverService = new ServerService();
|
||||||
$users = $serverService->getAvailableUsers(json_decode($server->group_id));
|
$users = $serverService->getAvailableUsers($server->group_id);
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
$user->trojan_user = [
|
$user->trojan_user = [
|
||||||
@ -73,23 +73,11 @@ class TrojanTidalabController extends Controller
|
|||||||
Cache::put(CacheKey::get('SERVER_TROJAN_ONLINE_USER', $server->id), count($data), 3600);
|
Cache::put(CacheKey::get('SERVER_TROJAN_ONLINE_USER', $server->id), count($data), 3600);
|
||||||
Cache::put(CacheKey::get('SERVER_TROJAN_LAST_PUSH_AT', $server->id), time(), 3600);
|
Cache::put(CacheKey::get('SERVER_TROJAN_LAST_PUSH_AT', $server->id), time(), 3600);
|
||||||
$userService = new UserService();
|
$userService = new UserService();
|
||||||
DB::beginTransaction();
|
foreach ($data as $item) {
|
||||||
try {
|
$u = $item['u'] * $server->rate;
|
||||||
foreach ($data as $item) {
|
$d = $item['d'] * $server->rate;
|
||||||
$u = $item['u'] * $server->rate;
|
$userService->trafficFetch($u, $d, $item['user_id'], $server, 'trojan');
|
||||||
$d = $item['d'] * $server->rate;
|
|
||||||
if (!$userService->trafficFetch($u, $d, $item['user_id'], $server, 'trojan')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
DB::rollBack();
|
|
||||||
return response([
|
|
||||||
'ret' => 0,
|
|
||||||
'msg' => 'user fetch fail'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
DB::commit();
|
|
||||||
|
|
||||||
return response([
|
return response([
|
||||||
'ret' => 1,
|
'ret' => 1,
|
||||||
|
@ -27,9 +27,8 @@ class CommController extends Controller
|
|||||||
->where('payment', 'StripeCredit')
|
->where('payment', 'StripeCredit')
|
||||||
->first();
|
->first();
|
||||||
if (!$payment) abort(500, 'payment is not found');
|
if (!$payment) abort(500, 'payment is not found');
|
||||||
$config = json_decode($payment->config, true);
|
|
||||||
return response([
|
return response([
|
||||||
'data' => $config['stripe_pk_live']
|
'data' => $payment->config['stripe_pk_live']
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers\User;
|
namespace App\Http\Controllers\User;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Services\CouponService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\Coupon;
|
use App\Models\Coupon;
|
||||||
|
|
||||||
@ -13,27 +14,12 @@ class CouponController extends Controller
|
|||||||
if (empty($request->input('code'))) {
|
if (empty($request->input('code'))) {
|
||||||
abort(500, __('Coupon cannot be empty'));
|
abort(500, __('Coupon cannot be empty'));
|
||||||
}
|
}
|
||||||
$coupon = Coupon::where('code', $request->input('code'))->first();
|
$couponService = new CouponService($request->input('code'));
|
||||||
if (!$coupon) {
|
$couponService->setPlanId($request->input('plan_id'));
|
||||||
abort(500, __('Invalid coupon'));
|
$couponService->setUserId($request->session()->get('id'));
|
||||||
}
|
$couponService->check();
|
||||||
if ($coupon->limit_use <= 0 && $coupon->limit_use !== NULL) {
|
|
||||||
abort(500, __('This coupon is no longer available'));
|
|
||||||
}
|
|
||||||
if (time() < $coupon->started_at) {
|
|
||||||
abort(500, __('This coupon has not yet started'));
|
|
||||||
}
|
|
||||||
if (time() > $coupon->ended_at) {
|
|
||||||
abort(500, __('This coupon has expired'));
|
|
||||||
}
|
|
||||||
if ($coupon->limit_plan_ids) {
|
|
||||||
$limitPlanIds = json_decode($coupon->limit_plan_ids);
|
|
||||||
if (!in_array($request->input('plan_id'), $limitPlanIds)) {
|
|
||||||
abort(500, __('The coupon code cannot be used for this subscription'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response([
|
return response([
|
||||||
'data' => $coupon
|
'data' => $couponService->getCoupon()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,6 @@ class KnowledgeController extends Controller
|
|||||||
}
|
}
|
||||||
$subscribeUrl = "{$subscribeUrl}/api/v1/client/subscribe?token={$user['token']}";
|
$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('{{appleIdPassword}}', $appleIdPassword, $knowledge['body']);
|
|
||||||
$knowledge['body'] = str_replace('{{subscribeUrl}}', $subscribeUrl, $knowledge['body']);
|
$knowledge['body'] = str_replace('{{subscribeUrl}}', $subscribeUrl, $knowledge['body']);
|
||||||
$knowledge['body'] = str_replace('{{urlEncodeSubscribeUrl}}', urlencode($subscribeUrl), $knowledge['body']);
|
$knowledge['body'] = str_replace('{{urlEncodeSubscribeUrl}}', urlencode($subscribeUrl), $knowledge['body']);
|
||||||
$knowledge['body'] = str_replace(
|
$knowledge['body'] = str_replace(
|
||||||
|
@ -108,7 +108,7 @@ class OrderController extends Controller
|
|||||||
$order->user_id = $request->session()->get('id');
|
$order->user_id = $request->session()->get('id');
|
||||||
$order->plan_id = $plan->id;
|
$order->plan_id = $plan->id;
|
||||||
$order->cycle = $request->input('cycle');
|
$order->cycle = $request->input('cycle');
|
||||||
$order->trade_no = Helper::guid();
|
$order->trade_no = Helper::generateOrderNo();
|
||||||
$order->total_amount = $plan[$request->input('cycle')];
|
$order->total_amount = $plan[$request->input('cycle')];
|
||||||
|
|
||||||
if ($request->input('coupon_code')) {
|
if ($request->input('coupon_code')) {
|
||||||
@ -169,9 +169,8 @@ class OrderController extends Controller
|
|||||||
}
|
}
|
||||||
// free process
|
// free process
|
||||||
if ($order->total_amount <= 0) {
|
if ($order->total_amount <= 0) {
|
||||||
$order->total_amount = 0;
|
$orderService = new OrderService($order);
|
||||||
$order->status = 1;
|
if (!$orderService->paid($order->trade_no)) abort(500, '');
|
||||||
$order->save();
|
|
||||||
return response([
|
return response([
|
||||||
'type' => -1,
|
'type' => -1,
|
||||||
'data' => true
|
'data' => true
|
||||||
|
@ -8,7 +8,7 @@ use App\Services\UserService;
|
|||||||
use App\Utils\CacheKey;
|
use App\Utils\CacheKey;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\ServerLog;
|
use App\Models\ServerLog;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
||||||
@ -36,16 +36,16 @@ class ServerController extends Controller
|
|||||||
$current = $request->input('current') ? $request->input('current') : 1;
|
$current = $request->input('current') ? $request->input('current') : 1;
|
||||||
$pageSize = $request->input('pageSize') >= 10 ? $request->input('pageSize') : 10;
|
$pageSize = $request->input('pageSize') >= 10 ? $request->input('pageSize') : 10;
|
||||||
$serverLogModel = ServerLog::where('user_id', $request->session()->get('id'))
|
$serverLogModel = ServerLog::where('user_id', $request->session()->get('id'))
|
||||||
->orderBy('created_at', 'DESC');
|
->orderBy('log_at', 'DESC');
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 0:
|
case 0:
|
||||||
$serverLogModel->where('created_at', '>=', strtotime(date('Y-m-d')));
|
$serverLogModel->where('log_at', '>=', strtotime(date('Y-m-d')));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
$serverLogModel->where('created_at', '>=', strtotime(date('Y-m-d')) - 604800);
|
$serverLogModel->where('log_at', '>=', strtotime(date('Y-m-d')) - 604800);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
$serverLogModel->where('created_at', '>=', strtotime(date('Y-m-1')));
|
$serverLogModel->where('log_at', '>=', strtotime(date('Y-m-1')));
|
||||||
}
|
}
|
||||||
$total = $serverLogModel->count();
|
$total = $serverLogModel->count();
|
||||||
$res = $serverLogModel->forPage($current, $pageSize)
|
$res = $serverLogModel->forPage($current, $pageSize)
|
||||||
|
@ -168,7 +168,7 @@ class TicketController extends Controller
|
|||||||
$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, __('The current required minimum withdrawal commission is', ['limit' => $limit]));
|
abort(500, __('The current required minimum withdrawal commission is :limit', ['limit' => $limit]));
|
||||||
}
|
}
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
$subject = __('[Commission Withdrawal Request] This ticket is opened by the system');
|
$subject = __('[Commission Withdrawal Request] This ticket is opened by the system');
|
||||||
|
@ -6,14 +6,16 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Http\Requests\User\UserTransfer;
|
use App\Http\Requests\User\UserTransfer;
|
||||||
use App\Http\Requests\User\UserUpdate;
|
use App\Http\Requests\User\UserUpdate;
|
||||||
use App\Http\Requests\User\UserChangePassword;
|
use App\Http\Requests\User\UserChangePassword;
|
||||||
|
use App\Utils\CacheKey;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Plan;
|
use App\Models\Plan;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\Ticket;
|
use App\Models\Ticket;
|
||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
use App\Models\ServerLog;
|
use App\Models\ServerLog;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
@ -33,6 +35,7 @@ class UserController extends Controller
|
|||||||
}
|
}
|
||||||
if (!Helper::multiPasswordVerify(
|
if (!Helper::multiPasswordVerify(
|
||||||
$user->password_algo,
|
$user->password_algo,
|
||||||
|
$user->password_salt,
|
||||||
$request->input('old_password'),
|
$request->input('old_password'),
|
||||||
$user->password)
|
$user->password)
|
||||||
) {
|
) {
|
||||||
@ -40,6 +43,7 @@ class UserController extends Controller
|
|||||||
}
|
}
|
||||||
$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;
|
||||||
|
$user->password_salt = NULL;
|
||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
abort(500, __('Save failed'));
|
abort(500, __('Save failed'));
|
||||||
}
|
}
|
||||||
@ -118,12 +122,7 @@ class UserController extends Controller
|
|||||||
abort(500, __('Subscription plan does not exist'));
|
abort(500, __('Subscription plan does not exist'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$subscribeUrl = config('v2board.app_url', env('APP_URL'));
|
$user['subscribe_url'] = Helper::getSubscribeHost() . "/api/v1/client/subscribe?token={$user['token']}";
|
||||||
$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
|
||||||
@ -209,4 +208,26 @@ class UserController extends Controller
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getQuickLoginUrl(Request $request)
|
||||||
|
{
|
||||||
|
$user = User::find($request->session()->get('id'));
|
||||||
|
if (!$user) {
|
||||||
|
abort(500, __('The user does not exist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = Helper::guid();
|
||||||
|
$key = CacheKey::get('TEMP_TOKEN', $code);
|
||||||
|
Cache::put($key, $user->id, 60);
|
||||||
|
$redirect = '/#/login?verify=' . $code . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
|
||||||
|
if (config('v2board.app_url')) {
|
||||||
|
$url = config('v2board.app_url') . $redirect;
|
||||||
|
} else {
|
||||||
|
$url = url($redirect);
|
||||||
|
}
|
||||||
|
return response([
|
||||||
|
'data' => $url
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\App\Http\Middleware\CORS::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
|
@ -15,8 +15,9 @@ class User
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if ($request->input('auth_data')) {
|
$authorization = $request->input('auth_data') ?? $request->header('authorization');
|
||||||
$authData = explode(':', base64_decode($request->input('auth_data')));
|
if ($authorization) {
|
||||||
|
$authData = explode(':', base64_decode($authorization));
|
||||||
if (!isset($authData[1]) || !isset($authData[0])) abort(403, '鉴权失败,请重新登入');
|
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])
|
||||||
|
@ -25,6 +25,10 @@ class ConfigSave extends FormRequest
|
|||||||
'commission_withdraw_limit' => 'nullable|numeric',
|
'commission_withdraw_limit' => 'nullable|numeric',
|
||||||
'commission_withdraw_method' => 'nullable|array',
|
'commission_withdraw_method' => 'nullable|array',
|
||||||
'withdraw_close_enable' => 'in:0,1',
|
'withdraw_close_enable' => 'in:0,1',
|
||||||
|
'commission_distribution_enable' => 'in:0,1',
|
||||||
|
'commission_distribution_l1' => 'nullable|numeric',
|
||||||
|
'commission_distribution_l2' => 'nullable|numeric',
|
||||||
|
'commission_distribution_l3' => 'nullable|numeric',
|
||||||
// site
|
// site
|
||||||
'stop_register' => 'in:0,1',
|
'stop_register' => 'in:0,1',
|
||||||
'email_verify' => 'in:0,1',
|
'email_verify' => 'in:0,1',
|
||||||
@ -44,7 +48,7 @@ class ConfigSave extends FormRequest
|
|||||||
'tos_url' => 'nullable|url',
|
'tos_url' => 'nullable|url',
|
||||||
// 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,2',
|
||||||
'surplus_enable' => 'in:0,1',
|
'surplus_enable' => 'in:0,1',
|
||||||
'new_order_event_id' => 'in:0,1',
|
'new_order_event_id' => 'in:0,1',
|
||||||
'renew_order_event_id' => 'in:0,1',
|
'renew_order_event_id' => 'in:0,1',
|
||||||
@ -88,14 +92,11 @@ class ConfigSave extends FormRequest
|
|||||||
'frontend_theme' => '',
|
'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,green',
|
||||||
'frontend_background_url' => 'nullable|url',
|
'frontend_background_url' => 'nullable|url',
|
||||||
'frontend_admin_path' => '',
|
'frontend_admin_path' => '',
|
||||||
'frontend_customer_service_method' => '',
|
'frontend_customer_service_method' => '',
|
||||||
'frontend_customer_service_id' => '',
|
'frontend_customer_service_id' => '',
|
||||||
// tutorial
|
|
||||||
'apple_id' => 'nullable|email',
|
|
||||||
'apple_id_password' => '',
|
|
||||||
// email
|
// email
|
||||||
'email_template' => '',
|
'email_template' => '',
|
||||||
'email_host' => '',
|
'email_host' => '',
|
||||||
|
@ -21,6 +21,7 @@ class CouponGenerate extends FormRequest
|
|||||||
'started_at' => 'required|integer',
|
'started_at' => 'required|integer',
|
||||||
'ended_at' => 'required|integer',
|
'ended_at' => 'required|integer',
|
||||||
'limit_use' => 'nullable|integer',
|
'limit_use' => 'nullable|integer',
|
||||||
|
'limit_use_with_user' => 'nullable|integer',
|
||||||
'limit_plan_ids' => 'nullable|array',
|
'limit_plan_ids' => 'nullable|array',
|
||||||
'code' => ''
|
'code' => ''
|
||||||
];
|
];
|
||||||
@ -40,7 +41,8 @@ class CouponGenerate extends FormRequest
|
|||||||
'started_at.integer' => '开始时间格式有误',
|
'started_at.integer' => '开始时间格式有误',
|
||||||
'ended_at.required' => '结束时间不能为空',
|
'ended_at.required' => '结束时间不能为空',
|
||||||
'ended_at.integer' => '结束时间格式有误',
|
'ended_at.integer' => '结束时间格式有误',
|
||||||
'limit_use.integer' => '使用次数格式有误',
|
'limit_use.integer' => '最大使用次数格式有误',
|
||||||
|
'limit_use_with_user.integer' => '限制用户使用次数格式有误',
|
||||||
'limit_plan_ids.array' => '指定订阅格式有误'
|
'limit_plan_ids.array' => '指定订阅格式有误'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Admin;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class CouponSave extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'required',
|
|
||||||
'type' => 'required|in:1,2',
|
|
||||||
'value' => 'required|integer',
|
|
||||||
'started_at' => 'required|integer',
|
|
||||||
'ended_at' => 'required|integer',
|
|
||||||
'limit_use' => 'nullable|integer',
|
|
||||||
'limit_plan_ids' => 'nullable|array',
|
|
||||||
'code' => ''
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function messages()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name.required' => '名称不能为空',
|
|
||||||
'type.required' => '类型不能为空',
|
|
||||||
'type.in' => '类型格式有误',
|
|
||||||
'value.required' => '金额或比例不能为空',
|
|
||||||
'value.integer' => '金额或比例格式有误',
|
|
||||||
'started_at.required' => '开始时间不能为空',
|
|
||||||
'started_at.integer' => '开始时间格式有误',
|
|
||||||
'ended_at.required' => '结束时间不能为空',
|
|
||||||
'ended_at.integer' => '结束时间格式有误',
|
|
||||||
'limit_use.integer' => '使用次数格式有误',
|
|
||||||
'limit_plan_ids.array' => '指定订阅格式有误'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@ -25,7 +25,8 @@ class PlanSave extends FormRequest
|
|||||||
'two_year_price' => 'nullable|integer',
|
'two_year_price' => 'nullable|integer',
|
||||||
'three_year_price' => 'nullable|integer',
|
'three_year_price' => 'nullable|integer',
|
||||||
'onetime_price' => 'nullable|integer',
|
'onetime_price' => 'nullable|integer',
|
||||||
'reset_price' => 'nullable|integer'
|
'reset_price' => 'nullable|integer',
|
||||||
|
'reset_traffic_method' => 'nullable|integer|in:0,1,2'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +45,9 @@ class PlanSave extends FormRequest
|
|||||||
'two_year_price.integer' => '两年付金额格式有误',
|
'two_year_price.integer' => '两年付金额格式有误',
|
||||||
'three_year_price.integer' => '三年付金额格式有误',
|
'three_year_price.integer' => '三年付金额格式有误',
|
||||||
'onetime_price.integer' => '一次性金额有误',
|
'onetime_price.integer' => '一次性金额有误',
|
||||||
'reset_price.integer' => '流量重置包金额有误'
|
'reset_price.integer' => '流量重置包金额有误',
|
||||||
|
'reset_traffic_method.integer' => '流量重置方式格式有误',
|
||||||
|
'reset_traffic_method.in' => '流量重置方式格式有误'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@ class ServerV2raySave extends FormRequest
|
|||||||
'rate' => 'required|numeric',
|
'rate' => 'required|numeric',
|
||||||
'alter_id' => 'required|integer',
|
'alter_id' => 'required|integer',
|
||||||
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic,grpc',
|
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic,grpc',
|
||||||
'networkSettings' => '',
|
'networkSettings' => 'nullable|array',
|
||||||
'ruleSettings' => '',
|
'ruleSettings' => 'nullable|array',
|
||||||
'tlsSettings' => '',
|
'tlsSettings' => 'nullable|array',
|
||||||
'dnsSettings' => ''
|
'dnsSettings' => 'nullable|array'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,11 @@ class ServerV2raySave extends FormRequest
|
|||||||
'rate.required' => '倍率不能为空',
|
'rate.required' => '倍率不能为空',
|
||||||
'rate.numeric' => '倍率格式不正确',
|
'rate.numeric' => '倍率格式不正确',
|
||||||
'network.required' => '传输协议不能为空',
|
'network.required' => '传输协议不能为空',
|
||||||
'network.in' => '传输协议格式不正确'
|
'network.in' => '传输协议格式不正确',
|
||||||
|
'networkSettings.array' => '传输协议配置有误',
|
||||||
|
'ruleSettings.array' => '规则配置有误',
|
||||||
|
'tlsSettings.array' => 'tls配置有误',
|
||||||
|
'dnsSettings.array' => 'dns配置有误'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,10 @@ class AdminRoute
|
|||||||
});
|
});
|
||||||
// Order
|
// Order
|
||||||
$router->get ('/order/fetch', 'Admin\\OrderController@fetch');
|
$router->get ('/order/fetch', 'Admin\\OrderController@fetch');
|
||||||
$router->post('/order/repair', 'Admin\\OrderController@repair');
|
|
||||||
$router->post('/order/update', 'Admin\\OrderController@update');
|
$router->post('/order/update', 'Admin\\OrderController@update');
|
||||||
$router->post('/order/assign', 'Admin\\OrderController@assign');
|
$router->post('/order/assign', 'Admin\\OrderController@assign');
|
||||||
|
$router->post('/order/paid', 'Admin\\OrderController@paid');
|
||||||
|
$router->post('/order/cancel', 'Admin\\OrderController@cancel');
|
||||||
// User
|
// User
|
||||||
$router->get ('/user/fetch', 'Admin\\UserController@fetch');
|
$router->get ('/user/fetch', 'Admin\\UserController@fetch');
|
||||||
$router->post('/user/update', 'Admin\\UserController@update');
|
$router->post('/user/update', 'Admin\\UserController@update');
|
||||||
|
@ -20,6 +20,7 @@ class UserRoute
|
|||||||
$router->get ('/getSubscribe', 'User\\UserController@getSubscribe');
|
$router->get ('/getSubscribe', 'User\\UserController@getSubscribe');
|
||||||
$router->get ('/getStat', 'User\\UserController@getStat');
|
$router->get ('/getStat', 'User\\UserController@getStat');
|
||||||
$router->post('/transfer', 'User\\UserController@transfer');
|
$router->post('/transfer', 'User\\UserController@transfer');
|
||||||
|
$router->post('/getQuickLoginUrl', 'User\\UserController@getQuickLoginUrl');
|
||||||
// Order
|
// Order
|
||||||
$router->post('/order/save', 'User\\OrderController@save');
|
$router->post('/order/save', 'User\\OrderController@save');
|
||||||
$router->post('/order/checkout', 'User\\OrderController@checkout');
|
$router->post('/order/checkout', 'User\\OrderController@checkout');
|
||||||
|
52
app/Jobs/OrderHandleJob.php
Normal file
52
app/Jobs/OrderHandleJob.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\Order;
|
||||||
|
use App\Services\OrderService;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class OrderHandleJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
protected $order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($tradeNo)
|
||||||
|
{
|
||||||
|
$this->onQueue('order_handle');
|
||||||
|
$this->order = Order::where('trade_no', $tradeNo)
|
||||||
|
->lockForUpdate()
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
if (!$this->order) return;
|
||||||
|
$orderService = new OrderService($this->order);
|
||||||
|
switch ($this->order->status) {
|
||||||
|
// cancel
|
||||||
|
case 0:
|
||||||
|
if ($this->order->created_at <= (time() - 1800)) {
|
||||||
|
$orderService->cancel();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$orderService->open();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
app/Jobs/ServerLogJob.php
Normal file
58
app/Jobs/ServerLogJob.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Services\ServerService;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class ServerLogJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
protected $u;
|
||||||
|
protected $d;
|
||||||
|
protected $userId;
|
||||||
|
protected $server;
|
||||||
|
protected $protocol;
|
||||||
|
|
||||||
|
public $tries = 3;
|
||||||
|
public $timeout = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($u, $d, $userId, $server, $protocol)
|
||||||
|
{
|
||||||
|
$this->onQueue('server_log');
|
||||||
|
$this->u = $u;
|
||||||
|
$this->d = $d;
|
||||||
|
$this->userId = $userId;
|
||||||
|
$this->server = $server;
|
||||||
|
$this->protocol = $protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$serverService = new ServerService();
|
||||||
|
if (!$serverService->log(
|
||||||
|
$this->userId,
|
||||||
|
$this->server->id,
|
||||||
|
$this->u,
|
||||||
|
$this->d,
|
||||||
|
$this->server->rate,
|
||||||
|
$this->protocol
|
||||||
|
)) {
|
||||||
|
throw new \Exception('日志记录失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
app/Jobs/TrafficFetchJob.php
Normal file
57
app/Jobs/TrafficFetchJob.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\MailService;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class TrafficFetchJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
protected $u;
|
||||||
|
protected $d;
|
||||||
|
protected $userId;
|
||||||
|
protected $server;
|
||||||
|
protected $protocol;
|
||||||
|
|
||||||
|
public $tries = 3;
|
||||||
|
public $timeout = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($u, $d, $userId, $server, $protocol)
|
||||||
|
{
|
||||||
|
$this->onQueue('traffic_fetch');
|
||||||
|
$this->u = $u;
|
||||||
|
$this->d = $d;
|
||||||
|
$this->userId = $userId;
|
||||||
|
$this->server = $server;
|
||||||
|
$this->protocol = $protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$user = User::lockForUpdate()->find($this->userId);
|
||||||
|
if (!$user) return;
|
||||||
|
|
||||||
|
$user->t = time();
|
||||||
|
$user->u = $user->u + $this->u;
|
||||||
|
$user->d = $user->d + $this->d;
|
||||||
|
if (!$user->save()) throw new \Exception('流量更新失败');
|
||||||
|
$mailService = new MailService();
|
||||||
|
$mailService->remindTraffic($user);
|
||||||
|
}
|
||||||
|
}
|
16
app/Models/CommissionLog.php
Normal file
16
app/Models/CommissionLog.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class CommissionLog extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'v2_commission_log';
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
|
}
|
@ -9,4 +9,9 @@ class Coupon extends Model
|
|||||||
protected $table = 'v2_coupon';
|
protected $table = 'v2_coupon';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp',
|
||||||
|
'limit_plan_ids' => 'array'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -8,4 +8,8 @@ class InviteCode extends Model
|
|||||||
{
|
{
|
||||||
protected $table = 'v2_invite_code';
|
protected $table = 'v2_invite_code';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class Knowledge extends Model
|
|||||||
protected $table = 'v2_knowledge';
|
protected $table = 'v2_knowledge';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class MailLog extends Model
|
|||||||
protected $table = 'v2_mail_log';
|
protected $table = 'v2_mail_log';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class Notice extends Model
|
|||||||
protected $table = 'v2_notice';
|
protected $table = 'v2_notice';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,9 @@ class Order extends Model
|
|||||||
protected $table = 'v2_order';
|
protected $table = 'v2_order';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp',
|
||||||
|
'surplus_order_ids' => 'array'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,9 @@ class Payment extends Model
|
|||||||
protected $table = 'v2_payment';
|
protected $table = 'v2_payment';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp',
|
||||||
|
'config' => 'array'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class Plan extends Model
|
|||||||
protected $table = 'v2_plan';
|
protected $table = 'v2_plan';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Server extends Model
|
|
||||||
{
|
|
||||||
protected $table = 'v2_server';
|
|
||||||
protected $dateFormat = 'U';
|
|
||||||
protected $guarded = ['id'];
|
|
||||||
}
|
|
@ -8,4 +8,8 @@ class ServerGroup extends Model
|
|||||||
{
|
{
|
||||||
protected $table = 'v2_server_group';
|
protected $table = 'v2_server_group';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class ServerLog extends Model
|
|||||||
{
|
{
|
||||||
protected $table = 'v2_server_log';
|
protected $table = 'v2_server_log';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,10 @@ class ServerShadowsocks extends Model
|
|||||||
protected $table = 'v2_server_shadowsocks';
|
protected $table = 'v2_server_shadowsocks';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp',
|
||||||
|
'group_id' => 'array',
|
||||||
|
'tags' => 'array'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class ServerStat extends Model
|
|||||||
protected $table = 'v2_server_stat';
|
protected $table = 'v2_server_stat';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,10 @@ class ServerTrojan extends Model
|
|||||||
protected $table = 'v2_server_trojan';
|
protected $table = 'v2_server_trojan';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp',
|
||||||
|
'group_id' => 'array',
|
||||||
|
'tags' => 'array'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
22
app/Models/ServerV2ray.php
Executable file
22
app/Models/ServerV2ray.php
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ServerV2ray extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'v2_server_v2ray';
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp',
|
||||||
|
'group_id' => 'array',
|
||||||
|
'tlsSettings' => 'array',
|
||||||
|
'networkSettings' => 'array',
|
||||||
|
'dnsSettings' => 'array',
|
||||||
|
'ruleSettings' => 'array',
|
||||||
|
'tags' => 'array'
|
||||||
|
];
|
||||||
|
}
|
@ -9,4 +9,8 @@ class StatOrder extends Model
|
|||||||
protected $table = 'v2_stat_order';
|
protected $table = 'v2_stat_order';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class StatServer extends Model
|
|||||||
protected $table = 'v2_stat_server';
|
protected $table = 'v2_stat_server';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class Ticket extends Model
|
|||||||
protected $table = 'v2_ticket';
|
protected $table = 'v2_ticket';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class TicketMessage extends Model
|
|||||||
protected $table = 'v2_ticket_message';
|
protected $table = 'v2_ticket_message';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,8 @@ class User extends Model
|
|||||||
protected $table = 'v2_user';
|
protected $table = 'v2_user';
|
||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
protected $casts = [
|
||||||
|
'created_at' => 'timestamp',
|
||||||
|
'updated_at' => 'timestamp'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ namespace App\Payments;
|
|||||||
use \Curl\Curl;
|
use \Curl\Curl;
|
||||||
|
|
||||||
class MGate {
|
class MGate {
|
||||||
|
private $config;
|
||||||
|
|
||||||
public function __construct($config)
|
public function __construct($config)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
@ -47,6 +49,7 @@ class MGate {
|
|||||||
$str = http_build_query($params) . $this->config['mgate_app_secret'];
|
$str = http_build_query($params) . $this->config['mgate_app_secret'];
|
||||||
$params['sign'] = md5($str);
|
$params['sign'] = md5($str);
|
||||||
$curl = new Curl();
|
$curl = new Curl();
|
||||||
|
$curl->setUserAgent('MGate');
|
||||||
$curl->post($this->config['mgate_url'] . '/v1/gateway/fetch', http_build_query($params));
|
$curl->post($this->config['mgate_url'] . '/v1/gateway/fetch', http_build_query($params));
|
||||||
$result = $curl->response;
|
$result = $curl->response;
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
|
43
app/Providers/HorizonServiceProvider.php
Normal file
43
app/Providers/HorizonServiceProvider.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
use Laravel\Horizon\Horizon;
|
||||||
|
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
||||||
|
|
||||||
|
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
// Horizon::routeSmsNotificationsTo('15556667777');
|
||||||
|
// Horizon::routeMailNotificationsTo('example@example.com');
|
||||||
|
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
|
||||||
|
|
||||||
|
// Horizon::night();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the Horizon gate.
|
||||||
|
*
|
||||||
|
* This gate determines who can access Horizon in non-local environments.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function gate()
|
||||||
|
{
|
||||||
|
Gate::define('viewHorizon', function ($user) {
|
||||||
|
return in_array($user->email, [
|
||||||
|
//
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -8,27 +8,20 @@ use Illuminate\Support\Facades\DB;
|
|||||||
|
|
||||||
class CouponService
|
class CouponService
|
||||||
{
|
{
|
||||||
public $order;
|
public $coupon;
|
||||||
|
public $planId;
|
||||||
|
public $userId;
|
||||||
|
|
||||||
public function __construct($code)
|
public function __construct($code)
|
||||||
{
|
{
|
||||||
$this->coupon = Coupon::where('code', $code)->first();
|
$this->coupon = Coupon::where('code', $code)->first();
|
||||||
if (!$this->coupon) {
|
|
||||||
abort(500, '优惠券无效');
|
|
||||||
}
|
|
||||||
if ($this->coupon->limit_use <= 0 && $this->coupon->limit_use !== NULL) {
|
|
||||||
abort(500, '优惠券已无可用次数');
|
|
||||||
}
|
|
||||||
if (time() < $this->coupon->started_at) {
|
|
||||||
abort(500, '优惠券还未到可用时间');
|
|
||||||
}
|
|
||||||
if (time() > $this->coupon->ended_at) {
|
|
||||||
abort(500, '优惠券已过期');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function use(Order $order)
|
public function use(Order $order):bool
|
||||||
{
|
{
|
||||||
|
$this->setPlanId($order->plan_id);
|
||||||
|
$this->setUserId($order->user_id);
|
||||||
|
$this->check();
|
||||||
switch ($this->coupon->type) {
|
switch ($this->coupon->type) {
|
||||||
case 1:
|
case 1:
|
||||||
$order->discount_amount = $this->coupon->value;
|
$order->discount_amount = $this->coupon->value;
|
||||||
@ -43,12 +36,6 @@ class CouponService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->coupon->limit_plan_ids) {
|
|
||||||
$limitPlanIds = json_decode($this->coupon->limit_plan_ids);
|
|
||||||
if (!in_array($order->plan_id, $limitPlanIds)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,4 +43,57 @@ class CouponService
|
|||||||
{
|
{
|
||||||
return $this->coupon->id;
|
return $this->coupon->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCoupon()
|
||||||
|
{
|
||||||
|
return $this->coupon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPlanId($planId)
|
||||||
|
{
|
||||||
|
$this->planId = $planId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUserId($userId)
|
||||||
|
{
|
||||||
|
$this->userId = $userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkLimitUseWithUser():bool
|
||||||
|
{
|
||||||
|
$usedCount = Order::where('coupon_id', $this->coupon->id)
|
||||||
|
->where('user_id', $this->userId)
|
||||||
|
->whereNotIn('status', [0, 2])
|
||||||
|
->count();
|
||||||
|
if ($usedCount >= $this->coupon->limit_use_with_user) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function check()
|
||||||
|
{
|
||||||
|
if (!$this->coupon) {
|
||||||
|
abort(500, __('Invalid coupon'));
|
||||||
|
}
|
||||||
|
if ($this->coupon->limit_use <= 0 && $this->coupon->limit_use !== NULL) {
|
||||||
|
abort(500, __('This coupon is no longer available'));
|
||||||
|
}
|
||||||
|
if (time() < $this->coupon->started_at) {
|
||||||
|
abort(500, __('This coupon has not yet started'));
|
||||||
|
}
|
||||||
|
if (time() > $this->coupon->ended_at) {
|
||||||
|
abort(500, __('This coupon has expired'));
|
||||||
|
}
|
||||||
|
if ($this->coupon->limit_plan_ids && $this->planId) {
|
||||||
|
if (!in_array($this->planId, $this->coupon->limit_plan_ids)) {
|
||||||
|
abort(500, __('The coupon code cannot be used for this subscription'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->coupon->limit_use_with_user !== NULL && $this->userId) {
|
||||||
|
if (!$this->checkLimitUseWithUser()) {
|
||||||
|
abort(500, __('The coupon can only be used :limit_use_with_user per person', [
|
||||||
|
'limit_use_with_user' => $this->coupon->limit_use_with_user
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,15 @@ class MailService
|
|||||||
public function remindTraffic (User $user)
|
public function remindTraffic (User $user)
|
||||||
{
|
{
|
||||||
if (!$user->remind_traffic) return;
|
if (!$user->remind_traffic) return;
|
||||||
if (!$this->remindTrafficIsWarnValue(($user->u + $user->d), $user->transfer_enable)) return;
|
if (!$this->remindTrafficIsWarnValue($user->u, $user->d, $user->transfer_enable)) return;
|
||||||
$flag = CacheKey::get('LAST_SEND_EMAIL_REMIND_TRAFFIC', $user->id);
|
$flag = CacheKey::get('LAST_SEND_EMAIL_REMIND_TRAFFIC', $user->id);
|
||||||
if (Cache::get($flag)) return;
|
if (Cache::get($flag)) return;
|
||||||
if (!Cache::put($flag, 1, 24 * 3600)) return;
|
if (!Cache::put($flag, 1, 24 * 3600)) return;
|
||||||
SendEmailJob::dispatch([
|
SendEmailJob::dispatch([
|
||||||
'email' => $user->email,
|
'email' => $user->email,
|
||||||
'subject' => '在' . config('v2board.app_name', 'V2board') . '的流量使用已达到80%',
|
'subject' => __('The traffic usage in :app_name has reached 80%', [
|
||||||
|
'app_name' => config('v2board.app_name', 'V2board')
|
||||||
|
]),
|
||||||
'template_name' => 'remindTraffic',
|
'template_name' => 'remindTraffic',
|
||||||
'template_value' => [
|
'template_value' => [
|
||||||
'name' => config('v2board.app_name', 'V2Board'),
|
'name' => config('v2board.app_name', 'V2Board'),
|
||||||
@ -27,8 +29,25 @@ class MailService
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function remindTrafficIsWarnValue($ud, $transfer_enable)
|
public function remindExpire(User $user)
|
||||||
{
|
{
|
||||||
|
if (!($user->expired_at !== NULL && ($user->expired_at - 86400) < time() && $user->expired_at > time())) return;
|
||||||
|
SendEmailJob::dispatch([
|
||||||
|
'email' => $user->email,
|
||||||
|
'subject' => __('The service in :app_name is about to expire', [
|
||||||
|
'app_name' => config('v2board.app_name', 'V2board')
|
||||||
|
]),
|
||||||
|
'template_name' => 'remindExpire',
|
||||||
|
'template_value' => [
|
||||||
|
'name' => config('v2board.app_name', 'V2Board'),
|
||||||
|
'url' => config('v2board.app_url')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function remindTrafficIsWarnValue($u, $d, $transfer_enable)
|
||||||
|
{
|
||||||
|
$ud = $u + $d;
|
||||||
if (!$ud) return false;
|
if (!$ud) return false;
|
||||||
if (!$transfer_enable) return false;
|
if (!$transfer_enable) return false;
|
||||||
$percentage = ($ud / $transfer_enable) * 100;
|
$percentage = ($ud / $transfer_enable) * 100;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Jobs\OrderHandleJob;
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
use App\Models\Plan;
|
use App\Models\Plan;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@ -37,7 +38,7 @@ class OrderService
|
|||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
if ($order->surplus_order_ids) {
|
if ($order->surplus_order_ids) {
|
||||||
try {
|
try {
|
||||||
Order::whereIn('id', json_decode($order->surplus_order_ids))->update([
|
Order::whereIn('id', $order->surplus_order_ids)->update([
|
||||||
'status' => 4
|
'status' => 4
|
||||||
]);
|
]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@ -81,25 +82,6 @@ class OrderService
|
|||||||
DB::commit();
|
DB::commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function cancel():bool
|
|
||||||
{
|
|
||||||
$order = $this->order;
|
|
||||||
DB::beginTransaction();
|
|
||||||
$order->status = 2;
|
|
||||||
if (!$order->save()) {
|
|
||||||
DB::rollBack();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($order->balance_amount) {
|
|
||||||
$userService = new UserService();
|
|
||||||
if (!$userService->addBalance($order->user_id, $order->balance_amount)) {
|
|
||||||
DB::rollBack();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DB::commit();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setOrderType(User $user)
|
public function setOrderType(User $user)
|
||||||
{
|
{
|
||||||
@ -190,13 +172,13 @@ class OrderService
|
|||||||
$result = $trafficUnitPrice * $notUsedTraffic;
|
$result = $trafficUnitPrice * $notUsedTraffic;
|
||||||
$orderModel = Order::where('user_id', $user->id)->where('cycle', '!=', 'reset_price')->where('status', 3);
|
$orderModel = Order::where('user_id', $user->id)->where('cycle', '!=', 'reset_price')->where('status', 3);
|
||||||
$order->surplus_amount = $result > 0 ? $result : 0;
|
$order->surplus_amount = $result > 0 ? $result : 0;
|
||||||
$order->surplus_order_ids = json_encode(array_column($orderModel->get()->toArray(), 'id'));
|
$order->surplus_order_ids = array_column($orderModel->get()->toArray(), 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function orderIsUsed(Order $order):bool
|
private function orderIsUsed(Order $order):bool
|
||||||
{
|
{
|
||||||
$month = self::STR_TO_TIME[$order->cycle];
|
$month = self::STR_TO_TIME[$order->cycle];
|
||||||
$orderExpireDay = strtotime('+' . $month . ' month', $order->created_at->timestamp);
|
$orderExpireDay = strtotime('+' . $month . ' month', $order->created_at);
|
||||||
if ($orderExpireDay < time()) return true;
|
if ($orderExpireDay < time()) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -229,20 +211,40 @@ class OrderService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$order->surplus_amount = $orderSurplusAmount > 0 ? $orderSurplusAmount : 0;
|
$order->surplus_amount = $orderSurplusAmount > 0 ? $orderSurplusAmount : 0;
|
||||||
$order->surplus_order_ids = json_encode(array_column($orders->toArray(), 'id'));
|
$order->surplus_order_ids = array_column($orders->toArray(), 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function success(string $callbackNo)
|
public function paid(string $callbackNo)
|
||||||
{
|
{
|
||||||
$order = $this->order;
|
$order = $this->order;
|
||||||
if ($order->status !== 0) {
|
if ($order->status !== 0) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$order->status = 1;
|
$order->status = 1;
|
||||||
|
$order->paid_at = time();
|
||||||
$order->callback_no = $callbackNo;
|
$order->callback_no = $callbackNo;
|
||||||
return $order->save();
|
if (!$order->save()) return false;
|
||||||
|
OrderHandleJob::dispatch($order->trade_no);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function cancel():bool
|
||||||
|
{
|
||||||
|
$order = $this->order;
|
||||||
|
DB::beginTransaction();
|
||||||
|
$order->status = 2;
|
||||||
|
if (!$order->save()) {
|
||||||
|
DB::rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($order->balance_amount) {
|
||||||
|
$userService = new UserService();
|
||||||
|
if (!$userService->addBalance($order->user_id, $order->balance_amount)) {
|
||||||
|
DB::rollBack();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DB::commit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private function buyByResetTraffic()
|
private function buyByResetTraffic()
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ class PaymentService
|
|||||||
if ($uuid) $payment = Payment::where('uuid', $uuid)->first()->toArray();
|
if ($uuid) $payment = Payment::where('uuid', $uuid)->first()->toArray();
|
||||||
$this->config = [];
|
$this->config = [];
|
||||||
if (isset($payment)) {
|
if (isset($payment)) {
|
||||||
$this->config = json_decode($payment['config'], true);
|
$this->config = $payment['config'];
|
||||||
$this->config['enable'] = $payment['enable'];
|
$this->config['enable'] = $payment['enable'];
|
||||||
$this->config['id'] = $payment['id'];
|
$this->config['id'] = $payment['id'];
|
||||||
$this->config['uuid'] = $payment['uuid'];
|
$this->config['uuid'] = $payment['uuid'];
|
||||||
|
@ -5,7 +5,7 @@ namespace App\Services;
|
|||||||
use App\Models\ServerLog;
|
use App\Models\ServerLog;
|
||||||
use App\Models\ServerShadowsocks;
|
use App\Models\ServerShadowsocks;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\ServerTrojan;
|
use App\Models\ServerTrojan;
|
||||||
use App\Utils\CacheKey;
|
use App\Utils\CacheKey;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
@ -18,14 +18,14 @@ class ServerService
|
|||||||
public function getV2ray(User $user, $all = false):array
|
public function getV2ray(User $user, $all = false):array
|
||||||
{
|
{
|
||||||
$servers = [];
|
$servers = [];
|
||||||
$model = Server::orderBy('sort', 'ASC');
|
$model = ServerV2ray::orderBy('sort', 'ASC');
|
||||||
if (!$all) {
|
if (!$all) {
|
||||||
$model->where('show', 1);
|
$model->where('show', 1);
|
||||||
}
|
}
|
||||||
$v2ray = $model->get();
|
$v2ray = $model->get();
|
||||||
for ($i = 0; $i < count($v2ray); $i++) {
|
for ($i = 0; $i < count($v2ray); $i++) {
|
||||||
$v2ray[$i]['type'] = 'v2ray';
|
$v2ray[$i]['type'] = 'v2ray';
|
||||||
$groupId = json_decode($v2ray[$i]['group_id']);
|
$groupId = $v2ray[$i]['group_id'];
|
||||||
if (in_array($user->group_id, $groupId)) {
|
if (in_array($user->group_id, $groupId)) {
|
||||||
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']));
|
||||||
@ -50,7 +50,7 @@ class ServerService
|
|||||||
$trojan = $model->get();
|
$trojan = $model->get();
|
||||||
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 = $trojan[$i]['group_id'];
|
||||||
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']));
|
||||||
@ -73,7 +73,7 @@ class ServerService
|
|||||||
$shadowsocks = $model->get();
|
$shadowsocks = $model->get();
|
||||||
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 = $shadowsocks[$i]['group_id'];
|
||||||
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']));
|
||||||
@ -123,7 +123,7 @@ class ServerService
|
|||||||
|
|
||||||
public function getV2RayConfig(int $nodeId, int $localPort)
|
public function getV2RayConfig(int $nodeId, int $localPort)
|
||||||
{
|
{
|
||||||
$server = Server::find($nodeId);
|
$server = ServerV2ray::find($nodeId);
|
||||||
if (!$server) {
|
if (!$server) {
|
||||||
abort(500, '节点不存在');
|
abort(500, '节点不存在');
|
||||||
}
|
}
|
||||||
@ -156,10 +156,10 @@ class ServerService
|
|||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setDns(Server $server, object $json)
|
private function setDns(ServerV2ray $server, object $json)
|
||||||
{
|
{
|
||||||
if ($server->dnsSettings) {
|
if ($server->dnsSettings) {
|
||||||
$dns = json_decode($server->dnsSettings);
|
$dns = $server->dnsSettings;
|
||||||
if (isset($dns->servers)) {
|
if (isset($dns->servers)) {
|
||||||
array_push($dns->servers, '1.1.1.1');
|
array_push($dns->servers, '1.1.1.1');
|
||||||
array_push($dns->servers, 'localhost');
|
array_push($dns->servers, 'localhost');
|
||||||
@ -169,41 +169,41 @@ class ServerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setNetwork(Server $server, object $json)
|
private function setNetwork(ServerV2ray $server, object $json)
|
||||||
{
|
{
|
||||||
if ($server->networkSettings) {
|
if ($server->networkSettings) {
|
||||||
switch ($server->network) {
|
switch ($server->network) {
|
||||||
case 'tcp':
|
case 'tcp':
|
||||||
$json->inbound->streamSettings->tcpSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->tcpSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
case 'kcp':
|
case 'kcp':
|
||||||
$json->inbound->streamSettings->kcpSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->kcpSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
case 'ws':
|
case 'ws':
|
||||||
$json->inbound->streamSettings->wsSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->wsSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
case 'http':
|
case 'http':
|
||||||
$json->inbound->streamSettings->httpSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->httpSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
case 'domainsocket':
|
case 'domainsocket':
|
||||||
$json->inbound->streamSettings->dsSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->dsSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
case 'quic':
|
case 'quic':
|
||||||
$json->inbound->streamSettings->quicSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->quicSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
case 'grpc':
|
case 'grpc':
|
||||||
$json->inbound->streamSettings->grpcSettings = json_decode($server->networkSettings);
|
$json->inbound->streamSettings->grpcSettings = $server->networkSettings;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setRule(Server $server, object $json)
|
private function setRule(ServerV2ray $server, object $json)
|
||||||
{
|
{
|
||||||
$domainRules = array_filter(explode(PHP_EOL, config('v2board.server_v2ray_domain')));
|
$domainRules = array_filter(explode(PHP_EOL, config('v2board.server_v2ray_domain')));
|
||||||
$protocolRules = array_filter(explode(PHP_EOL, config('v2board.server_v2ray_protocol')));
|
$protocolRules = array_filter(explode(PHP_EOL, config('v2board.server_v2ray_protocol')));
|
||||||
if ($server->ruleSettings) {
|
if ($server->ruleSettings) {
|
||||||
$ruleSettings = json_decode($server->ruleSettings);
|
$ruleSettings = $server->ruleSettings;
|
||||||
// domain
|
// domain
|
||||||
if (isset($ruleSettings->domain)) {
|
if (isset($ruleSettings->domain)) {
|
||||||
$ruleSettings->domain = array_filter($ruleSettings->domain);
|
$ruleSettings->domain = array_filter($ruleSettings->domain);
|
||||||
@ -238,10 +238,10 @@ class ServerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setTls(Server $server, object $json)
|
private function setTls(ServerV2ray $server, object $json)
|
||||||
{
|
{
|
||||||
if ((int)$server->tls) {
|
if ((int)$server->tls) {
|
||||||
$tlsSettings = json_decode($server->tlsSettings);
|
$tlsSettings = $server->tlsSettings;
|
||||||
$json->inbound->streamSettings->security = 'tls';
|
$json->inbound->streamSettings->security = 'tls';
|
||||||
$tls = (object)[
|
$tls = (object)[
|
||||||
'certificateFile' => '/root/.cert/server.crt',
|
'certificateFile' => '/root/.cert/server.crt',
|
||||||
@ -260,20 +260,23 @@ class ServerService
|
|||||||
|
|
||||||
public function log(int $userId, int $serverId, int $u, int $d, float $rate, string $method)
|
public function log(int $userId, int $serverId, int $u, int $d, float $rate, string $method)
|
||||||
{
|
{
|
||||||
if (($u + $d) <= 10240) return;
|
if (($u + $d) < 10240) return true;
|
||||||
$timestamp = strtotime(date('Y-m-d H:0'));
|
$timestamp = strtotime(date('Y-m-d'));
|
||||||
$serverLog = ServerLog::where('log_at', '>=', $timestamp)
|
$serverLog = ServerLog::where('log_at', '>=', $timestamp)
|
||||||
->where('log_at', '<', $timestamp + 3600)
|
->where('log_at', '<', $timestamp + 3600)
|
||||||
->where('server_id', $serverId)
|
->where('server_id', $serverId)
|
||||||
->where('user_id', $userId)
|
->where('user_id', $userId)
|
||||||
->where('rate', $rate)
|
->where('rate', $rate)
|
||||||
->where('method', $method)
|
->where('method', $method)
|
||||||
->lockForUpdate()
|
|
||||||
->first();
|
->first();
|
||||||
if ($serverLog) {
|
if ($serverLog) {
|
||||||
$serverLog->u = $serverLog->u + $u;
|
try {
|
||||||
$serverLog->d = $serverLog->d + $d;
|
$serverLog->increment('u', $u);
|
||||||
$serverLog->save();
|
$serverLog->increment('d', $d);
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$serverLog = new ServerLog();
|
$serverLog = new ServerLog();
|
||||||
$serverLog->user_id = $userId;
|
$serverLog->user_id = $userId;
|
||||||
@ -283,7 +286,7 @@ class ServerService
|
|||||||
$serverLog->rate = $rate;
|
$serverLog->rate = $rate;
|
||||||
$serverLog->log_at = $timestamp;
|
$serverLog->log_at = $timestamp;
|
||||||
$serverLog->method = $method;
|
$serverLog->method = $method;
|
||||||
$serverLog->save();
|
return $serverLog->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,32 +295,15 @@ class ServerService
|
|||||||
$server = ServerShadowsocks::orderBy('sort', 'ASC')->get();
|
$server = ServerShadowsocks::orderBy('sort', 'ASC')->get();
|
||||||
for ($i = 0; $i < count($server); $i++) {
|
for ($i = 0; $i < count($server); $i++) {
|
||||||
$server[$i]['type'] = 'shadowsocks';
|
$server[$i]['type'] = 'shadowsocks';
|
||||||
if (!empty($server[$i]['tags'])) {
|
|
||||||
$server[$i]['tags'] = json_decode($server[$i]['tags']);
|
|
||||||
}
|
|
||||||
$server[$i]['group_id'] = json_decode($server[$i]['group_id']);
|
|
||||||
}
|
}
|
||||||
return $server->toArray();
|
return $server->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getV2rayServers()
|
public function getV2rayServers()
|
||||||
{
|
{
|
||||||
$server = Server::orderBy('sort', 'ASC')->get();
|
$server = ServerV2ray::orderBy('sort', 'ASC')->get();
|
||||||
for ($i = 0; $i < count($server); $i++) {
|
for ($i = 0; $i < count($server); $i++) {
|
||||||
$server[$i]['type'] = 'v2ray';
|
$server[$i]['type'] = 'v2ray';
|
||||||
if (!empty($server[$i]['tags'])) {
|
|
||||||
$server[$i]['tags'] = json_decode($server[$i]['tags']);
|
|
||||||
}
|
|
||||||
if (!empty($server[$i]['dnsSettings'])) {
|
|
||||||
$server[$i]['dnsSettings'] = json_decode($server[$i]['dnsSettings']);
|
|
||||||
}
|
|
||||||
if (!empty($server[$i]['tlsSettings'])) {
|
|
||||||
$server[$i]['tlsSettings'] = json_decode($server[$i]['tlsSettings']);
|
|
||||||
}
|
|
||||||
if (!empty($server[$i]['ruleSettings'])) {
|
|
||||||
$server[$i]['ruleSettings'] = json_decode($server[$i]['ruleSettings']);
|
|
||||||
}
|
|
||||||
$server[$i]['group_id'] = json_decode($server[$i]['group_id']);
|
|
||||||
}
|
}
|
||||||
return $server->toArray();
|
return $server->toArray();
|
||||||
}
|
}
|
||||||
@ -327,10 +313,6 @@ class ServerService
|
|||||||
$server = ServerTrojan::orderBy('sort', 'ASC')->get();
|
$server = ServerTrojan::orderBy('sort', 'ASC')->get();
|
||||||
for ($i = 0; $i < count($server); $i++) {
|
for ($i = 0; $i < count($server); $i++) {
|
||||||
$server[$i]['type'] = 'trojan';
|
$server[$i]['type'] = 'trojan';
|
||||||
if (!empty($server[$i]['tags'])) {
|
|
||||||
$server[$i]['tags'] = json_decode($server[$i]['tags']);
|
|
||||||
}
|
|
||||||
$server[$i]['group_id'] = json_decode($server[$i]['group_id']);
|
|
||||||
}
|
}
|
||||||
return $server->toArray();
|
return $server->toArray();
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ class TelegramService {
|
|||||||
$curl->get($this->api . $method . '?' . http_build_query($params));
|
$curl->get($this->api . $method . '?' . http_build_query($params));
|
||||||
$response = $curl->response;
|
$response = $curl->response;
|
||||||
$curl->close();
|
$curl->close();
|
||||||
|
if (!isset($response->ok)) abort(500, '请求失败');
|
||||||
if (!$response->ok) {
|
if (!$response->ok) {
|
||||||
abort(500, '来自TG的错误:' . $response->description);
|
abort(500, '来自TG的错误:' . $response->description);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ use Illuminate\Support\Facades\DB;
|
|||||||
class TicketService {
|
class TicketService {
|
||||||
public function replyByAdmin($ticketId, $message, $userId):void
|
public function replyByAdmin($ticketId, $message, $userId):void
|
||||||
{
|
{
|
||||||
|
if ($message)
|
||||||
$ticket = Ticket::where('id', $ticketId)
|
$ticket = Ticket::where('id', $ticketId)
|
||||||
->first();
|
->first();
|
||||||
if (!$ticket) {
|
if (!$ticket) {
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Jobs\ServerLogJob;
|
||||||
|
use App\Jobs\TrafficFetchJob;
|
||||||
use App\Models\InviteCode;
|
use App\Models\InviteCode;
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\Ticket;
|
use App\Models\Ticket;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
@ -80,33 +82,9 @@ class UserService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function trafficFetch(int $u, int $d, int $userId, object $server, string $protocol):bool
|
public function trafficFetch(int $u, int $d, int $userId, object $server, string $protocol)
|
||||||
{
|
{
|
||||||
$user = User::lockForUpdate()
|
TrafficFetchJob::dispatch($u, $d, $userId, $server, $protocol);
|
||||||
->find($userId);
|
ServerLogJob::dispatch($u, $d, $userId, $server, $protocol);
|
||||||
if (!$user) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$user->t = time();
|
|
||||||
$user->u = $user->u + $u;
|
|
||||||
$user->d = $user->d + $d;
|
|
||||||
if (!$user->save()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$mailService = new MailService();
|
|
||||||
$serverService = new ServerService();
|
|
||||||
try {
|
|
||||||
$mailService->remindTraffic($user);
|
|
||||||
$serverService->log(
|
|
||||||
$userId,
|
|
||||||
$server->id,
|
|
||||||
$u,
|
|
||||||
$d,
|
|
||||||
$server->rate,
|
|
||||||
$protocol
|
|
||||||
);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class CacheKey
|
|||||||
'SERVER_SHADOWSOCKS_LAST_CHECK_AT' => 'ss节点最后检查时间',
|
'SERVER_SHADOWSOCKS_LAST_CHECK_AT' => 'ss节点最后检查时间',
|
||||||
'SERVER_SHADOWSOCKS_LAST_PUSH_AT' => 'ss节点最后推送时间',
|
'SERVER_SHADOWSOCKS_LAST_PUSH_AT' => 'ss节点最后推送时间',
|
||||||
'TEMP_TOKEN' => '临时令牌',
|
'TEMP_TOKEN' => '临时令牌',
|
||||||
'LAST_SEND_EMAIL_REMIND_TRAFFIC'
|
'LAST_SEND_EMAIL_REMIND_TRAFFIC' => '最后发送流量邮件提醒'
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function get(string $key, $uniqueValue)
|
public static function get(string $key, $uniqueValue)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Utils;
|
namespace App\Utils;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\ServerV2ray;
|
||||||
use App\Models\ServerShadowsocks;
|
use App\Models\ServerShadowsocks;
|
||||||
use App\Models\ServerTrojan;
|
use App\Models\ServerTrojan;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@ -23,6 +23,12 @@ class Helper
|
|||||||
return md5(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)) . '-' . time());
|
return md5(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)) . '-' . time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function generateOrderNo(): string
|
||||||
|
{
|
||||||
|
$randomChar = rand(10000, 99999);
|
||||||
|
return date('YmdHms') . $randomChar;
|
||||||
|
}
|
||||||
|
|
||||||
public static function exchange($from, $to)
|
public static function exchange($from, $to)
|
||||||
{
|
{
|
||||||
$result = file_get_contents('https://api.exchangerate.host/latest?symbols=' . $to . '&base=' . $from);
|
$result = file_get_contents('https://api.exchangerate.host/latest?symbols=' . $to . '&base=' . $from);
|
||||||
@ -58,11 +64,12 @@ class Helper
|
|||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function multiPasswordVerify($algo, $password, $hash)
|
public static function multiPasswordVerify($algo, $salt, $password, $hash)
|
||||||
{
|
{
|
||||||
switch($algo) {
|
switch($algo) {
|
||||||
case 'md5': return md5($password) === $hash;
|
case 'md5': return md5($password) === $hash;
|
||||||
case 'sha256': return hash('sha256', $password) === $hash;
|
case 'sha256': return hash('sha256', $password) === $hash;
|
||||||
|
case 'md5salt': return md5($password . $salt) === $hash;
|
||||||
default: return password_verify($password, $hash);
|
default: return password_verify($password, $hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,4 +102,14 @@ class Helper
|
|||||||
return round($byte, 2) . ' B';
|
return round($byte, 2) . ' B';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getSubscribeHost()
|
||||||
|
{
|
||||||
|
$subscribeUrl = config('v2board.app_url');
|
||||||
|
$subscribeUrls = explode(',', config('v2board.subscribe_url'));
|
||||||
|
if ($subscribeUrls && $subscribeUrls[0]) {
|
||||||
|
$subscribeUrl = $subscribeUrls[rand(0, count($subscribeUrls) - 1)];
|
||||||
|
}
|
||||||
|
return $subscribeUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,37 @@
|
|||||||
{
|
{
|
||||||
"name": "v2board/v2board",
|
"name": "v2board/v2board",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"description": "v2board is a v2ray manage.",
|
"description": "v2board is a proxy protocol manage.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"v2board",
|
"v2board",
|
||||||
"v2ray",
|
"v2ray",
|
||||||
|
"shadowsocks",
|
||||||
|
"trojan",
|
||||||
"laravel"
|
"laravel"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.2",
|
"php": "^7.2.5|^8.0",
|
||||||
"fideloper/proxy": "^4.0",
|
"fideloper/proxy": "^4.4",
|
||||||
|
"fruitcake/laravel-cors": "^2.0",
|
||||||
"google/recaptcha": "^1.2",
|
"google/recaptcha": "^1.2",
|
||||||
"laravel/framework": "^6.0",
|
"guzzlehttp/guzzle": "^6.3.1|^7.0.1",
|
||||||
"laravel/tinker": "^1.0",
|
"laravel/framework": "^7.29",
|
||||||
"lokielse/omnipay-alipay": "3.0.6",
|
"laravel/horizon": "^4.3.5",
|
||||||
|
"laravel/tinker": "^2.5",
|
||||||
|
"linfo/linfo": "^4.0",
|
||||||
|
"lokielse/omnipay-alipay": "3.1.2",
|
||||||
"lokielse/omnipay-wechatpay": "^3.0",
|
"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"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"facade/ignition": "^1.4",
|
"facade/ignition": "^2.0",
|
||||||
"fzaninotto/faker": "^1.4",
|
"fakerphp/faker": "^1.9.1",
|
||||||
"mockery/mockery": "^1.0",
|
"mockery/mockery": "^1.3.1",
|
||||||
"nunomaduro/collision": "^3.0",
|
"nunomaduro/collision": "^4.3",
|
||||||
"phpunit/phpunit": "^8.0"
|
"phpunit/phpunit": "^8.5.8|^9.3.3"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
|
@ -173,6 +173,7 @@ return [
|
|||||||
App\Providers\AuthServiceProvider::class,
|
App\Providers\AuthServiceProvider::class,
|
||||||
// App\Providers\BroadcastServiceProvider::class,
|
// App\Providers\BroadcastServiceProvider::class,
|
||||||
App\Providers\EventServiceProvider::class,
|
App\Providers\EventServiceProvider::class,
|
||||||
|
App\Providers\HorizonServiceProvider::class,
|
||||||
App\Providers\RouteServiceProvider::class,
|
App\Providers\RouteServiceProvider::class,
|
||||||
|
|
||||||
],
|
],
|
||||||
@ -236,5 +237,5 @@ return [
|
|||||||
| The only modification by laravel config
|
| The only modification by laravel config
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'version' => '1.5.2.1627559775390'
|
'version' => '1.5.3.1628409393360'
|
||||||
];
|
];
|
||||||
|
34
config/cors.php
Normal file
34
config/cors.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your settings for cross-origin resource sharing
|
||||||
|
| or "CORS". This determines what cross-origin operations may execute
|
||||||
|
| in web browsers. You are free to adjust these settings as needed.
|
||||||
|
|
|
||||||
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'paths' => ['api/*'],
|
||||||
|
|
||||||
|
'allowed_methods' => ['*'],
|
||||||
|
|
||||||
|
'allowed_origins' => ['*'],
|
||||||
|
|
||||||
|
'allowed_origins_patterns' => [],
|
||||||
|
|
||||||
|
'allowed_headers' => ['*'],
|
||||||
|
|
||||||
|
'exposed_headers' => [],
|
||||||
|
|
||||||
|
'max_age' => 0,
|
||||||
|
|
||||||
|
'supports_credentials' => false,
|
||||||
|
|
||||||
|
];
|
191
config/horizon.php
Normal file
191
config/horizon.php
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Linfo\Linfo;
|
||||||
|
|
||||||
|
$lInfo = new Linfo();
|
||||||
|
$parser = $lInfo->getParser();
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Domain
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the subdomain where Horizon will be accessible from. If this
|
||||||
|
| setting is null, Horizon will reside under the same domain as the
|
||||||
|
| application. Otherwise, this value will serve as the subdomain.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'domain' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the URI path where Horizon will be accessible from. Feel free
|
||||||
|
| to change this path to anything you like. Note that the URI will not
|
||||||
|
| affect the paths of its internal API that aren't exposed to users.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'path' => 'monitor',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Redis Connection
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This is the name of the Redis connection where Horizon will store the
|
||||||
|
| meta information required for it to function. It includes the list
|
||||||
|
| of supervisors, failed jobs, job metrics, and other information.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use' => 'default',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Redis Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This prefix will be used when storing all Horizon data in Redis. You
|
||||||
|
| may modify the prefix when you are running multiple installations
|
||||||
|
| of Horizon on the same server so that they don't have problems.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env(
|
||||||
|
'HORIZON_PREFIX',
|
||||||
|
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
|
||||||
|
),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Horizon Route Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These middleware will get attached onto each Horizon route, giving you
|
||||||
|
| the chance to add your own middleware to this list or change any of
|
||||||
|
| the existing middleware. Or, you can simply stick with this list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => ['web', 'admin'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Wait Time Thresholds
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to configure when the LongWaitDetected event
|
||||||
|
| will be fired. Every connection / queue combination may have its
|
||||||
|
| own, unique threshold (in seconds) before this event is fired.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'waits' => [
|
||||||
|
'redis:default' => 60,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Job Trimming Times
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you can configure for how long (in minutes) you desire Horizon to
|
||||||
|
| persist the recent and failed jobs. Typically, recent jobs are kept
|
||||||
|
| for one hour while all failed jobs are stored for an entire week.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'trim' => [
|
||||||
|
'recent' => 60,
|
||||||
|
'pending' => 60,
|
||||||
|
'completed' => 60,
|
||||||
|
'recent_failed' => 10080,
|
||||||
|
'failed' => 10080,
|
||||||
|
'monitored' => 10080,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Metrics
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you can configure how many snapshots should be kept to display in
|
||||||
|
| the metrics graph. This will get used in combination with Horizon's
|
||||||
|
| `horizon:snapshot` schedule to define how long to retain metrics.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'metrics' => [
|
||||||
|
'trim_snapshots' => [
|
||||||
|
'job' => 24,
|
||||||
|
'queue' => 24,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Fast Termination
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When this option is enabled, Horizon's "terminate" command will not
|
||||||
|
| wait on all of the workers to terminate unless the --wait option
|
||||||
|
| is provided. Fast termination can shorten deployment delay by
|
||||||
|
| allowing a new instance of Horizon to start while the last
|
||||||
|
| instance will continue to terminate each of its workers.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'fast_termination' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Memory Limit (MB)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value describes the maximum amount of memory the Horizon worker
|
||||||
|
| may consume before it is terminated and restarted. You should set
|
||||||
|
| this value according to the resources available to your server.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'memory_limit' => 32,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Worker Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define the queue worker settings used by your application
|
||||||
|
| in all environments. These supervisors and settings handle all your
|
||||||
|
| queued jobs and will be provisioned by Horizon during deployment.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'environments' => [
|
||||||
|
'local' => [
|
||||||
|
'V2board' => [
|
||||||
|
'connection' => 'redis',
|
||||||
|
'queue' => [
|
||||||
|
'traffic_fetch',
|
||||||
|
'server_log',
|
||||||
|
'send_email',
|
||||||
|
'send_telegram',
|
||||||
|
'stat_server',
|
||||||
|
'order_handle'
|
||||||
|
],
|
||||||
|
'balance' => 'auto',
|
||||||
|
'minProcesses' => 1,
|
||||||
|
'maxProcesses' => (int)ceil($parser->getRam()['total'] / 1024 / 1024 / 1024 * 6),
|
||||||
|
'tries' => 1,
|
||||||
|
'nice' => 0,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
@ -19,6 +19,20 @@ CREATE TABLE `failed_jobs` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `v2_commission_log`;
|
||||||
|
CREATE TABLE `v2_commission_log` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`invite_user_id` int(11) NOT NULL,
|
||||||
|
`user_id` int(11) NOT NULL,
|
||||||
|
`trade_no` char(36) NOT NULL,
|
||||||
|
`order_amount` int(11) NOT NULL,
|
||||||
|
`get_amount` int(11) NOT NULL,
|
||||||
|
`created_at` int(11) NOT NULL,
|
||||||
|
`updated_at` int(11) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `v2_coupon`;
|
DROP TABLE IF EXISTS `v2_coupon`;
|
||||||
CREATE TABLE `v2_coupon` (
|
CREATE TABLE `v2_coupon` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
@ -27,6 +41,7 @@ CREATE TABLE `v2_coupon` (
|
|||||||
`type` tinyint(1) NOT NULL,
|
`type` tinyint(1) NOT NULL,
|
||||||
`value` int(11) NOT NULL,
|
`value` int(11) NOT NULL,
|
||||||
`limit_use` int(11) DEFAULT NULL,
|
`limit_use` int(11) DEFAULT NULL,
|
||||||
|
`limit_use_with_user` int(11) DEFAULT NULL,
|
||||||
`limit_plan_ids` varchar(255) DEFAULT NULL,
|
`limit_plan_ids` varchar(255) DEFAULT NULL,
|
||||||
`started_at` int(11) NOT NULL,
|
`started_at` int(11) NOT NULL,
|
||||||
`ended_at` int(11) NOT NULL,
|
`ended_at` int(11) NOT NULL,
|
||||||
@ -110,6 +125,7 @@ CREATE TABLE `v2_order` (
|
|||||||
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待支付1开通中2已取消3已完成4已折抵',
|
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待支付1开通中2已取消3已完成4已折抵',
|
||||||
`commission_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待确认1发放中2有效3无效',
|
`commission_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0待确认1发放中2有效3无效',
|
||||||
`commission_balance` int(11) NOT NULL DEFAULT '0',
|
`commission_balance` int(11) NOT NULL DEFAULT '0',
|
||||||
|
`paid_at` int(11) DEFAULT NULL,
|
||||||
`created_at` int(11) NOT NULL,
|
`created_at` int(11) NOT NULL,
|
||||||
`updated_at` int(11) NOT NULL,
|
`updated_at` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
@ -149,40 +165,13 @@ CREATE TABLE `v2_plan` (
|
|||||||
`three_year_price` int(11) DEFAULT NULL,
|
`three_year_price` int(11) DEFAULT NULL,
|
||||||
`onetime_price` int(11) DEFAULT NULL,
|
`onetime_price` int(11) DEFAULT NULL,
|
||||||
`reset_price` int(11) DEFAULT NULL,
|
`reset_price` int(11) DEFAULT NULL,
|
||||||
|
`reset_traffic_method` tinyint(1) DEFAULT NULL,
|
||||||
`created_at` int(11) NOT NULL,
|
`created_at` int(11) NOT NULL,
|
||||||
`updated_at` int(11) NOT NULL,
|
`updated_at` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `v2_server`;
|
|
||||||
CREATE TABLE `v2_server` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`group_id` varchar(255) NOT NULL,
|
|
||||||
`name` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
|
|
||||||
`parent_id` int(11) DEFAULT NULL,
|
|
||||||
`host` varchar(255) NOT NULL,
|
|
||||||
`port` int(11) NOT NULL,
|
|
||||||
`server_port` int(11) NOT NULL,
|
|
||||||
`tls` tinyint(4) NOT NULL DEFAULT '0',
|
|
||||||
`tags` varchar(255) DEFAULT NULL,
|
|
||||||
`rate` varchar(11) NOT NULL,
|
|
||||||
`network` text NOT NULL,
|
|
||||||
`alter_id` int(11) NOT NULL DEFAULT '1',
|
|
||||||
`settings` text,
|
|
||||||
`rules` text,
|
|
||||||
`networkSettings` text,
|
|
||||||
`tlsSettings` text,
|
|
||||||
`ruleSettings` text,
|
|
||||||
`dnsSettings` text,
|
|
||||||
`show` tinyint(1) NOT NULL DEFAULT '0',
|
|
||||||
`sort` int(11) DEFAULT NULL,
|
|
||||||
`created_at` int(11) NOT NULL,
|
|
||||||
`updated_at` int(11) NOT NULL,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `v2_server_group`;
|
DROP TABLE IF EXISTS `v2_server_group`;
|
||||||
CREATE TABLE `v2_server_group` (
|
CREATE TABLE `v2_server_group` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
@ -206,7 +195,9 @@ CREATE TABLE `v2_server_log` (
|
|||||||
`created_at` int(11) NOT NULL,
|
`created_at` int(11) NOT NULL,
|
||||||
`updated_at` int(11) NOT NULL,
|
`updated_at` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `log_at` (`log_at`)
|
KEY `log_at` (`log_at`),
|
||||||
|
KEY `user_id` (`user_id`),
|
||||||
|
KEY `server_id` (`server_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
@ -251,6 +242,34 @@ CREATE TABLE `v2_server_trojan` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='trojan伺服器表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='trojan伺服器表';
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `v2_server_v2ray`;
|
||||||
|
CREATE TABLE `v2_server_v2ray` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`group_id` varchar(255) NOT NULL,
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 NOT NULL,
|
||||||
|
`parent_id` int(11) DEFAULT NULL,
|
||||||
|
`host` varchar(255) NOT NULL,
|
||||||
|
`port` int(11) NOT NULL,
|
||||||
|
`server_port` int(11) NOT NULL,
|
||||||
|
`tls` tinyint(4) NOT NULL DEFAULT '0',
|
||||||
|
`tags` varchar(255) DEFAULT NULL,
|
||||||
|
`rate` varchar(11) NOT NULL,
|
||||||
|
`network` text NOT NULL,
|
||||||
|
`alter_id` int(11) NOT NULL DEFAULT '1',
|
||||||
|
`settings` text,
|
||||||
|
`rules` text,
|
||||||
|
`networkSettings` text,
|
||||||
|
`tlsSettings` text,
|
||||||
|
`ruleSettings` text,
|
||||||
|
`dnsSettings` text,
|
||||||
|
`show` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`sort` int(11) DEFAULT NULL,
|
||||||
|
`created_at` int(11) NOT NULL,
|
||||||
|
`updated_at` int(11) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `v2_stat_order`;
|
DROP TABLE IF EXISTS `v2_stat_order`;
|
||||||
CREATE TABLE `v2_stat_order` (
|
CREATE TABLE `v2_stat_order` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
@ -304,7 +323,7 @@ CREATE TABLE `v2_ticket_message` (
|
|||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`user_id` int(11) NOT NULL,
|
`user_id` int(11) NOT NULL,
|
||||||
`ticket_id` int(11) NOT NULL,
|
`ticket_id` int(11) NOT NULL,
|
||||||
`message` varchar(255) NOT NULL,
|
`message` text CHARACTER SET utf8mb4 NOT NULL,
|
||||||
`created_at` int(11) NOT NULL,
|
`created_at` int(11) NOT NULL,
|
||||||
`updated_at` int(11) NOT NULL,
|
`updated_at` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
@ -319,6 +338,7 @@ CREATE TABLE `v2_user` (
|
|||||||
`email` varchar(64) NOT NULL,
|
`email` varchar(64) NOT NULL,
|
||||||
`password` varchar(64) NOT NULL,
|
`password` varchar(64) NOT NULL,
|
||||||
`password_algo` char(10) DEFAULT NULL,
|
`password_algo` char(10) DEFAULT NULL,
|
||||||
|
`password_salt` 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_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0: system 1: cycle 2: onetime',
|
||||||
@ -336,8 +356,8 @@ CREATE TABLE `v2_user` (
|
|||||||
`uuid` varchar(36) NOT NULL,
|
`uuid` varchar(36) NOT NULL,
|
||||||
`group_id` int(11) DEFAULT NULL,
|
`group_id` int(11) DEFAULT NULL,
|
||||||
`plan_id` int(11) DEFAULT NULL,
|
`plan_id` int(11) DEFAULT NULL,
|
||||||
`remind_expire` tinyint(4) DEFAULT '1',
|
`remind_expire` tinyint(4) DEFAULT '0',
|
||||||
`remind_traffic` tinyint(4) DEFAULT '1',
|
`remind_traffic` tinyint(4) DEFAULT '0',
|
||||||
`token` char(32) NOT NULL,
|
`token` char(32) NOT NULL,
|
||||||
`remarks` text,
|
`remarks` text,
|
||||||
`expired_at` bigint(20) DEFAULT '0',
|
`expired_at` bigint(20) DEFAULT '0',
|
||||||
@ -348,4 +368,4 @@ CREATE TABLE `v2_user` (
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
-- 2021-07-13 13:50:52
|
-- 2021-09-21 10:07:22
|
||||||
|
@ -425,3 +425,40 @@ DROP INDEX `email_deleted_at`;
|
|||||||
|
|
||||||
ALTER TABLE `v2_user`
|
ALTER TABLE `v2_user`
|
||||||
ADD `commission_type` tinyint NOT NULL DEFAULT '0' COMMENT '0: system 1: cycle 2: onetime' AFTER `discount`;
|
ADD `commission_type` tinyint NOT NULL DEFAULT '0' COMMENT '0: system 1: cycle 2: onetime' AFTER `discount`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_order`
|
||||||
|
ADD `paid_at` int(11) NULL AFTER `commission_balance`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_server_log`
|
||||||
|
ADD INDEX `user_id` (`user_id`),
|
||||||
|
ADD INDEX `server_id` (`server_id`);
|
||||||
|
|
||||||
|
ALTER TABLE `v2_ticket_message`
|
||||||
|
CHANGE `message` `message` text COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `ticket_id`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_coupon`
|
||||||
|
ADD `limit_use_with_user` int(11) NULL AFTER `limit_use`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_user`
|
||||||
|
ADD `password_salt` char(10) COLLATE 'utf8_general_ci' NULL AFTER `password_algo`;
|
||||||
|
|
||||||
|
CREATE TABLE `v2_commission_log` (
|
||||||
|
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`invite_user_id` int(11) NOT NULL,
|
||||||
|
`user_id` int(11) NOT NULL,
|
||||||
|
`trade_no` char(36) NOT NULL,
|
||||||
|
`order_amount` int(11) NOT NULL,
|
||||||
|
`get_amount` int(11) NOT NULL,
|
||||||
|
`created_at` int(11) NOT NULL,
|
||||||
|
`updated_at` int(11) NOT NULL
|
||||||
|
) COLLATE 'utf8mb4_general_ci';
|
||||||
|
|
||||||
|
ALTER TABLE `v2_plan`
|
||||||
|
ADD `reset_traffic_method` tinyint(1) NULL AFTER `reset_price`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_server`
|
||||||
|
RENAME TO `v2_server_v2ray`;
|
||||||
|
|
||||||
|
ALTER TABLE `v2_user`
|
||||||
|
CHANGE `remind_expire` `remind_expire` tinyint(4) NULL DEFAULT '0' AFTER `plan_id`,
|
||||||
|
CHANGE `remind_traffic` `remind_traffic` tinyint(4) NULL DEFAULT '0' AFTER `remind_expire`;
|
||||||
|
1
init.sh
1
init.sh
@ -1,3 +1,4 @@
|
|||||||
|
rm -rf composer.phar
|
||||||
wget https://getcomposer.org/download/2.0.13/composer.phar
|
wget https://getcomposer.org/download/2.0.13/composer.phar
|
||||||
php composer.phar install -vvv
|
php composer.phar install -vvv
|
||||||
php artisan v2board:install
|
php artisan v2board:install
|
||||||
|
4
pm2.yaml
4
pm2.yaml
@ -1,5 +1,5 @@
|
|||||||
apps:
|
apps:
|
||||||
- name : 'V2Board'
|
- name : 'V2Board'
|
||||||
script : 'php artisan queue:work --queue=send_email,send_telegram,stat_server'
|
script : 'php artisan horizon'
|
||||||
instances: 4
|
instances: 1
|
||||||
out_file : './storage/logs/queue/queue.log'
|
out_file : './storage/logs/queue/queue.log'
|
||||||
|
4
public/assets/admin/theme/green.css
vendored
Normal file
4
public/assets/admin/theme/green.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/assets/admin/umi.css
vendored
2
public/assets/admin/umi.css
vendored
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user