mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-24 12:07:28 +08:00
feat: plugin controller config system with guest_comm_config hook integration
- Add HasPluginConfig trait and PluginController base class - Integrate guest_comm_config hook in CommController for plugin frontend config injection - Add user creation functionality to UserService and fix null value handling - Enhance AbstractPlugin.getConfig() with key parameter support - Multiple service layer optimizations and architecture improvements
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Models\InviteCode;
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Services\CaptchaService;
|
||||
use App\Services\UserService;
|
||||
use App\Utils\CacheKey;
|
||||
use App\Utils\Dict;
|
||||
use App\Utils\Helper;
|
||||
@@ -100,16 +101,11 @@ class RegisterService
|
||||
/**
|
||||
* 处理邀请码
|
||||
*
|
||||
* @param User $user 用户对象
|
||||
* @param string|null $inviteCode 邀请码
|
||||
* @return array [是否成功, 错误消息]
|
||||
* @param string $inviteCode 邀请码
|
||||
* @return array [邀请人ID或成功状态, 错误消息]
|
||||
*/
|
||||
public function handleInviteCode(User $user, ?string $inviteCode): array
|
||||
public function handleInviteCode(string $inviteCode): array
|
||||
{
|
||||
if (!$inviteCode) {
|
||||
return [true, null];
|
||||
}
|
||||
|
||||
$inviteCodeModel = InviteCode::where('code', $inviteCode)
|
||||
->where('status', 0)
|
||||
->first();
|
||||
@@ -118,38 +114,18 @@ class RegisterService
|
||||
if ((int) admin_setting('invite_force', 0)) {
|
||||
return [false, [400, __('Invalid invitation code')]];
|
||||
}
|
||||
return [true, null];
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
$user->invite_user_id = $inviteCodeModel->user_id ? $inviteCodeModel->user_id : null;
|
||||
|
||||
if (!(int) admin_setting('invite_never_expire', 0)) {
|
||||
$inviteCodeModel->status = true;
|
||||
$inviteCodeModel->save();
|
||||
}
|
||||
|
||||
return [true, null];
|
||||
return [$inviteCodeModel->user_id, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理试用计划
|
||||
*
|
||||
* @param User $user 用户对象
|
||||
* @return void
|
||||
*/
|
||||
public function handleTryOut(User $user): void
|
||||
{
|
||||
if ((int) admin_setting('try_out_plan_id', 0)) {
|
||||
$plan = Plan::find(admin_setting('try_out_plan_id'));
|
||||
if ($plan) {
|
||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||
$user->plan_id = $plan->id;
|
||||
$user->group_id = $plan->group_id;
|
||||
$user->expired_at = time() + (admin_setting('try_out_hour', 1) * 3600);
|
||||
$user->speed_limit = $plan->speed_limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 注册用户
|
||||
@@ -167,24 +143,25 @@ class RegisterService
|
||||
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
$inviteCode = $request->input('invite_code');
|
||||
|
||||
// 创建用户
|
||||
$user = new User();
|
||||
$user->email = $email;
|
||||
$user->password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->uuid = Helper::guid(true);
|
||||
$user->token = Helper::guid();
|
||||
$user->remind_expire = admin_setting('default_remind_expire', 1);
|
||||
$user->remind_traffic = admin_setting('default_remind_traffic', 1);
|
||||
|
||||
// 处理邀请码
|
||||
[$inviteSuccess, $inviteError] = $this->handleInviteCode($user, $request->input('invite_code'));
|
||||
if (!$inviteSuccess) {
|
||||
return [false, $inviteError];
|
||||
// 处理邀请码获取邀请人ID
|
||||
$inviteUserId = null;
|
||||
if ($inviteCode) {
|
||||
[$inviteSuccess, $inviteError] = $this->handleInviteCode($inviteCode);
|
||||
if (!$inviteSuccess) {
|
||||
return [false, $inviteError];
|
||||
}
|
||||
$inviteUserId = $inviteSuccess;
|
||||
}
|
||||
|
||||
// 处理试用计划
|
||||
$this->handleTryOut($user);
|
||||
// 创建用户
|
||||
$userService = app(UserService::class);
|
||||
$user = $userService->createUser([
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'invite_user_id' => $inviteUserId,
|
||||
]);
|
||||
|
||||
// 保存用户
|
||||
if (!$user->save()) {
|
||||
|
||||
@@ -80,7 +80,7 @@ class CaptchaService
|
||||
// 检查分数阈值(如果有的话)
|
||||
$score = $recaptchaResp->getScore();
|
||||
$threshold = admin_setting('recaptcha_v3_score_threshold', 0.5);
|
||||
if ($score !== null && $score < $threshold) {
|
||||
if ($score < $threshold) {
|
||||
return [false, [400, __('Invalid code is incorrect')]];
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class MailService
|
||||
/**
|
||||
* 分块处理用户提醒邮件
|
||||
*/
|
||||
public function processUsersInChunks(int $chunkSize, callable $progressCallback = null): array
|
||||
public function processUsersInChunks(int $chunkSize, ?callable $progressCallback = null): array
|
||||
{
|
||||
$statistics = [
|
||||
'processed_users' => 0,
|
||||
|
||||
@@ -58,9 +58,13 @@ abstract class AbstractPlugin
|
||||
/**
|
||||
* 获取配置
|
||||
*/
|
||||
public function getConfig(): array
|
||||
public function getConfig(?string $key = null, $default = null): mixed
|
||||
{
|
||||
return $this->config;
|
||||
$config = $this->config;
|
||||
if ($key) {
|
||||
$config = $config[$key] ?? $default;
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ class PluginManager
|
||||
*/
|
||||
public function getPluginPath(string $pluginCode): string
|
||||
{
|
||||
return $this->pluginPath . '/' . Str::studly($pluginCode);
|
||||
return $this->pluginPath . '/' . Str::studly($pluginCode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,16 +85,21 @@ class PluginManager
|
||||
{
|
||||
$routesPath = $this->getPluginPath($pluginCode) . '/routes';
|
||||
if (File::exists($routesPath)) {
|
||||
$files = ['web.php', 'api.php'];
|
||||
foreach ($files as $file) {
|
||||
$routeFile = $routesPath . '/' . $file;
|
||||
if (File::exists($routeFile)) {
|
||||
Route::middleware('web')
|
||||
->namespace($this->getPluginNamespace($pluginCode) . '\\Controllers')
|
||||
->group(function () use ($routeFile) {
|
||||
require $routeFile;
|
||||
});
|
||||
}
|
||||
$webRouteFile = $routesPath . '/web.php';
|
||||
$apiRouteFile = $routesPath . '/api.php';
|
||||
if (File::exists($webRouteFile)) {
|
||||
Route::middleware('web')
|
||||
->namespace($this->getPluginNamespace($pluginCode) . '\\Controllers')
|
||||
->group(function () use ($webRouteFile) {
|
||||
require $webRouteFile;
|
||||
});
|
||||
}
|
||||
if (File::exists($apiRouteFile)) {
|
||||
Route::middleware('api')
|
||||
->namespace($this->getPluginNamespace($pluginCode) . '\\Controllers')
|
||||
->group(function () use ($apiRouteFile) {
|
||||
require $apiRouteFile;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ class TrafficResetService
|
||||
/**
|
||||
* Batch check and reset users. Processes all eligible users in batches.
|
||||
*/
|
||||
public function batchCheckReset(int $batchSize = 100, callable $progressCallback = null): array
|
||||
public function batchCheckReset(int $batchSize = 100, ?callable $progressCallback = null): array
|
||||
{
|
||||
$startTime = microtime(true);
|
||||
$totalResetCount = 0;
|
||||
|
||||
@@ -11,6 +11,8 @@ use App\Models\User;
|
||||
use App\Services\Plugin\HookManager;
|
||||
use App\Services\TrafficResetService;
|
||||
use App\Models\TrafficResetLog;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class UserService
|
||||
{
|
||||
@@ -23,22 +25,22 @@ class UserService
|
||||
// Use TrafficResetService to calculate the next reset time
|
||||
$trafficResetService = app(TrafficResetService::class);
|
||||
$nextResetTime = $trafficResetService->calculateNextResetTime($user);
|
||||
|
||||
|
||||
if (!$nextResetTime) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Calculate the remaining days from now to the next reset time
|
||||
$now = time();
|
||||
$resetTimestamp = $nextResetTime->timestamp;
|
||||
|
||||
|
||||
if ($resetTimestamp <= $now) {
|
||||
return 0; // Reset time has passed or is now
|
||||
}
|
||||
|
||||
|
||||
// Calculate the difference in days (rounded up)
|
||||
$daysDifference = ceil(($resetTimestamp - $now) / 86400);
|
||||
|
||||
|
||||
return (int) $daysDifference;
|
||||
}
|
||||
|
||||
@@ -115,7 +117,7 @@ class UserService
|
||||
{
|
||||
list($server, $protocol, $data) = HookManager::filter('traffic.before_process', [
|
||||
$server,
|
||||
$protocol,
|
||||
$protocol,
|
||||
$data
|
||||
]);
|
||||
|
||||
@@ -134,10 +136,10 @@ class UserService
|
||||
{
|
||||
// 检查是否需要重置流量
|
||||
app(TrafficResetService::class)->checkAndReset($user, TrafficResetLog::SOURCE_USER_ACCESS);
|
||||
|
||||
|
||||
// 重新获取用户数据(可能已被重置)
|
||||
$user->refresh();
|
||||
|
||||
|
||||
return [
|
||||
'upload' => $user->u ?? 0,
|
||||
'download' => $user->d ?? 0,
|
||||
@@ -150,4 +152,97 @@ class UserService
|
||||
'reset_count' => $user->reset_count,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
public function createUser(array $data): User
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
// 基本信息
|
||||
$user->email = $data['email'];
|
||||
$user->password = isset($data['password'])
|
||||
? Hash::make($data['password'])
|
||||
: Hash::make($data['email']);
|
||||
$user->uuid = Helper::guid(true);
|
||||
$user->token = Helper::guid();
|
||||
|
||||
// 默认设置
|
||||
$user->remind_expire = admin_setting('default_remind_expire', 1);
|
||||
$user->remind_traffic = admin_setting('default_remind_traffic', 1);
|
||||
|
||||
// 可选字段
|
||||
$this->setOptionalFields($user, $data);
|
||||
|
||||
$user->expired_at = null;
|
||||
|
||||
// 处理计划
|
||||
if (isset($data['plan_id'])) {
|
||||
$this->setPlanForUser($user, $data['plan_id'], $data['expired_at'] ?? null);
|
||||
} else {
|
||||
$this->setTryOutPlan(user: $user);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置可选字段
|
||||
*/
|
||||
private function setOptionalFields(User $user, array $data): void
|
||||
{
|
||||
$optionalFields = [
|
||||
'invite_user_id',
|
||||
'telegram_id',
|
||||
'group_id',
|
||||
'speed_limit',
|
||||
'expired_at',
|
||||
'transfer_enable'
|
||||
];
|
||||
|
||||
foreach ($optionalFields as $field) {
|
||||
if (array_key_exists($field, $data)) {
|
||||
$user->{$field} = $data[$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为用户设置计划
|
||||
*/
|
||||
private function setPlanForUser(User $user, int $planId, ?int $expiredAt = null): void
|
||||
{
|
||||
$plan = Plan::find($planId);
|
||||
if (!$plan)
|
||||
return;
|
||||
|
||||
$user->plan_id = $plan->id;
|
||||
$user->group_id = $plan->group_id;
|
||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||
$user->speed_limit = $plan->speed_limit;
|
||||
|
||||
if ($expiredAt) {
|
||||
$user->expired_at = $expiredAt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置试用计划
|
||||
*/
|
||||
private function setTryOutPlan(User $user): void
|
||||
{
|
||||
if (!(int) admin_setting('try_out_plan_id', 0))
|
||||
return;
|
||||
|
||||
$plan = Plan::find(admin_setting('try_out_plan_id'));
|
||||
if (!$plan)
|
||||
return;
|
||||
|
||||
$user->transfer_enable = $plan->transfer_enable * 1073741824;
|
||||
$user->plan_id = $plan->id;
|
||||
$user->group_id = $plan->group_id;
|
||||
$user->expired_at = time() + (admin_setting('try_out_hour', 1) * 3600);
|
||||
$user->speed_limit = $plan->speed_limit;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user