refactor: 重构规范部分代码、邮件队列增加失败重试、去除多个支付方式、更新依赖
This commit is contained in:
@@ -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,11 +35,12 @@ 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', [
|
||||
'app_name' => admin_setting('app_name', 'XBoard')
|
||||
'app_name' => admin_setting('app_name', 'XBoard')
|
||||
]),
|
||||
'template_name' => 'remindExpire',
|
||||
'template_value' => [
|
||||
@@ -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');
|
||||
@@ -41,15 +42,15 @@ class ServerService
|
||||
unset($serverData['tls_settings']['private_key']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$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){
|
||||
|
||||
Reference in New Issue
Block a user