mirror of
https://github.com/cedar2025/Xboard.git
synced 2025-01-22 10:38:14 -05:00
refactor: 重构规范部分代码、邮件队列增加失败重试、去除多个支付方式、更新依赖
This commit is contained in:
parent
ec63e05575
commit
4c6c7182e2
@ -46,8 +46,7 @@ class CheckServer extends Command
|
||||
|
||||
private function checkOffline()
|
||||
{
|
||||
$serverService = new ServerService();
|
||||
$servers = $serverService->getAllServers();
|
||||
$servers = ServerService::getAllServers();
|
||||
foreach ($servers as $server) {
|
||||
if ($server['parent_id']) continue;
|
||||
if ($server['last_check_at'] && (time() - $server['last_check_at']) > 1800) {
|
||||
|
@ -45,7 +45,7 @@ class CheckTicket extends Command
|
||||
->get();
|
||||
foreach ($tickets as $ticket) {
|
||||
if ($ticket->user_id === $ticket->last_reply_user_id) continue;
|
||||
$ticket->status = 1;
|
||||
$ticket->status = Ticket::STATUS_CLOSED;
|
||||
$ticket->save();
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ namespace App\Console\Commands;
|
||||
use App\Services\MailService;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\MailLog;
|
||||
use App\Jobs\SendEmailJob;
|
||||
|
||||
class SendRemindMail extends Command
|
||||
{
|
||||
|
@ -52,7 +52,8 @@ class XboardInstall extends Command
|
||||
$this->info(" \ \/ / | __ \ / _ \ / _` | '__/ _` | ");
|
||||
$this->info(" / /\ \ | |_) | (_) | (_| | | | (_| | ");
|
||||
$this->info("/_/ \_\|____/ \___/ \__,_|_| \__,_| ");
|
||||
if ((\File::exists(base_path() . '/.env') && $this->getEnvValue('INSTALLED'))
|
||||
if (
|
||||
(\File::exists(base_path() . '/.env') && $this->getEnvValue('INSTALLED'))
|
||||
|| (env('INSTALLED', false) && $isDocker)
|
||||
) {
|
||||
$securePath = admin_setting('secure_path', admin_setting('frontend_admin_path', hash('crc32b', config('app.key'))));
|
||||
@ -60,23 +61,15 @@ class XboardInstall extends Command
|
||||
$this->warn("如需重新安装请清空目录下 .env 文件的内容(Docker安装方式不可以删除此文件)");
|
||||
$this->warn("快捷清空.env命令:");
|
||||
note('rm .env && touch .env');
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (is_dir(base_path() . '/.env')){
|
||||
if (is_dir(base_path() . '/.env')) {
|
||||
$this->error('😔:安装失败,Docker环境下安装请保留空的 .env 文件');
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
// 选择是否使用Sqlite
|
||||
if(confirm(label: '是否启用Sqlite(无需额外安装)代替Mysql',default: false, yes: '启用', no: '不启用')) {
|
||||
if (confirm(label: '是否启用Sqlite(无需额外安装)代替Mysql', default: false, yes: '启用', no: '不启用')) {
|
||||
$sqliteFile = '.docker/.data/database.sqlite';
|
||||
if (!file_exists(base_path($sqliteFile))) {
|
||||
// 创建空文件
|
||||
if (!touch(base_path($sqliteFile))) {
|
||||
echo "sqlite创建成功: $sqliteFile";
|
||||
} else {
|
||||
echo "sqlite创建失败";
|
||||
}
|
||||
}
|
||||
$envConfig = [
|
||||
'DB_CONNECTION' => 'sqlite',
|
||||
'DB_DATABASE' => $sqliteFile,
|
||||
@ -84,16 +77,16 @@ class XboardInstall extends Command
|
||||
'DB_USERNAME' => '',
|
||||
'DB_PASSWORD' => '',
|
||||
];
|
||||
}else{
|
||||
} else {
|
||||
$isMysqlValid = false;
|
||||
while(!$isMysqlValid){
|
||||
while (!$isMysqlValid) {
|
||||
$envConfig = [
|
||||
'DB_CONNECTION' => 'mysql',
|
||||
'DB_HOST' => text(label: "请输入数据库地址", default: '127.0.0.1', required: true),
|
||||
'DB_PORT' => text(label: '请输入数据库端口', default: '3306', required: true),
|
||||
'DB_DATABASE' => text(label:'请输入数据库名', default:'xboard', required: true),
|
||||
'DB_USERNAME' => text(label:'请输入数据库用户名', required: true),
|
||||
'DB_PASSWORD' => text(label:'请输入数据库密码', required: false),
|
||||
'DB_DATABASE' => text(label: '请输入数据库名', default: 'xboard', required: true),
|
||||
'DB_USERNAME' => text(label: '请输入数据库用户名', required: true),
|
||||
'DB_PASSWORD' => text(label: '请输入数据库密码', required: false),
|
||||
];
|
||||
try {
|
||||
\Config::set("database.connections.mysql.host", $envConfig['DB_HOST']);
|
||||
@ -114,14 +107,14 @@ class XboardInstall extends Command
|
||||
$envConfig['APP_KEY'] = 'base64:' . base64_encode(Encrypter::generateKey('AES-256-CBC'));
|
||||
$envConfig['INSTALLED'] = true;
|
||||
$isReidsValid = false;
|
||||
while(!$isReidsValid){
|
||||
while (!$isReidsValid) {
|
||||
// 判断是否为Docker环境
|
||||
if ($isDocker == 'true' && (confirm(label: '是否启用Docker内置的Redis', default: true, yes:'启用', no:'不启用'))){
|
||||
if ($isDocker == 'true' && (confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) {
|
||||
$envConfig['REDIS_HOST'] = '/run/redis-socket/redis.sock';
|
||||
$envConfig['REDIS_PORT'] = 0;
|
||||
$envConfig['REDIS_PASSWORD'] = null;
|
||||
}else{
|
||||
$envConfig['REDIS_HOST'] = text(label: '请输入Redis地址', default: '127.0.0.1',required: true);
|
||||
} else {
|
||||
$envConfig['REDIS_HOST'] = text(label: '请输入Redis地址', default: '127.0.0.1', required: true);
|
||||
$envConfig['REDIS_PORT'] = text(label: '请输入Redis端口', default: '6379', required: true);
|
||||
$envConfig['REDIS_PASSWORD'] = text(label: '请输入redis密码(默认: null)', default: '');
|
||||
}
|
||||
@ -134,11 +127,11 @@ class XboardInstall extends Command
|
||||
'database' => 0,
|
||||
],
|
||||
];
|
||||
try{
|
||||
try {
|
||||
$redis = new \Illuminate\Redis\RedisManager(app(), 'phpredis', $redisConfig);
|
||||
$redis->ping();
|
||||
$isReidsValid = true;
|
||||
}catch(\Exception $e){
|
||||
} catch (\Exception $e) {
|
||||
// 连接失败,输出错误消息
|
||||
$this->error("redis连接失败:" . $e->getMessage());
|
||||
$this->info("请重新输入REDIS配置");
|
||||
@ -147,12 +140,16 @@ class XboardInstall extends Command
|
||||
|
||||
if (!copy(base_path() . '/.env.example', base_path() . '/.env')) {
|
||||
abort(500, '复制环境文件失败,请检查目录权限');
|
||||
};
|
||||
$email = text(label: '请输入管理员账号',required: true,
|
||||
validate: fn (string $email): ?string => match (true) {
|
||||
! filter_var($email, FILTER_VALIDATE_EMAIL) => '请输入有效的邮箱地址.',
|
||||
}
|
||||
;
|
||||
$email = text(
|
||||
label: '请输入管理员账号',
|
||||
required: true,
|
||||
validate: fn(string $email): ?string => match (true) {
|
||||
!filter_var($email, FILTER_VALIDATE_EMAIL) => '请输入有效的邮箱地址.',
|
||||
default => null,
|
||||
});
|
||||
}
|
||||
);
|
||||
$password = Helper::guid(false);
|
||||
$this->saveToEnv($envConfig);
|
||||
|
||||
@ -197,9 +194,9 @@ class XboardInstall extends Command
|
||||
|
||||
private function saveToEnv($data = [])
|
||||
{
|
||||
function set_env_var($key, $value)
|
||||
{
|
||||
if (! is_bool(strpos($value, ' '))) {
|
||||
foreach ($data as $key => $value) {
|
||||
function ($key, $value) {
|
||||
if (!is_bool(strpos($value, ' '))) {
|
||||
$value = '"' . $value . '"';
|
||||
}
|
||||
$key = strtoupper($key);
|
||||
@ -220,9 +217,7 @@ class XboardInstall extends Command
|
||||
$file = fopen($envPath, 'w');
|
||||
fwrite($file, $contents);
|
||||
return fclose($file);
|
||||
}
|
||||
foreach($data as $key => $value) {
|
||||
set_env_var($key, $value);
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -5,10 +5,8 @@ namespace App\Exceptions;
|
||||
use App\Helpers\ApiResponse;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Support\Arr;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Illuminate\View\ViewException;
|
||||
use Throwable;
|
||||
use Facade\Ignition\Exceptions\ViewException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
use App\Support\Setting;
|
||||
|
||||
|
||||
if (! function_exists("get_request_content")){
|
||||
@ -20,14 +21,14 @@ if (! function_exists('admin_setting')) {
|
||||
function admin_setting($key = null, $default = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
return app('setting');
|
||||
return App::make(Setting::class)->toArray();
|
||||
}
|
||||
|
||||
if (is_array($key)) {
|
||||
app('setting')->save($key);
|
||||
return;
|
||||
App::make(Setting::class)->save($key);
|
||||
return '';
|
||||
}
|
||||
$default = config('v2board.'. $key) ?? $default;
|
||||
return app('setting')->get($key) ?? $default ;
|
||||
return App::make(Setting::class)->get($key) ?? $default ;
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ namespace App\Http\Controllers\V1\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\ConfigSave;
|
||||
use App\Jobs\SendEmailJob;
|
||||
use App\Models\Setting;
|
||||
use App\Services\MailService;
|
||||
use App\Services\TelegramService;
|
||||
use App\Utils\Dict;
|
||||
use Illuminate\Http\Request;
|
||||
@ -33,7 +33,7 @@ class ConfigController extends Controller
|
||||
|
||||
public function testSendMail(Request $request)
|
||||
{
|
||||
$obj = new SendEmailJob([
|
||||
$mailLog = MailService::sendEmail([
|
||||
'email' => $request->user['email'],
|
||||
'subject' => 'This is xboard test email',
|
||||
'template_name' => 'notify',
|
||||
@ -45,7 +45,7 @@ class ConfigController extends Controller
|
||||
]);
|
||||
return response([
|
||||
'data' => true,
|
||||
'log' => $obj->handle()
|
||||
'log' => $mailLog
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -160,13 +160,13 @@ class OrderController extends Controller
|
||||
$order->total_amount = $request->input('total_amount');
|
||||
|
||||
if ($order->period === 'reset_price') {
|
||||
$order->type = 4;
|
||||
$order->type = Order::TYPE_RESET_TRAFFIC;
|
||||
} else if ($user->plan_id !== NULL && $order->plan_id !== $user->plan_id) {
|
||||
$order->type = 3;
|
||||
$order->type = Order::TYPE_UPGRADE;
|
||||
} else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) {
|
||||
$order->type = 2;
|
||||
$order->type = Order::TYPE_RENEWAL;
|
||||
} else {
|
||||
$order->type = 1;
|
||||
$order->type = Order::TYPE_NEW_PURCHASE;
|
||||
}
|
||||
|
||||
$orderService->setInvite($user);
|
||||
|
@ -19,8 +19,7 @@ class GroupController extends Controller
|
||||
return $this->success([ServerGroup::find($request->input('group_id'))]);
|
||||
}
|
||||
$serverGroups = ServerGroup::get();
|
||||
$serverService = new ServerService();
|
||||
$servers = $serverService->getAllServers();
|
||||
$servers = ServerService::getAllServers();
|
||||
foreach ($serverGroups as $k => $v) {
|
||||
$serverGroups[$k]['user_count'] = User::where('group_id', $v['id'])->count();
|
||||
$serverGroups[$k]['server_count'] = 0;
|
||||
|
@ -12,8 +12,7 @@ class ManageController extends Controller
|
||||
{
|
||||
public function getNodes(Request $request)
|
||||
{
|
||||
$serverService = new ServerService();
|
||||
return $this->success($serverService->getAllServers());
|
||||
return $this->success(ServerService::getAllServers());
|
||||
}
|
||||
|
||||
public function sort(Request $request)
|
||||
|
@ -2,12 +2,10 @@
|
||||
|
||||
namespace App\Http\Controllers\V1\Admin\Server;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\ServerTrojanSave;
|
||||
use App\Http\Requests\Admin\ServerTrojanUpdate;
|
||||
use App\Models\ServerTrojan;
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrojanController extends Controller
|
||||
@ -75,10 +73,4 @@ class TrojanController extends Controller
|
||||
ServerTrojan::create($server->toArray());
|
||||
return $this->success(true);
|
||||
}
|
||||
public function viewConfig(Request $request)
|
||||
{
|
||||
$serverService = new ServerService();
|
||||
$config = $serverService->getTrojanConfig($request->input('node_id'), 23333);
|
||||
return $this->success($config);
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class TicketController extends Controller
|
||||
]);
|
||||
try {
|
||||
$ticket = Ticket::findOrFail($request->input('id'));
|
||||
$ticket->status = 1;
|
||||
$ticket->status = Ticket::STATUS_CLOSED;
|
||||
$ticket->save();
|
||||
return $this->success(true);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
|
@ -17,8 +17,7 @@ class AppController extends Controller
|
||||
$user = $request->user;
|
||||
$userService = new UserService();
|
||||
if ($userService->isAvailable($user)) {
|
||||
$serverService = new ServerService();
|
||||
$servers = $serverService->getAvailableServers($user);
|
||||
$servers = ServerService::getAvailableServers($user);
|
||||
}
|
||||
$defaultConfig = base_path() . '/resources/rules/app.clash.yaml';
|
||||
$customConfig = base_path() . '/resources/rules/custom.app.clash.yaml';
|
||||
|
@ -65,8 +65,7 @@ class ClientController extends Controller
|
||||
$region = $geo['region'] ?? null;
|
||||
|
||||
// 获取服务器列表
|
||||
$serverService = new ServerService();
|
||||
$servers = $serverService->getAvailableServers($user);
|
||||
$servers = ServerService::getAvailableServers($user);
|
||||
|
||||
// 判断不满足,不满足的直接过滤掉
|
||||
$serversFiltered = collect($servers)->reject(function ($server) use ($typesArr, $filterArr, $region, $supportHy2){
|
||||
|
@ -17,14 +17,15 @@ class PaymentController extends Controller
|
||||
try {
|
||||
$paymentService = new PaymentService($method, null, $uuid);
|
||||
$verify = $paymentService->notify($request->input());
|
||||
if (!$verify) return $this->fail([422,'verify error']);
|
||||
if (!$verify)
|
||||
return $this->fail([422, 'verify error']);
|
||||
if (!$this->handle($verify['trade_no'], $verify['callback_no'])) {
|
||||
return $this->fail([400,'handle error']);
|
||||
return $this->fail([400, 'handle error']);
|
||||
}
|
||||
return (isset($verify['custom_result']) ? $verify['custom_result'] : 'success');
|
||||
} catch (\Exception $e) {
|
||||
\Log::error($e);
|
||||
return $this->fail([500,'fail']);
|
||||
return $this->fail([500, 'fail']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,9 +33,10 @@ class PaymentController extends Controller
|
||||
{
|
||||
$order = Order::where('trade_no', $tradeNo)->first();
|
||||
if (!$order) {
|
||||
return $this->fail([400202,'order is not found']);
|
||||
return $this->fail([400202, 'order is not found']);
|
||||
}
|
||||
if ($order->status !== 0) return true;
|
||||
if ($order->status !== Order::STATUS_PENDING)
|
||||
return true;
|
||||
$orderService = new OrderService($order);
|
||||
if (!$orderService->paid($callbackNo)) {
|
||||
return false;
|
||||
|
@ -13,24 +13,23 @@ class TelegramController extends Controller
|
||||
protected $commands = [];
|
||||
protected $telegramService;
|
||||
|
||||
public function __construct(Request $request)
|
||||
public function __construct(TelegramService $telegramService)
|
||||
{
|
||||
if ($request->input('access_token') !== md5(admin_setting('telegram_bot_token'))) {
|
||||
throw new ApiException('access_token is error', 401);
|
||||
}
|
||||
|
||||
$this->telegramService = new TelegramService();
|
||||
$this->telegramService = $telegramService;
|
||||
}
|
||||
|
||||
public function webhook(Request $request)
|
||||
{
|
||||
if ($request->input('access_token') !== md5(admin_setting('telegram_bot_token'))) {
|
||||
throw new ApiException('access_token is error', 401);
|
||||
}
|
||||
$data = json_decode(get_request_content(),true);
|
||||
$this->formatMessage($data);
|
||||
$this->formatChatJoinRequest($data);
|
||||
$this->handle();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
private function handle()
|
||||
{
|
||||
if (!$this->msg) return;
|
||||
$msg = $this->msg;
|
||||
@ -68,7 +67,7 @@ class TelegramController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function getBotName()
|
||||
private function getBotName()
|
||||
{
|
||||
$response = $this->telegramService->getMe();
|
||||
return $response->result->username;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers\V1\Passport;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Helpers\ResponseEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Passport\AuthForget;
|
||||
|
@ -18,16 +18,6 @@ use Illuminate\Support\Facades\Cache;
|
||||
class DeepbworkController extends Controller
|
||||
{
|
||||
CONST V2RAY_CONFIG = '{"log":{"loglevel":"debug","access":"access.log","error":"error.log"},"api":{"services":["HandlerService","StatsService"],"tag":"api"},"dns":{},"stats":{},"inbounds":[{"port":443,"protocol":"vmess","settings":{"clients":[]},"sniffing":{"enabled":true,"destOverride":["http","tls"]},"streamSettings":{"network":"tcp"},"tag":"proxy"},{"listen":"127.0.0.1","port":23333,"protocol":"dokodemo-door","settings":{"address":"0.0.0.0"},"tag":"api"}],"outbounds":[{"protocol":"freedom","settings":{}},{"protocol":"blackhole","settings":{},"tag":"block"}],"routing":{"rules":[{"type":"field","inboundTag":"api","outboundTag":"api"}]},"policy":{"levels":{"0":{"handshake":4,"connIdle":300,"uplinkOnly":5,"downlinkOnly":30,"statsUserUplink":true,"statsUserDownlink":true}}}}';
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
throw new ApiException('token is null');
|
||||
}
|
||||
if ($token !== admin_setting('server_token')) {
|
||||
throw new ApiException('token is error');
|
||||
}
|
||||
}
|
||||
|
||||
// 后端获取用户
|
||||
public function user(Request $request)
|
||||
@ -39,8 +29,7 @@ class DeepbworkController extends Controller
|
||||
return $this->fail([400,'节点不存在']);
|
||||
}
|
||||
Cache::put(CacheKey::get('SERVER_VMESS_LAST_CHECK_AT', $server->id), time(), 3600);
|
||||
$serverService = new ServerService();
|
||||
$users = $serverService->getAvailableUsers($server->group_id);
|
||||
$users = ServerService::getAvailableUsers($server->group_id);
|
||||
$result = [];
|
||||
foreach ($users as $user) {
|
||||
$user->v2ray_user = [
|
||||
|
@ -17,17 +17,6 @@ use Illuminate\Support\Facades\Cache;
|
||||
*/
|
||||
class ShadowsocksTidalabController extends Controller
|
||||
{
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
throw new ApiException('token is null');
|
||||
}
|
||||
if ($token !== admin_setting('server_token')) {
|
||||
throw new ApiException('token is error');
|
||||
}
|
||||
}
|
||||
|
||||
// 后端获取用户
|
||||
public function user(Request $request)
|
||||
{
|
||||
@ -38,8 +27,7 @@ class ShadowsocksTidalabController extends Controller
|
||||
return $this->fail([400,'节点不存在']);
|
||||
}
|
||||
Cache::put(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $server->id), time(), 3600);
|
||||
$serverService = new ServerService();
|
||||
$users = $serverService->getAvailableUsers($server->group_id);
|
||||
$users = ServerService::getAvailableUsers($server->group_id);
|
||||
$result = [];
|
||||
foreach ($users as $user) {
|
||||
array_push($result, [
|
||||
|
@ -17,17 +17,7 @@ use Illuminate\Support\Facades\Cache;
|
||||
*/
|
||||
class TrojanTidalabController extends Controller
|
||||
{
|
||||
CONST TROJAN_CONFIG = '{"run_type":"server","local_addr":"0.0.0.0","local_port":443,"remote_addr":"www.taobao.com","remote_port":80,"password":[],"ssl":{"cert":"server.crt","key":"server.key","sni":"domain.com"},"api":{"enabled":true,"api_addr":"127.0.0.1","api_port":10000}}';
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$token = $request->input('token');
|
||||
if (empty($token)) {
|
||||
throw new ApiException('token is null');
|
||||
}
|
||||
if ($token !== admin_setting('server_token')) {
|
||||
throw new ApiException('token is error');
|
||||
}
|
||||
}
|
||||
const TROJAN_CONFIG = '{"run_type":"server","local_addr":"0.0.0.0","local_port":443,"remote_addr":"www.taobao.com","remote_port":80,"password":[],"ssl":{"cert":"server.crt","key":"server.key","sni":"domain.com"},"api":{"enabled":true,"api_addr":"127.0.0.1","api_port":10000}}';
|
||||
|
||||
// 后端获取用户
|
||||
public function user(Request $request)
|
||||
@ -36,11 +26,10 @@ class TrojanTidalabController extends Controller
|
||||
$nodeId = $request->input('node_id');
|
||||
$server = ServerTrojan::find($nodeId);
|
||||
if (!$server) {
|
||||
return $this->fail([400,'节点不存在']);
|
||||
return $this->fail([400, '节点不存在']);
|
||||
}
|
||||
Cache::put(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $server->id), time(), 3600);
|
||||
$serverService = new ServerService();
|
||||
$users = $serverService->getAvailableUsers($server->group_id);
|
||||
$users = ServerService::getAvailableUsers($server->group_id);
|
||||
$result = [];
|
||||
foreach ($users as $user) {
|
||||
$user->trojan_user = [
|
||||
@ -50,8 +39,8 @@ class TrojanTidalabController extends Controller
|
||||
array_push($result, $user);
|
||||
}
|
||||
$eTag = sha1(json_encode($result));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
return response(null,304);
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false) {
|
||||
return response(null, 304);
|
||||
}
|
||||
return response([
|
||||
'msg' => 'ok',
|
||||
@ -92,7 +81,7 @@ class TrojanTidalabController extends Controller
|
||||
$request->validate([
|
||||
'node_id' => 'required',
|
||||
'local_port' => 'required'
|
||||
],[
|
||||
], [
|
||||
'node_id.required' => '节点ID不能为空',
|
||||
'local_port.required' => '本地端口不能为空'
|
||||
]);
|
||||
@ -100,10 +89,10 @@ class TrojanTidalabController extends Controller
|
||||
$json = $this->getTrojanConfig($request->input('node_id'), $request->input('local_port'));
|
||||
} catch (\Exception $e) {
|
||||
\Log::error($e);
|
||||
return $this->fail([500,'配置获取失败']);
|
||||
return $this->fail([500, '配置获取失败']);
|
||||
}
|
||||
|
||||
return(json_encode($json, JSON_UNESCAPED_UNICODE));
|
||||
return (json_encode($json, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
private function getTrojanConfig(int $nodeId, int $localPort)
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers\V1\Server;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\ServerService;
|
||||
use App\Services\UserService;
|
||||
@ -10,40 +9,23 @@ use App\Utils\CacheKey;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UniProxyController extends Controller
|
||||
{
|
||||
private $nodeType;
|
||||
private $nodeInfo;
|
||||
private $nodeId;
|
||||
private $serverService;
|
||||
|
||||
public function __construct(ServerService $serverService, Request $request)
|
||||
{
|
||||
$this->serverService = $serverService;
|
||||
$this->nodeId = $request->input('node_id');
|
||||
$this->nodeType = $request->input('node_type');
|
||||
$this->nodeInfo = $this->serverService->getServer($this->nodeId, $this->nodeType);
|
||||
if(!$this->nodeInfo) {
|
||||
throw new ApiException('server is not exist', 500);
|
||||
};
|
||||
}
|
||||
|
||||
// 后端获取用户
|
||||
public function user(Request $request)
|
||||
{
|
||||
ini_set('memory_limit', -1);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($this->nodeType) . '_LAST_CHECK_AT', $this->nodeInfo->id), time(), 3600);
|
||||
$users = $this->serverService->getAvailableUsers($this->nodeInfo->group_id);
|
||||
$users = $users->toArray();
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($request->input('node_type')) . '_LAST_CHECK_AT', $request->input('node_id')), time(), 3600);
|
||||
$users = ServerService::getAvailableUsers($request->input('node_info')->group_id)->toArray();
|
||||
|
||||
$response['users'] = $users;
|
||||
|
||||
$eTag = sha1(json_encode($response));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false) {
|
||||
return response(null, 304);
|
||||
};
|
||||
}
|
||||
|
||||
return response($response)->header('ETag', "\"{$eTag}\"");
|
||||
}
|
||||
@ -51,14 +33,18 @@ class UniProxyController extends Controller
|
||||
// 后端提交数据
|
||||
public function push(Request $request)
|
||||
{
|
||||
$data = get_request_content();
|
||||
$data = json_decode($data, true);
|
||||
$data = $request->validate([
|
||||
"*.0" => 'integer',
|
||||
"*.1" => 'integer'
|
||||
]);
|
||||
|
||||
$nodeType = $request->input('node_type');
|
||||
$nodeId = $request->input('node_id');
|
||||
// 增加单节点多服务器统计在线人数
|
||||
$ip = $request->ip();
|
||||
$id = $request->input("id");
|
||||
$time = time();
|
||||
$cacheKey = CacheKey::get('MULTI_SERVER_' . strtoupper($this->nodeType) . '_ONLINE_USER', $this->nodeInfo->id);
|
||||
$cacheKey = CacheKey::get('MULTI_SERVER_' . strtoupper($nodeType) . '_ONLINE_USER', $nodeId);
|
||||
|
||||
// 1、获取节点节点在线人数缓存
|
||||
$onlineUsers = Cache::get($cacheKey) ?? [];
|
||||
@ -87,83 +73,84 @@ class UniProxyController extends Controller
|
||||
Cache::put($cacheKey, $onlineUsers, 3600);
|
||||
|
||||
$online_user = $onlineCollection->sum('online_user');
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($this->nodeType) . '_ONLINE_USER', $this->nodeInfo->id), $online_user, 3600);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($this->nodeType) . '_LAST_PUSH_AT', $this->nodeInfo->id), time(), 3600);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($nodeType) . '_ONLINE_USER', $nodeId), $online_user, 3600);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($nodeType) . '_LAST_PUSH_AT', $nodeId), time(), 3600);
|
||||
$userService = new UserService();
|
||||
$userService->trafficFetch($this->nodeInfo->toArray(), $this->nodeType, $data , $ip);
|
||||
|
||||
$userService->trafficFetch($request->input('node_info')->toArray(), $nodeType, $data, $ip);
|
||||
return $this->success(true);
|
||||
}
|
||||
|
||||
// 后端获取配置
|
||||
public function config(Request $request)
|
||||
{
|
||||
switch ($this->nodeType) {
|
||||
$nodeType = $request->input('node_type');
|
||||
$nodeInfo = $request->input('node_info');
|
||||
switch ($nodeType) {
|
||||
case 'shadowsocks':
|
||||
$response = [
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'cipher' => $this->nodeInfo->cipher,
|
||||
'obfs' => $this->nodeInfo->obfs,
|
||||
'obfs_settings' => $this->nodeInfo->obfs_settings
|
||||
'server_port' => $nodeInfo->server_port,
|
||||
'cipher' => $nodeInfo->cipher,
|
||||
'obfs' => $nodeInfo->obfs,
|
||||
'obfs_settings' => $nodeInfo->obfs_settings
|
||||
];
|
||||
|
||||
if ($this->nodeInfo->cipher === '2022-blake3-aes-128-gcm') {
|
||||
$response['server_key'] = Helper::getServerKey($this->nodeInfo->created_at, 16);
|
||||
if ($nodeInfo->cipher === '2022-blake3-aes-128-gcm') {
|
||||
$response['server_key'] = Helper::getServerKey($nodeInfo->created_at, 16);
|
||||
}
|
||||
if ($this->nodeInfo->cipher === '2022-blake3-aes-256-gcm') {
|
||||
$response['server_key'] = Helper::getServerKey($this->nodeInfo->created_at, 32);
|
||||
if ($nodeInfo->cipher === '2022-blake3-aes-256-gcm') {
|
||||
$response['server_key'] = Helper::getServerKey($nodeInfo->created_at, 32);
|
||||
}
|
||||
break;
|
||||
case 'vmess':
|
||||
$response = [
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'network' => $this->nodeInfo->network,
|
||||
'networkSettings' => $this->nodeInfo->networkSettings,
|
||||
'tls' => $this->nodeInfo->tls
|
||||
'server_port' => $nodeInfo->server_port,
|
||||
'network' => $nodeInfo->network,
|
||||
'networkSettings' => $nodeInfo->networkSettings,
|
||||
'tls' => $nodeInfo->tls
|
||||
];
|
||||
break;
|
||||
case 'trojan':
|
||||
$response = [
|
||||
'host' => $this->nodeInfo->host,
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'server_name' => $this->nodeInfo->server_name,
|
||||
'network' => $this->nodeInfo->network,
|
||||
'networkSettings' => $this->nodeInfo->networkSettings,
|
||||
'host' => $nodeInfo->host,
|
||||
'server_port' => $nodeInfo->server_port,
|
||||
'server_name' => $nodeInfo->server_name,
|
||||
'network' => $nodeInfo->network,
|
||||
'networkSettings' => $nodeInfo->networkSettings,
|
||||
];
|
||||
break;
|
||||
case 'hysteria':
|
||||
$response = [
|
||||
'version' => $this->nodeInfo->version,
|
||||
'host' => $this->nodeInfo->host,
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'server_name' => $this->nodeInfo->server_name,
|
||||
'up_mbps' => $this->nodeInfo->up_mbps,
|
||||
'down_mbps' => $this->nodeInfo->down_mbps,
|
||||
'obfs' => $this->nodeInfo->is_obfs ? Helper::getServerKey($this->nodeInfo->created_at, 16) : null
|
||||
'version' => $nodeInfo->version,
|
||||
'host' => $nodeInfo->host,
|
||||
'server_port' => $nodeInfo->server_port,
|
||||
'server_name' => $nodeInfo->server_name,
|
||||
'up_mbps' => $nodeInfo->up_mbps,
|
||||
'down_mbps' => $nodeInfo->down_mbps,
|
||||
'obfs' => $nodeInfo->is_obfs ? Helper::getServerKey($nodeInfo->created_at, 16) : null
|
||||
];
|
||||
break;
|
||||
case "vless":
|
||||
$response = [
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'network' => $this->nodeInfo->network,
|
||||
'network_settings' => $this->nodeInfo->network_settings,
|
||||
'networkSettings' => $this->nodeInfo->network_settings,
|
||||
'tls' => $this->nodeInfo->tls,
|
||||
'flow' => $this->nodeInfo->flow,
|
||||
'tls_settings' => $this->nodeInfo->tls_settings
|
||||
'server_port' => $nodeInfo->server_port,
|
||||
'network' => $nodeInfo->network,
|
||||
'network_settings' => $nodeInfo->network_settings,
|
||||
'networkSettings' => $nodeInfo->network_settings,
|
||||
'tls' => $nodeInfo->tls,
|
||||
'flow' => $nodeInfo->flow,
|
||||
'tls_settings' => $nodeInfo->tls_settings
|
||||
];
|
||||
break;
|
||||
}
|
||||
$response['base_config'] = [
|
||||
'push_interval' => (int)admin_setting('server_push_interval', 60),
|
||||
'pull_interval' => (int)admin_setting('server_pull_interval', 60)
|
||||
'push_interval' => (int) admin_setting('server_push_interval', 60),
|
||||
'pull_interval' => (int) admin_setting('server_pull_interval', 60)
|
||||
];
|
||||
if ($this->nodeInfo['route_id']) {
|
||||
$response['routes'] = $this->serverService->getRoutes($this->nodeInfo['route_id']);
|
||||
if ($nodeInfo['route_id']) {
|
||||
$response['routes'] = ServerService::getRoutes($nodeInfo['route_id']);
|
||||
}
|
||||
$eTag = sha1(json_encode($response));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
return response(null,304);
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false) {
|
||||
return response(null, 304);
|
||||
}
|
||||
|
||||
return response($response)->header('ETag', "\"{$eTag}\"");
|
||||
|
@ -73,7 +73,7 @@ class TicketController extends Controller
|
||||
if (!$ticket) {
|
||||
return $this->fail([400202,'工单不存在']);
|
||||
}
|
||||
$ticket->status = 1;
|
||||
$ticket->status = Ticket::STATUS_CLOSED;
|
||||
if (!$ticket->save()) {
|
||||
return $this->fail([500, '工单关闭失败']);
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ use App\Models\User;
|
||||
use App\Services\ServerService;
|
||||
use App\Services\UserService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
@ -19,8 +17,7 @@ class ServerController extends Controller
|
||||
$servers = [];
|
||||
$userService = new UserService();
|
||||
if ($userService->isAvailable($user)) {
|
||||
$serverService = new ServerService();
|
||||
$servers = $serverService->getAvailableServers($user);
|
||||
$servers = ServerService::getAvailableServers($user);
|
||||
}
|
||||
$eTag = sha1(json_encode(array_column($servers, 'cache_key')));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
|
@ -118,7 +118,7 @@ class TicketController extends Controller
|
||||
if (!$ticket) {
|
||||
return $this->fail([400, __('Ticket does not exist')]);
|
||||
}
|
||||
$ticket->status = 1;
|
||||
$ticket->status = Ticket::STATUS_CLOSED;
|
||||
if (!$ticket->save()) {
|
||||
return $this->fail([500, __('Close failed')]);
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ class Kernel extends HttpKernel
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewareAliases = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
@ -83,7 +82,6 @@ class Kernel extends HttpKernel
|
||||
protected $middlewarePriority = [
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\Authenticate::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
|
||||
class Authenticate extends Middleware
|
||||
{
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (!$request->expectsJson()) {
|
||||
return route('login');
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Services\ServerService;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@ -22,27 +24,22 @@ class Server
|
||||
'hysteria2' => 'hysteria'
|
||||
];
|
||||
$request->validate([
|
||||
'token' => ['required','string',function ($attribute, $value, $fail) {
|
||||
if ($value != admin_setting('server_token')) {
|
||||
$fail("The $attribute is error.");
|
||||
}
|
||||
}],
|
||||
'token' => ['required', 'string', 'in:' . admin_setting('server_token')],
|
||||
'node_id' => 'required',
|
||||
'node_type' => [
|
||||
'nullable',
|
||||
'string',
|
||||
'regex:/^(?i)(hysteria|hysteria2|vless|trojan|vmess|v2ray|tuic|shadowsocks|shadowsocks-plugin)$/',
|
||||
function ($attribute, $value, $fail)use($aliasTypes) {
|
||||
// 将值转换为小写
|
||||
request()->merge([$attribute => strtolower($value)]);
|
||||
// 类别别名
|
||||
if (in_array($value, array_keys($aliasTypes))){
|
||||
request()->merge([$attribute => $aliasTypes[$value]]);
|
||||
}
|
||||
function ($attribute, $value, $fail) use ($aliasTypes, $request) {
|
||||
$request->merge([$attribute => strtolower(isset ($aliasTypes[$value]) ? $aliasTypes[$value] : $value)]);
|
||||
},
|
||||
]
|
||||
], [
|
||||
'token.in' => 'Token is error!',
|
||||
'node_type.regex' => 'node_type is error!'
|
||||
]);
|
||||
|
||||
$nodeInfo = ServerService::getServer($request->input('node_id'), $request->input('node_type'));
|
||||
if (!$nodeInfo)
|
||||
throw new ApiException('server is not exist!');
|
||||
$request->merge(['node_info' => $nodeInfo]);
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
<?php
|
||||
namespace App\Http\Routes\V1;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Http\Controllers\V1\Server\DeepbworkController;
|
||||
use App\Http\Controllers\V1\Server\ShadowsocksTidalabController;
|
||||
use App\Http\Controllers\V1\Server\TrojanTidalabController;
|
||||
use App\Http\Controllers\V1\Server\UniProxyController;
|
||||
use Illuminate\Contracts\Routing\Registrar;
|
||||
|
||||
class ServerRoute
|
||||
@ -12,13 +15,25 @@ class ServerRoute
|
||||
'prefix' => 'server',
|
||||
'middleware' => 'server'
|
||||
], function ($router) {
|
||||
$router->any('/{class}/{action}', function($class, $action) {
|
||||
$controllerClass = "\\App\\Http\\Controllers\\V1\\Server\\" . ucfirst($class) . "Controller";
|
||||
if(!(class_exists($controllerClass) && method_exists($controllerClass, $action))){
|
||||
throw new ApiException('Not Found',404);
|
||||
};
|
||||
$ctrl = \App::make($controllerClass);
|
||||
return \App::call([$ctrl, $action]);
|
||||
$router->prefix('UniProxy')->group(function ($route) {
|
||||
$route->get('config', [UniProxyController::class, 'config']);
|
||||
$route->get('user', [UniProxyController::class, 'user']);
|
||||
$route->post('push', [UniProxyController::class, 'push']);
|
||||
$route->post('alive', [UniProxyController::class, 'alive']);
|
||||
});
|
||||
$router->prefix('Deepbwork')->group(function ($route) {
|
||||
$route->get('config', [DeepbworkController::class, 'config']);
|
||||
$route->get('user', [DeepbworkController::class, 'user']);
|
||||
$route->post('submit', [DeepbworkController::class, 'submit']);
|
||||
});
|
||||
$router->prefix('ShadowsocksTidalab')->group(function ($route) {
|
||||
$route->get('user', [ShadowsocksTidalabController::class, 'user']);
|
||||
$route->post('submit', [ShadowsocksTidalabController::class, 'submit']);
|
||||
});
|
||||
$router->prefix('TrojanTidalab')->group(function ($route) {
|
||||
$route->get('config', [TrojanTidalabController::class, 'config']);
|
||||
$route->get('user', [TrojanTidalabController::class, 'user']);
|
||||
$route->post('submit', [TrojanTidalabController::class, 'submit']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2,14 +2,12 @@
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
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;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Models\MailLog;
|
||||
|
||||
class SendEmailJob implements ShouldQueue
|
||||
{
|
||||
@ -36,40 +34,9 @@ class SendEmailJob implements ShouldQueue
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (admin_setting('email_host')) {
|
||||
Config::set('mail.host', admin_setting('email_host', config('mail.host')));
|
||||
Config::set('mail.port', admin_setting('email_port', config('mail.port')));
|
||||
Config::set('mail.encryption', admin_setting('email_encryption', config('mail.encryption')));
|
||||
Config::set('mail.username', admin_setting('email_username', config('mail.username')));
|
||||
Config::set('mail.password', admin_setting('email_password', config('mail.password')));
|
||||
Config::set('mail.from.address', admin_setting('email_from_address', config('mail.from.address')));
|
||||
Config::set('mail.from.name', admin_setting('app_name', 'XBoard'));
|
||||
$mailLog = MailService::sendEmail($this->params);
|
||||
if($mailLog['error']){
|
||||
$this->release(); //发送失败将触发重试
|
||||
}
|
||||
$params = $this->params;
|
||||
$email = $params['email'];
|
||||
$subject = $params['subject'];
|
||||
$params['template_name'] = 'mail.' . admin_setting('email_template', 'default') . '.' . $params['template_name'];
|
||||
try {
|
||||
Mail::send(
|
||||
$params['template_name'],
|
||||
$params['template_value'],
|
||||
function ($message) use ($email, $subject) {
|
||||
$message->to($email)->subject($subject);
|
||||
}
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
|
||||
$log = [
|
||||
'email' => $params['email'],
|
||||
'subject' => $params['subject'],
|
||||
'template_name' => $params['template_name'],
|
||||
'error' => isset($error) ? $error : NULL
|
||||
];
|
||||
|
||||
MailLog::create($log);
|
||||
$log['config'] = config('mail');
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\MailService;
|
||||
use App\Services\ServerService;
|
||||
use App\Services\StatisticalService;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
@ -14,4 +14,30 @@ class Order extends Model
|
||||
'updated_at' => 'timestamp',
|
||||
'surplus_order_ids' => 'array'
|
||||
];
|
||||
|
||||
const STATUS_PENDING = 0; // 待支付
|
||||
const STATUS_PROCESSING = 1; // 开通中
|
||||
const STATUS_CANCELLED = 2; // 已取消
|
||||
const STATUS_COMPLETED = 3; // 已完成
|
||||
const STATUS_DISCOUNTED = 4; // 已折抵
|
||||
|
||||
public static $statusMap = [
|
||||
self::STATUS_PENDING => '待支付',
|
||||
self::STATUS_PROCESSING => '开通中',
|
||||
self::STATUS_CANCELLED => '已取消',
|
||||
self::STATUS_COMPLETED => '已完成',
|
||||
self::STATUS_DISCOUNTED => '已折抵',
|
||||
];
|
||||
|
||||
const TYPE_NEW_PURCHASE = 1; // 新购
|
||||
const TYPE_RENEWAL = 2; // 续费
|
||||
const TYPE_UPGRADE = 3; // 升级
|
||||
const TYPE_RESET_TRAFFIC = 4; //流量重置包
|
||||
public static $typeMap = [
|
||||
self::TYPE_NEW_PURCHASE => '新购',
|
||||
self::TYPE_RENEWAL => '续费',
|
||||
self::TYPE_UPGRADE => '升级',
|
||||
self::TYPE_RESET_TRAFFIC => '流量重置',
|
||||
];
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,12 @@ class Ticket extends Model
|
||||
'updated_at' => 'timestamp'
|
||||
];
|
||||
|
||||
const STATUS_OPENING = 0;
|
||||
const STATUS_CLOSED = 1;
|
||||
public static $statusMap = [
|
||||
self::STATUS_OPENING => '开启',
|
||||
self::STATUS_CLOSED => '关闭'
|
||||
];
|
||||
|
||||
public function message()
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ namespace App\Payments;
|
||||
use App\Exceptions\ApiException;
|
||||
|
||||
class AlipayF2F {
|
||||
protected $config;
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
@ -1,11 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
|
||||
|
||||
class BTCPay {
|
||||
public function __construct($config) {
|
||||
class BTCPay
|
||||
{
|
||||
protected $config;
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
@ -35,7 +39,8 @@ class BTCPay {
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order) {
|
||||
public function pay($order)
|
||||
{
|
||||
|
||||
$params = [
|
||||
'jsonResponse' => true,
|
||||
@ -52,7 +57,7 @@ class BTCPay {
|
||||
|
||||
$ret = @json_decode($ret_raw, true);
|
||||
|
||||
if(empty($ret['checkoutLink'])) {
|
||||
if (empty($ret['checkoutLink'])) {
|
||||
throw new ApiException("error!");
|
||||
}
|
||||
return [
|
||||
@ -61,7 +66,8 @@ class BTCPay {
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params) {
|
||||
public function notify($params)
|
||||
{
|
||||
$payload = trim(get_request_content());
|
||||
|
||||
$headers = getallheaders();
|
||||
@ -76,7 +82,7 @@ class BTCPay {
|
||||
$computedSignature = "sha256=" . \hash_hmac('sha256', $payload, $this->config['btcpay_webhook_key']);
|
||||
|
||||
if (!self::hashEqual($signraturHeader, $computedSignature)) {
|
||||
throw new ApiException('HMAC signature does not match',400);
|
||||
throw new ApiException('HMAC signature does not match', 400);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -93,16 +99,16 @@ class BTCPay {
|
||||
|
||||
|
||||
$out_trade_no = $invoiceDetail['metadata']["orderId"];
|
||||
$pay_trade_no=$json_param['invoiceId'];
|
||||
$pay_trade_no = $json_param['invoiceId'];
|
||||
return [
|
||||
'trade_no' => $out_trade_no,
|
||||
'callback_no' => $pay_trade_no
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function _curlPost($url,$params=false){
|
||||
private function _curlPost($url, $params = false)
|
||||
{
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
@ -111,7 +117,9 @@ class BTCPay {
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 300);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
|
||||
curl_setopt(
|
||||
$ch, CURLOPT_HTTPHEADER, array('Authorization:' .'token '.$this->config['btcpay_api_key'], 'Content-Type: application/json')
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
array('Authorization:' . 'token ' . $this->config['btcpay_api_key'], 'Content-Type: application/json')
|
||||
);
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
@ -143,6 +151,4 @@ class BTCPay {
|
||||
return !$ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
|
||||
class CoinPayments {
|
||||
public function __construct($config) {
|
||||
class CoinPayments
|
||||
{
|
||||
protected $config;
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
@ -99,7 +103,7 @@ class CoinPayments {
|
||||
throw new ApiException('Payment Timed Out or Error');
|
||||
} else {
|
||||
//payment is pending, you can optionally add a note to the order page
|
||||
return('IPN OK: pending');
|
||||
return ('IPN OK: pending');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
|
||||
class Coinbase {
|
||||
public function __construct($config) {
|
||||
class Coinbase
|
||||
{
|
||||
protected $config;
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
@ -29,7 +33,8 @@ class Coinbase {
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order) {
|
||||
public function pay($order)
|
||||
{
|
||||
|
||||
$params = [
|
||||
'name' => '订阅套餐',
|
||||
@ -50,7 +55,7 @@ class Coinbase {
|
||||
|
||||
$ret = @json_decode($ret_raw, true);
|
||||
|
||||
if(empty($ret['data']['hosted_url'])) {
|
||||
if (empty($ret['data']['hosted_url'])) {
|
||||
throw new ApiException("error!");
|
||||
}
|
||||
return [
|
||||
@ -59,7 +64,8 @@ class Coinbase {
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params) {
|
||||
public function notify($params)
|
||||
{
|
||||
|
||||
$payload = trim(get_request_content());
|
||||
$json_param = json_decode($payload, true);
|
||||
@ -71,20 +77,20 @@ class Coinbase {
|
||||
$computedSignature = \hash_hmac('sha256', $payload, $this->config['coinbase_webhook_key']);
|
||||
|
||||
if (!self::hashEqual($signatureHeader, $computedSignature)) {
|
||||
throw new ApiException( 'HMAC signature does not match', 400);
|
||||
throw new ApiException('HMAC signature does not match', 400);
|
||||
}
|
||||
|
||||
$out_trade_no = $json_param['event']['data']['metadata']['outTradeNo'];
|
||||
$pay_trade_no=$json_param['event']['id'];
|
||||
$pay_trade_no = $json_param['event']['id'];
|
||||
return [
|
||||
'trade_no' => $out_trade_no,
|
||||
'callback_no' => $pay_trade_no
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function _curlPost($url,$params=false){
|
||||
private function _curlPost($url, $params = false)
|
||||
{
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
@ -93,7 +99,9 @@ class Coinbase {
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 300);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
|
||||
curl_setopt(
|
||||
$ch, CURLOPT_HTTPHEADER, array('X-CC-Api-Key:' .$this->config['coinbase_api_key'], 'X-CC-Version: 2018-03-22')
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
array('X-CC-Api-Key:' . $this->config['coinbase_api_key'], 'X-CC-Version: 2018-03-22')
|
||||
);
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
@ -124,6 +132,4 @@ class Coinbase {
|
||||
return !$ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Payments;
|
||||
|
||||
class EPay {
|
||||
class EPay
|
||||
{
|
||||
protected $config;
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 自己写别抄,抄NMB抄
|
||||
*/
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Stripe\Source;
|
||||
use Stripe\Stripe;
|
||||
|
||||
class StripeAlipay {
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function form()
|
||||
{
|
||||
return [
|
||||
'currency' => [
|
||||
'label' => '货币单位',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_sk_live' => [
|
||||
'label' => 'SK_LIVE',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_webhook_key' => [
|
||||
'label' => 'WebHook密钥签名',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order)
|
||||
{
|
||||
$currency = $this->config['currency'];
|
||||
$exchange = $this->exchange('CNY', strtoupper($currency));
|
||||
if (!$exchange) {
|
||||
throw new ApiException(__('Currency conversion has timed out, please try again later'));
|
||||
}
|
||||
Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
$source = Source::create([
|
||||
'amount' => floor($order['total_amount'] * $exchange),
|
||||
'currency' => $currency,
|
||||
'type' => 'alipay',
|
||||
'statement_descriptor' => $order['trade_no'],
|
||||
'metadata' => [
|
||||
'user_id' => $order['user_id'],
|
||||
'out_trade_no' => $order['trade_no'],
|
||||
'identifier' => ''
|
||||
],
|
||||
'redirect' => [
|
||||
'return_url' => $order['return_url']
|
||||
]
|
||||
]);
|
||||
if (!$source['redirect']['url']) {
|
||||
throw new ApiException(__('Payment gateway request failed'));
|
||||
}
|
||||
return [
|
||||
'type' => 1,
|
||||
'data' => $source['redirect']['url']
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params)
|
||||
{
|
||||
\Stripe\Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
try {
|
||||
$event = \Stripe\Webhook::constructEvent(
|
||||
get_request_content(),
|
||||
request()->header('HTTP_STRIPE_SIGNATURE'),
|
||||
$this->config['stripe_webhook_key']
|
||||
);
|
||||
} catch (\Stripe\Error\SignatureVerification $e) {
|
||||
abort(400);
|
||||
}
|
||||
switch ($event->type) {
|
||||
case 'source.chargeable':
|
||||
$object = $event->data->object;
|
||||
\Stripe\Charge::create([
|
||||
'amount' => $object->amount,
|
||||
'currency' => $object->currency,
|
||||
'source' => $object->id,
|
||||
'metadata' => json_decode($object->metadata, true)
|
||||
]);
|
||||
break;
|
||||
case 'charge.succeeded':
|
||||
$object = $event->data->object;
|
||||
if ($object->status === 'succeeded') {
|
||||
if (!isset($object->metadata->out_trade_no) && !isset($object->source->metadata)) {
|
||||
return('order error');
|
||||
}
|
||||
$metaData = isset($object->metadata->out_trade_no) ? $object->metadata : $object->source->metadata;
|
||||
$tradeNo = $metaData->out_trade_no;
|
||||
return [
|
||||
'trade_no' => $tradeNo,
|
||||
'callback_no' => $object->id
|
||||
];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ApiException('event is not support');
|
||||
}
|
||||
return('success');
|
||||
}
|
||||
|
||||
private function exchange($from, $to)
|
||||
{
|
||||
$result = file_get_contents('https://api.exchangerate.host/latest?symbols=' . $to . '&base=' . $from);
|
||||
$result = json_decode($result, true);
|
||||
return $result['rates'][$to];
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Stripe\Stripe;
|
||||
use Stripe\Checkout\Session;
|
||||
|
||||
class StripeCheckout {
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function form()
|
||||
{
|
||||
return [
|
||||
'currency' => [
|
||||
'label' => '货币单位',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_sk_live' => [
|
||||
'label' => 'SK_LIVE',
|
||||
'description' => 'API 密钥',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_pk_live' => [
|
||||
'label' => 'PK_LIVE',
|
||||
'description' => 'API 公钥',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_webhook_key' => [
|
||||
'label' => 'WebHook 密钥签名',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_custom_field_name' => [
|
||||
'label' => '自定义字段名称',
|
||||
'description' => '例如可设置为“联系方式”,以便及时与客户取得联系',
|
||||
'type' => 'input',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order)
|
||||
{
|
||||
$currency = $this->config['currency'];
|
||||
$exchange = $this->exchange('CNY', strtoupper($currency));
|
||||
if (!$exchange) {
|
||||
throw new ApiException(__('Currency conversion has timed out, please try again later'));
|
||||
}
|
||||
$customFieldName = isset($this->config['stripe_custom_field_name']) ? $this->config['stripe_custom_field_name'] : 'Contact Infomation';
|
||||
|
||||
$params = [
|
||||
'success_url' => $order['return_url'],
|
||||
'cancel_url' => $order['return_url'],
|
||||
'client_reference_id' => $order['trade_no'],
|
||||
'line_items' => [
|
||||
[
|
||||
'price_data' => [
|
||||
'currency' => $currency,
|
||||
'product_data' => [
|
||||
'name' => $order['trade_no']
|
||||
],
|
||||
'unit_amount' => floor($order['total_amount'] * $exchange)
|
||||
],
|
||||
'quantity' => 1
|
||||
]
|
||||
],
|
||||
'mode' => 'payment',
|
||||
'invoice_creation' => ['enabled' => true],
|
||||
'phone_number_collection' => ['enabled' => true],
|
||||
'custom_fields' => [
|
||||
[
|
||||
'key' => 'contactinfo',
|
||||
'label' => ['type' => 'custom', 'custom' => $customFieldName],
|
||||
'type' => 'text',
|
||||
],
|
||||
],
|
||||
// 'customer_email' => $user['email'] not support
|
||||
|
||||
];
|
||||
|
||||
Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
try {
|
||||
$session = Session::create($params);
|
||||
} catch (\Exception $e) {
|
||||
info($e);
|
||||
throw new ApiException("Failed to create order. Error: {$e->getMessage}");
|
||||
}
|
||||
return [
|
||||
'type' => 1, // 0:qrcode 1:url
|
||||
'data' => $session->url
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params)
|
||||
{
|
||||
\Stripe\Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
try {
|
||||
$event = \Stripe\Webhook::constructEvent(
|
||||
get_request_content(),
|
||||
request()->header('HTTP_STRIPE_SIGNATURE'),
|
||||
$this->config['stripe_webhook_key']
|
||||
);
|
||||
} catch (\Stripe\Error\SignatureVerification $e) {
|
||||
abort(400);
|
||||
}
|
||||
|
||||
switch ($event->type) {
|
||||
case 'checkout.session.completed':
|
||||
$object = $event->data->object;
|
||||
if ($object->payment_status === 'paid') {
|
||||
return [
|
||||
'trade_no' => $object->client_reference_id,
|
||||
'callback_no' => $object->payment_intent
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'checkout.session.async_payment_succeeded':
|
||||
$object = $event->data->object;
|
||||
return [
|
||||
'trade_no' => $object->client_reference_id,
|
||||
'callback_no' => $object->payment_intent
|
||||
];
|
||||
break;
|
||||
default:
|
||||
throw new ApiException('event is not support');
|
||||
}
|
||||
return('success');
|
||||
}
|
||||
|
||||
private function exchange($from, $to)
|
||||
{
|
||||
$result = file_get_contents('https://api.exchangerate.host/latest?symbols=' . $to . '&base=' . $from);
|
||||
$result = json_decode($result, true);
|
||||
return $result['rates'][$to];
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 自己写别抄,抄NMB抄
|
||||
*/
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Stripe\Source;
|
||||
use Stripe\Stripe;
|
||||
|
||||
class StripeCredit {
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function form()
|
||||
{
|
||||
return [
|
||||
'currency' => [
|
||||
'label' => '货币单位',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_sk_live' => [
|
||||
'label' => 'SK_LIVE',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_pk_live' => [
|
||||
'label' => 'PK_LIVE',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_webhook_key' => [
|
||||
'label' => 'WebHook密钥签名',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order)
|
||||
{
|
||||
info($order);
|
||||
$currency = $this->config['currency'];
|
||||
$exchange = $this->exchange('CNY', strtoupper($currency));
|
||||
if (!$exchange) {
|
||||
throw new ApiException(__('Currency conversion has timed out, please try again later'));
|
||||
}
|
||||
Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
try {
|
||||
$charge = \Stripe\Charge::create([
|
||||
'amount' => floor($order['total_amount'] * $exchange),
|
||||
'currency' => $currency,
|
||||
'source' => $order['stripe_token'],
|
||||
'metadata' => [
|
||||
'user_id' => $order['user_id'],
|
||||
'out_trade_no' => $order['trade_no'],
|
||||
'identifier' => ''
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
info($e);
|
||||
throw new ApiException(__('Payment failed. Please check your credit card information'));
|
||||
}
|
||||
if (!$charge->paid) {
|
||||
throw new ApiException(__('Payment failed. Please check your credit card information'));
|
||||
}
|
||||
return [
|
||||
'type' => 2,
|
||||
'data' => $charge->paid
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params)
|
||||
{
|
||||
\Stripe\Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
try {
|
||||
$event = \Stripe\Webhook::constructEvent(
|
||||
get_request_content(),
|
||||
request()->header('HTTP_STRIPE_SIGNATURE'),
|
||||
$this->config['stripe_webhook_key']
|
||||
);
|
||||
} catch (\Stripe\Error\SignatureVerification $e) {
|
||||
\Log::error($e);
|
||||
abort(400);
|
||||
}
|
||||
switch ($event->type) {
|
||||
case 'source.chargeable':
|
||||
$object = $event->data->object;
|
||||
\Stripe\Charge::create([
|
||||
'amount' => $object->amount,
|
||||
'currency' => $object->currency,
|
||||
'source' => $object->id,
|
||||
'metadata' => json_decode($object->metadata, true)
|
||||
]);
|
||||
break;
|
||||
case 'charge.succeeded':
|
||||
$object = $event->data->object;
|
||||
if ($object->status === 'succeeded') {
|
||||
if (!isset($object->metadata->out_trade_no) && !isset($object->source->metadata)) {
|
||||
return('order error');
|
||||
}
|
||||
$metaData = isset($object->metadata->out_trade_no) ? $object->metadata : $object->source->metadata;
|
||||
$tradeNo = $metaData->out_trade_no;
|
||||
return [
|
||||
'trade_no' => $tradeNo,
|
||||
'callback_no' => $object->id
|
||||
];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ApiException('event is not support');
|
||||
}
|
||||
return('success');
|
||||
}
|
||||
|
||||
private function exchange($from, $to)
|
||||
{
|
||||
$result = file_get_contents('https://api.exchangerate.host/latest?symbols=' . $to . '&base=' . $from);
|
||||
$result = json_decode($result, true);
|
||||
return $result['rates'][$to];
|
||||
}
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 自己写别抄,抄NMB抄
|
||||
*/
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Stripe\Source;
|
||||
use Stripe\Stripe;
|
||||
|
||||
class StripeWepay {
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function form()
|
||||
{
|
||||
return [
|
||||
'currency' => [
|
||||
'label' => '货币单位',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_sk_live' => [
|
||||
'label' => 'SK_LIVE',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'stripe_webhook_key' => [
|
||||
'label' => 'WebHook密钥签名',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order)
|
||||
{
|
||||
$currency = $this->config['currency'];
|
||||
$exchange = $this->exchange('CNY', strtoupper($currency));
|
||||
if (!$exchange) {
|
||||
throw new ApiException(__('Currency conversion has timed out, please try again later'));
|
||||
}
|
||||
Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
$source = Source::create([
|
||||
'amount' => floor($order['total_amount'] * $exchange),
|
||||
'currency' => $currency,
|
||||
'type' => 'wechat',
|
||||
'statement_descriptor' => $order['trade_no'],
|
||||
'metadata' => [
|
||||
'user_id' => $order['user_id'],
|
||||
'out_trade_no' => $order['trade_no'],
|
||||
'identifier' => ''
|
||||
],
|
||||
'redirect' => [
|
||||
'return_url' => $order['return_url']
|
||||
]
|
||||
]);
|
||||
if (!$source['wechat']['qr_code_url']) {
|
||||
throw new ApiException(__('Payment gateway request failed'));
|
||||
}
|
||||
return [
|
||||
'type' => 0,
|
||||
'data' => $source['wechat']['qr_code_url']
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params)
|
||||
{
|
||||
\Stripe\Stripe::setApiKey($this->config['stripe_sk_live']);
|
||||
try {
|
||||
$event = \Stripe\Webhook::constructEvent(
|
||||
get_request_content(),
|
||||
request()->header('HTTP_STRIPE_SIGNATURE'),
|
||||
$this->config['stripe_webhook_key']
|
||||
);
|
||||
} catch (\Stripe\Error\SignatureVerification $e) {
|
||||
abort(400);
|
||||
}
|
||||
switch ($event->type) {
|
||||
case 'source.chargeable':
|
||||
$object = $event->data->object;
|
||||
\Stripe\Charge::create([
|
||||
'amount' => $object->amount,
|
||||
'currency' => $object->currency,
|
||||
'source' => $object->id,
|
||||
'metadata' => json_decode($object->metadata, true)
|
||||
]);
|
||||
break;
|
||||
case 'charge.succeeded':
|
||||
$object = $event->data->object;
|
||||
if ($object->status === 'succeeded') {
|
||||
if (!isset($object->metadata->out_trade_no) && !isset($object->source->metadata)) {
|
||||
return('order error');
|
||||
}
|
||||
$metaData = isset($object->metadata->out_trade_no) ? $object->metadata : $object->source->metadata;
|
||||
$tradeNo = $metaData->out_trade_no;
|
||||
return [
|
||||
'trade_no' => $tradeNo,
|
||||
'callback_no' => $object->id
|
||||
];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ApiException('event is not support');
|
||||
}
|
||||
return('success');
|
||||
}
|
||||
|
||||
private function exchange($from, $to)
|
||||
{
|
||||
$result = file_get_contents('https://api.exchangerate.host/latest?symbols=' . $to . '&base=' . $from);
|
||||
$result = json_decode($result, true);
|
||||
return $result['rates'][$to];
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Payments;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Omnipay\Omnipay;
|
||||
use Omnipay\WechatPay\Helper;
|
||||
|
||||
class WechatPayNative {
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function form()
|
||||
{
|
||||
return [
|
||||
'app_id' => [
|
||||
'label' => 'APPID',
|
||||
'description' => '绑定微信支付商户的APPID',
|
||||
'type' => 'input',
|
||||
],
|
||||
'mch_id' => [
|
||||
'label' => '商户号',
|
||||
'description' => '微信支付商户号',
|
||||
'type' => 'input',
|
||||
],
|
||||
'api_key' => [
|
||||
'label' => 'APIKEY(v1)',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function pay($order)
|
||||
{
|
||||
$gateway = Omnipay::create('WechatPay_Native');
|
||||
$gateway->setAppId($this->config['app_id']);
|
||||
$gateway->setMchId($this->config['mch_id']);
|
||||
$gateway->setApiKey($this->config['api_key']);
|
||||
$gateway->setNotifyUrl($order['notify_url']);
|
||||
|
||||
$params = [
|
||||
'body' => $order['trade_no'],
|
||||
'out_trade_no' => $order['trade_no'],
|
||||
'total_fee' => $order['total_amount'],
|
||||
'spbill_create_ip' => '0.0.0.0',
|
||||
'fee_type' => 'CNY'
|
||||
];
|
||||
|
||||
$request = $gateway->purchase($params);
|
||||
$response = $request->send();
|
||||
$response = $response->getData();
|
||||
if ($response['return_code'] !== 'SUCCESS') {
|
||||
throw new ApiException($response['return_msg']);
|
||||
}
|
||||
return [
|
||||
'type' => 0,
|
||||
'data' => $response['code_url'],
|
||||
'custom_result' => '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'
|
||||
];
|
||||
}
|
||||
|
||||
public function notify($params)
|
||||
{
|
||||
$data = Helper::xml2array(get_request_content());
|
||||
$gateway = Omnipay::create('WechatPay');
|
||||
$gateway->setAppId($this->config['app_id']);
|
||||
$gateway->setMchId($this->config['mch_id']);
|
||||
$gateway->setApiKey($this->config['api_key']);
|
||||
$response = $gateway->completePurchase([
|
||||
'request_params' => get_request_content()
|
||||
])->send();
|
||||
|
||||
if (!$response->isPaid()) {
|
||||
return('FAIL');
|
||||
}
|
||||
|
||||
return [
|
||||
'trade_no' => $data['out_trade_no'],
|
||||
'callback_no' => $data['transaction_id']
|
||||
];
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace App\Providers;
|
||||
|
||||
use App\Support\Setting;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
|
||||
class SettingServiceProvider extends ServiceProvider
|
||||
{
|
||||
@ -14,9 +15,11 @@ class SettingServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->bind('setting', function ($app) {
|
||||
return Setting::fromDatabase(); // 假设 AdminSetting 是您的设置类
|
||||
|
||||
$this->app->bind(Setting::class, function (Application $app) {
|
||||
return new Setting();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,6 +29,5 @@ class SettingServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,17 @@ use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class MailService
|
||||
{
|
||||
public function remindTraffic (User $user)
|
||||
public function remindTraffic(User $user)
|
||||
{
|
||||
if (!$user->remind_traffic) return;
|
||||
if (!$this->remindTrafficIsWarnValue($user->u, $user->d, $user->transfer_enable)) return;
|
||||
if (!$user->remind_traffic)
|
||||
return;
|
||||
if (!$this->remindTrafficIsWarnValue($user->u, $user->d, $user->transfer_enable))
|
||||
return;
|
||||
$flag = CacheKey::get('LAST_SEND_EMAIL_REMIND_TRAFFIC', $user->id);
|
||||
if (Cache::get($flag)) return;
|
||||
if (!Cache::put($flag, 1, 24 * 3600)) return;
|
||||
if (Cache::get($flag))
|
||||
return;
|
||||
if (!Cache::put($flag, 1, 24 * 3600))
|
||||
return;
|
||||
SendEmailJob::dispatch([
|
||||
'email' => $user->email,
|
||||
'subject' => __('The traffic usage in :app_name has reached 80%', [
|
||||
@ -31,7 +35,8 @@ class MailService
|
||||
|
||||
public function remindExpire(User $user)
|
||||
{
|
||||
if (!($user->expired_at !== NULL && ($user->expired_at - 86400) < time() && $user->expired_at > time())) return;
|
||||
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', [
|
||||
@ -48,11 +53,67 @@ class MailService
|
||||
private function remindTrafficIsWarnValue($u, $d, $transfer_enable)
|
||||
{
|
||||
$ud = $u + $d;
|
||||
if (!$ud) return false;
|
||||
if (!$transfer_enable) return false;
|
||||
if (!$ud)
|
||||
return false;
|
||||
if (!$transfer_enable)
|
||||
return false;
|
||||
$percentage = ($ud / $transfer_enable) * 100;
|
||||
if ($percentage < 80) return false;
|
||||
if ($percentage >= 100) return false;
|
||||
if ($percentage < 80)
|
||||
return false;
|
||||
if ($percentage >= 100)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
*
|
||||
* @param array $params 包含邮件参数的数组,必须包含以下字段:
|
||||
* - email: 收件人邮箱地址
|
||||
* - subject: 邮件主题
|
||||
* - template_name: 邮件模板名称,例如 "welcome" 或 "password_reset"
|
||||
* - template_value: 邮件模板变量,一个关联数组,包含模板中需要替换的变量和对应的值
|
||||
* @return array 包含邮件发送结果的数组,包含以下字段:
|
||||
* - email: 收件人邮箱地址
|
||||
* - subject: 邮件主题
|
||||
* - template_name: 邮件模板名称
|
||||
* - error: 如果邮件发送失败,包含错误信息;否则为 null
|
||||
* @throws \InvalidArgumentException 如果 $params 参数缺少必要的字段,抛出此异常
|
||||
*/
|
||||
public static function sendEmail(array $params)
|
||||
{
|
||||
if (admin_setting('email_host')) {
|
||||
\Config::set('mail.host', admin_setting('email_host', config('mail.host')));
|
||||
\Config::set('mail.port', admin_setting('email_port', config('mail.port')));
|
||||
\Config::set('mail.encryption', admin_setting('email_encryption', config('mail.encryption')));
|
||||
\Config::set('mail.username', admin_setting('email_username', config('mail.username')));
|
||||
\Config::set('mail.password', admin_setting('email_password', config('mail.password')));
|
||||
\Config::set('mail.from.address', admin_setting('email_from_address', config('mail.from.address')));
|
||||
\Config::set('mail.from.name', admin_setting('app_name', 'XBoard'));
|
||||
}
|
||||
$email = $params['email'];
|
||||
$subject = $params['subject'];
|
||||
$params['template_name'] = 'mail.' . admin_setting('email_template', 'default') . '.' . $params['template_name'];
|
||||
try {
|
||||
\Mail::send(
|
||||
$params['template_name'],
|
||||
$params['template_value'],
|
||||
function ($message) use ($email, $subject) {
|
||||
$message->to($email)->subject($subject);
|
||||
}
|
||||
);
|
||||
$error = null;
|
||||
} catch (\Exception $e) {
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
$log = [
|
||||
'email' => $params['email'],
|
||||
'subject' => $params['subject'],
|
||||
'template_name' => $params['template_name'],
|
||||
'error' => $error,
|
||||
'config' => config('mail')
|
||||
];
|
||||
\App\Models\MailLog::create($log);
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ class OrderService
|
||||
DB::beginTransaction();
|
||||
if ($order->surplus_order_ids) {
|
||||
Order::whereIn('id', $order->surplus_order_ids)->update([
|
||||
'status' => 4
|
||||
'status' => Order::STATUS_DISCOUNTED
|
||||
]);
|
||||
}
|
||||
switch ((string)$order->period) {
|
||||
@ -71,7 +71,7 @@ class OrderService
|
||||
if (!$this->user->save()) {
|
||||
throw new \Exception('用户信息保存失败');
|
||||
}
|
||||
$order->status = 3;
|
||||
$order->status = Order::STATUS_COMPLETED;
|
||||
if (!$order->save()) {
|
||||
throw new \Exception('订单信息保存失败');
|
||||
}
|
||||
@ -88,10 +88,10 @@ class OrderService
|
||||
{
|
||||
$order = $this->order;
|
||||
if ($order->period === 'reset_price') {
|
||||
$order->type = 4;
|
||||
$order->type = Order::TYPE_RESET_TRAFFIC;
|
||||
} else if ($user->plan_id !== NULL && $order->plan_id !== $user->plan_id && ($user->expired_at > time() || $user->expired_at === NULL)) {
|
||||
if (!(int)admin_setting('plan_change_enable', 1)) throw new ApiException('目前不允许更改订阅,请联系客服或提交工单操作');
|
||||
$order->type = 3;
|
||||
$order->type = Order::TYPE_UPGRADE;
|
||||
if ((int)admin_setting('surplus_enable', 1)) $this->getSurplusValue($user, $order);
|
||||
if ($order->surplus_amount >= $order->total_amount) {
|
||||
$order->refund_amount = $order->surplus_amount - $order->total_amount;
|
||||
@ -100,9 +100,9 @@ class OrderService
|
||||
$order->total_amount = $order->total_amount - $order->surplus_amount;
|
||||
}
|
||||
} else if ($user->expired_at > time() && $order->plan_id == $user->plan_id) { // 用户订阅未过期且购买订阅与当前订阅相同 === 续费
|
||||
$order->type = 2;
|
||||
$order->type = Order::TYPE_RENEWAL;
|
||||
} else { // 新购
|
||||
$order->type = 1;
|
||||
$order->type = Order::TYPE_NEW_PURCHASE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,8 +215,8 @@ class OrderService
|
||||
public function paid(string $callbackNo)
|
||||
{
|
||||
$order = $this->order;
|
||||
if ($order->status !== 0) return true;
|
||||
$order->status = 1;
|
||||
if ($order->status !== Order::STATUS_PENDING) return true;
|
||||
$order->status = Order::STATUS_PROCESSING;
|
||||
$order->paid_at = time();
|
||||
$order->callback_no = $callbackNo;
|
||||
if (!$order->save()) return false;
|
||||
@ -233,7 +233,7 @@ class OrderService
|
||||
$order = $this->order;
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$order->status = 2;
|
||||
$order->status = Order::STATUS_CANCELLED;
|
||||
if (!$order->save()) {
|
||||
throw new \Exception('Failed to save order status.');
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ServerService
|
||||
{
|
||||
public function getAvailableVless(User $user):array
|
||||
// 获取可用的 VLESS 服务器列表
|
||||
public static function getAvailableVless(User $user): array
|
||||
{
|
||||
$servers = [];
|
||||
$model = ServerVless::orderBy('sort', 'ASC');
|
||||
@ -45,11 +46,11 @@ class ServerService
|
||||
$servers[] = $serverData;
|
||||
}
|
||||
|
||||
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAvailableVmess(User $user):array
|
||||
// 获取可用的 VMESS 服务器列表
|
||||
public static function getAvailableVmess(User $user): array
|
||||
{
|
||||
$servers = [];
|
||||
$model = ServerVmess::orderBy('sort', 'ASC');
|
||||
@ -69,11 +70,11 @@ class ServerService
|
||||
$servers[] = $vmess[$key]->toArray();
|
||||
}
|
||||
|
||||
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAvailableTrojan(User $user):array
|
||||
// 获取可用的 TROJAN 服务器列表
|
||||
public static function getAvailableTrojan(User $user): array
|
||||
{
|
||||
$servers = [];
|
||||
$model = ServerTrojan::orderBy('sort', 'ASC');
|
||||
@ -95,7 +96,8 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAvailableHysteria(User $user)
|
||||
// 获取可用的 HYSTERIA 服务器列表
|
||||
public static function getAvailableHysteria(User $user)
|
||||
{
|
||||
$availableServers = [];
|
||||
$model = ServerHysteria::orderBy('sort', 'ASC');
|
||||
@ -119,7 +121,8 @@ class ServerService
|
||||
return $availableServers;
|
||||
}
|
||||
|
||||
public function getAvailableShadowsocks(User $user)
|
||||
// 获取可用的 SHADOWSOCKS 服务器列表
|
||||
public static function getAvailableShadowsocks(User $user)
|
||||
{
|
||||
$servers = [];
|
||||
$model = ServerShadowsocks::orderBy('sort', 'ASC');
|
||||
@ -141,15 +144,16 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAvailableServers(User $user)
|
||||
// 获取可用的服务器列表
|
||||
public static function getAvailableServers(User $user)
|
||||
{
|
||||
$servers = Cache::remember('serversAvailable_'. $user->id, 5, function() use($user){
|
||||
return array_merge(
|
||||
$this->getAvailableShadowsocks($user),
|
||||
$this->getAvailableVmess($user),
|
||||
$this->getAvailableTrojan($user),
|
||||
$this->getAvailableHysteria($user),
|
||||
$this->getAvailableVless($user)
|
||||
self::getAvailableShadowsocks($user),
|
||||
self::getAvailableVmess($user),
|
||||
self::getAvailableTrojan($user),
|
||||
self::getAvailableHysteria($user),
|
||||
self::getAvailableVless($user)
|
||||
);
|
||||
});
|
||||
$tmp = array_column($servers, 'sort');
|
||||
@ -162,7 +166,8 @@ class ServerService
|
||||
}, $servers);
|
||||
}
|
||||
|
||||
public function getAvailableUsers($groupId): Collection
|
||||
// 获取可用的用户列表
|
||||
public static function getAvailableUsers($groupId): Collection
|
||||
{
|
||||
return \DB::table('v2_user')
|
||||
->whereIn('group_id', $groupId)
|
||||
@ -180,7 +185,8 @@ class ServerService
|
||||
->get();
|
||||
}
|
||||
|
||||
public function log(int $userId, int $serverId, int $u, int $d, float $rate, string $method)
|
||||
// 记录流量日志
|
||||
public static function log(int $userId, int $serverId, int $u, int $d, float $rate, string $method)
|
||||
{
|
||||
if (($u + $d) < 10240) return true;
|
||||
$timestamp = strtotime(date('Y-m-d'));
|
||||
@ -212,7 +218,8 @@ class ServerService
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllShadowsocks()
|
||||
// 获取所有 SHADOWSOCKS 服务器列表
|
||||
public static function getAllShadowsocks()
|
||||
{
|
||||
$servers = ServerShadowsocks::orderBy('sort', 'ASC')
|
||||
->get()
|
||||
@ -223,7 +230,8 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAllVMess()
|
||||
// 获取所有 VMESS 服务器列表
|
||||
public static function getAllVMess()
|
||||
{
|
||||
$servers = ServerVmess::orderBy('sort', 'ASC')
|
||||
->get()
|
||||
@ -234,7 +242,8 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAllVLess()
|
||||
// 获取所有 VLESS 服务器列表
|
||||
public static function getAllVLess()
|
||||
{
|
||||
$servers = ServerVless::orderBy('sort', 'ASC')
|
||||
->get()
|
||||
@ -245,7 +254,8 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAllTrojan()
|
||||
// 获取所有 TROJAN 服务器列表
|
||||
public static function getAllTrojan()
|
||||
{
|
||||
$servers = ServerTrojan::orderBy('sort', 'ASC')
|
||||
->get()
|
||||
@ -256,7 +266,8 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getAllHysteria()
|
||||
// 获取所有 HYSTERIA 服务器列表
|
||||
public static function getAllHysteria()
|
||||
{
|
||||
$servers = ServerHysteria::orderBy('sort', 'ASC')
|
||||
->get()
|
||||
@ -267,7 +278,8 @@ class ServerService
|
||||
return $servers;
|
||||
}
|
||||
|
||||
private function mergeData(&$servers)
|
||||
// 合并数据
|
||||
private static function mergeData(&$servers)
|
||||
{
|
||||
foreach ($servers as $k => $v) {
|
||||
$serverType = strtoupper($v['type']);
|
||||
@ -291,22 +303,24 @@ class ServerService
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllServers()
|
||||
// 获取所有服务器列表
|
||||
public static function getAllServers()
|
||||
{
|
||||
$servers = array_merge(
|
||||
$this->getAllShadowsocks(),
|
||||
$this->getAllVMess(),
|
||||
$this->getAllTrojan(),
|
||||
$this->getAllHysteria(),
|
||||
$this->getAllVLess()
|
||||
self::getAllShadowsocks(),
|
||||
self::getAllVMess(),
|
||||
self::getAllTrojan(),
|
||||
self::getAllHysteria(),
|
||||
self::getAllVLess()
|
||||
);
|
||||
$this->mergeData($servers);
|
||||
self::mergeData($servers);
|
||||
$tmp = array_column($servers, 'sort');
|
||||
array_multisort($tmp, SORT_ASC, $servers);
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getRoutes(array $routeIds)
|
||||
// 获取路由规则
|
||||
public static function getRoutes(array $routeIds)
|
||||
{
|
||||
$routes = ServerRoute::select(['id', 'match', 'action', 'action_value'])->whereIn('id', $routeIds)->get();
|
||||
// TODO: remove on 1.8.0
|
||||
@ -318,7 +332,8 @@ class ServerService
|
||||
return $routes;
|
||||
}
|
||||
|
||||
public function getServer($serverId, $serverType)
|
||||
// 获取服务器
|
||||
public static function getServer($serverId, $serverType)
|
||||
{
|
||||
switch ($serverType) {
|
||||
case 'vmess':
|
||||
@ -336,8 +351,8 @@ class ServerService
|
||||
}
|
||||
}
|
||||
|
||||
// 根据节点IP和父级别节点ID查询字节点
|
||||
public function getChildServer($serverId, $serverType, $nodeIp){
|
||||
// 根据节点IP和父级别节点ID查询子节点
|
||||
public static function getChildServer($serverId, $serverType, $nodeIp){
|
||||
switch ($serverType) {
|
||||
case 'vmess':
|
||||
return ServerVmess::query()
|
||||
|
@ -21,9 +21,9 @@ class TicketService {
|
||||
'message' => $message
|
||||
]);
|
||||
if ($userId !== $ticket->user_id) {
|
||||
$ticket->reply_status = 0;
|
||||
$ticket->reply_status = Ticket::STATUS_OPENING;
|
||||
} else {
|
||||
$ticket->reply_status = 1;
|
||||
$ticket->reply_status = Ticket::STATUS_CLOSED;
|
||||
}
|
||||
if (!$ticketMessage || !$ticket->save()) {
|
||||
throw new \Exception();
|
||||
@ -43,7 +43,7 @@ class TicketService {
|
||||
if (!$ticket) {
|
||||
throw new ApiException('工单不存在');
|
||||
}
|
||||
$ticket->status = 0;
|
||||
$ticket->status = Ticket::STATUS_OPENING;
|
||||
try{
|
||||
DB::beginTransaction();
|
||||
$ticketMessage = TicketMessage::create([
|
||||
@ -52,9 +52,9 @@ class TicketService {
|
||||
'message' => $message
|
||||
]);
|
||||
if ($userId !== $ticket->user_id) {
|
||||
$ticket->reply_status = 0;
|
||||
$ticket->reply_status = Ticket::STATUS_OPENING;
|
||||
} else {
|
||||
$ticket->reply_status = 1;
|
||||
$ticket->reply_status = Ticket::STATUS_CLOSED;
|
||||
}
|
||||
if (!$ticketMessage || !$ticket->save()) {
|
||||
throw new ApiException('工单回复失败');
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Jobs\StatServerJob;
|
||||
use App\Jobs\StatUserJob;
|
||||
use App\Jobs\TrafficFetchJob;
|
||||
use App\Models\Order;
|
||||
use App\Models\Plan;
|
||||
@ -172,7 +170,7 @@ class UserService
|
||||
{
|
||||
// 获取子节点
|
||||
$childServer = ($server['parent_id'] == null && !blank($nodeIp))
|
||||
? (new ServerService())->getChildServer($server['id'], $protocol, $nodeIp)
|
||||
? ServerService::getChildServer($server['id'], $protocol, $nodeIp)
|
||||
: null;
|
||||
$timestamp = strtotime(date('Y-m-d'));
|
||||
collect($data)->chunk(1000)->each(function($chunk) use ($timestamp,$server,$protocol, $childServer){
|
||||
|
@ -10,6 +10,10 @@ use Illuminate\Support\Fluent;
|
||||
|
||||
class Setting extends Fluent
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->attributes = self::fromDatabase();
|
||||
}
|
||||
/**
|
||||
* 获取配置,并转化为数组.
|
||||
*
|
||||
@ -129,21 +133,12 @@ class Setting extends Fluent
|
||||
public static function fromDatabase()
|
||||
{
|
||||
$values = [];
|
||||
|
||||
try {
|
||||
if(env('ADMIN_SETTING_CACHE') > 0){
|
||||
$values = Cache::remember('admin_settings', env('ADMIN_SETTING_CACHE'), function () {
|
||||
$values = Cache::remember('admin_settings', env('ADMIN_SETTING_CACHE', 0), function () {
|
||||
return SettingModel::pluck('value', 'name')->toArray();
|
||||
}
|
||||
);
|
||||
}else{
|
||||
$values = SettingModel::pluck('value', 'name')->toArray();
|
||||
}
|
||||
});
|
||||
} catch (QueryException $e) {
|
||||
return new static($values);
|
||||
// throw new \Exception('配置获取失败、请检查数据库配置');
|
||||
}
|
||||
|
||||
return new static($values);
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,8 @@
|
||||
"joanhey/adapterman": "^0.6.1",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/horizon": "^5.9.6",
|
||||
"laravel/pulse": "*",
|
||||
"laravel/tinker": "^2.5",
|
||||
"linfo/linfo": "^4.0",
|
||||
"nunomaduro/collision": "^7.10",
|
||||
"paragonie/sodium_compat": "^1.20",
|
||||
"php-curl-class/php-curl-class": "^8.6",
|
||||
"spatie/db-dumper": "^3.4",
|
||||
@ -39,6 +37,7 @@
|
||||
"barryvdh/laravel-debugbar": "^3.9",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"mockery/mockery": "^1.3.1",
|
||||
"nunomaduro/collision": "^7.10",
|
||||
"orangehill/iseed": "^3.0",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"spatie/laravel-ignition": "^2.0"
|
||||
|
Loading…
Reference in New Issue
Block a user