Files
webman-buildadmin/app/api/controller/Account.php

367 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\api\controller;
use ba\Date;
use ba\Captcha;
use ba\Random;
use app\common\library\finance\WithdrawFlow;
use app\common\model\User;
use app\common\facade\Token;
use app\common\model\UserScoreLog;
use app\common\model\UserMoneyLog;
use app\common\controller\Frontend;
use app\common\facade\Token as TokenFacade;
use app\common\service\MobileAuthDeviceService;
use support\think\Db;
use support\validation\Validator;
use support\validation\ValidationException;
use Webman\Http\Request;
use support\Response;
class Account extends Frontend
{
protected array $noNeedLogin = ['retrievePassword'];
// 移动端 API 不走会员权限表user_group/user_rule校验仅校验登录态
protected array $noNeedPermission = ['*'];
public function userProfile(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) {
return $response;
}
$authToken = trim((string) $request->header('auth-token', ''));
if ($authToken === '') {
return $this->mobileResult(1101, 'Missing auth-token');
}
$tokenData = TokenFacade::get($authToken);
$type = $tokenData['type'] ?? '';
$expireTime = $tokenData['expire_time'] ?? 0;
if ($type !== 'auth-token' || !is_numeric($expireTime) || $expireTime < time()) {
return $this->mobileResult(1101, 'auth-token is invalid or expired');
}
$user = $this->auth->getUser();
$userId = intval(strval($user->id));
$deviceError = MobileAuthDeviceService::validateUserDeviceSession($authToken, $userId);
if ($deviceError !== null) {
return $this->mobileResult(1101, $deviceError);
}
$coinBalance = WithdrawFlow::amountString($user->coin ?? '0');
// 打码量 / 提现配额快照
$flow = WithdrawFlow::status($userId, [
'total_deposit_coin' => $user->total_deposit_coin ?? '0',
'total_withdraw_coin' => $user->total_withdraw_coin ?? '0',
'bet_flow_coin' => $user->bet_flow_coin ?? '0',
]);
$maxWithdrawable = WithdrawFlow::maxWithdrawable($coinBalance, $flow);
// 待审核提现订单数(配合 /api/finance/withdrawCreate 的 3 笔上限)
$pendingWithdrawCount = Db::name('withdraw_order')
->where('user_id', $userId)
->where('status', 0)
->count();
$payload = [
'code' => 1,
'message' => __('ok'),
'data' => [
'uuid' => $user->uuid ?? '',
'username' => $user->username,
'head_image' => $user->avatar ?? '',
'phone' => $user->phone ?? '',
'email' => $user->email ?? '',
'register_invite_code' => $user->register_invite_code ?? '',
'channel_id' => $user->channel_id,
'risk_flags' => $user->risk_flags ?? 0,
'current_streak' => $user->current_streak ?? 0,
'last_bet_period_no' => $user->last_bet_period_no ?? '',
'create_time' => $user->create_time ?? 0,
// 资金字段4 位小数字符串,与钱包展示口径一致)
'coin' => floatval($coinBalance),
'coin_balance' => floatval($coinBalance),
'frozen_balance' => 0.00,
'total_deposit_coin' => floatval(WithdrawFlow::amountString($user->total_deposit_coin ?? '0')),
'total_withdraw_coin' => floatval(WithdrawFlow::amountString($user->total_withdraw_coin ?? '0')),
'bet_flow_coin' => floatval($flow['bet_flow_coin']),
'max_withdrawable' => floatval($maxWithdrawable),
'withdraw_flow' => [
'ratio' => floatval($flow['ratio']),
'net_deposit' => floatval($flow['net_deposit']),
'required_bet_flow' => floatval($flow['required_bet_flow']),
'remaining_bet_flow' => floatval($flow['remaining_bet_flow']),
'eligible' => $flow['eligible'],
'max_withdraw_by_flow' => $flow['flow_unlimited'] ? null : floatval($flow['max_withdraw_by_flow']),
'flow_unlimited' => $flow['flow_unlimited'],
'pending_withdraw' => [
'count' => $pendingWithdrawCount,
'max' => WithdrawFlow::MAX_PENDING_WITHDRAW,
],
],
],
];
return \response(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 200, ['Content-Type' => 'application/json']);
}
private function mobileResult(int $code, string $message, array $data = []): Response
{
$payload = [
'code' => $code,
'message' => __($message),
'data' => $data,
];
return \response(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 200, ['Content-Type' => 'application/json']);
}
public function overview(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
$sevenDays = Date::unixTime('day', -6);
$score = $money = $days = [];
for ($i = 0; $i < 7; $i++) {
$days[$i] = date("Y-m-d", $sevenDays + ($i * 86400));
$tempToday0 = strtotime($days[$i]);
$tempToday24 = strtotime('+1 day', $tempToday0) - 1;
$score[$i] = UserScoreLog::where('user_id', $this->auth->id)
->where('create_time', 'BETWEEN', $tempToday0 . ',' . $tempToday24)
->sum('score');
$userMoneyTemp = UserMoneyLog::where('user_id', $this->auth->id)
->where('create_time', 'BETWEEN', $tempToday0 . ',' . $tempToday24)
->sum('money');
$money[$i] = bcdiv((string) $userMoneyTemp, '100', 2);
}
return $this->success('', [
'days' => $days,
'score' => $score,
'money' => $money,
]);
}
public function profile(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
if ($request->method() === 'POST') {
$model = $this->auth->getUser();
$data = $request->only(['avatar', 'username', 'nickname', 'gender', 'birthday', 'motto']);
$data['id'] = $this->auth->id;
if (!isset($data['birthday'])) {
$data['birthday'] = null;
}
try {
Validator::make($data, [
'username' => 'required|string|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/',
'nickname' => 'required|string|regex:/^[\x{4e00}-\x{9fa5}a-zA-Z0-9_-]+$/u',
'birthday' => 'nullable|date',
], [
'nickname.regex' => __('nicknameChsDash'),
])->validate();
} catch (ValidationException $e) {
return $this->error($e->getMessage());
}
$existUser = User::where('username', $data['username'])->where('id', '<>', $this->auth->id)->find();
if ($existUser) {
return $this->error(__('Username') . ' ' . __('already exists'));
}
$model->startTrans();
try {
$model->save($data);
$model->commit();
} catch (\Throwable $e) {
$model->rollback();
return $this->error($e->getMessage());
}
return $this->success(__('Data updated successfully~'));
}
return $this->success('', [
'accountVerificationType' => get_account_verification_type()
]);
}
public function verification(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
$captcha = new Captcha();
$params = $request->only(['type', 'captcha']);
$key = ($params['type'] == 'email' ? $this->auth->email : $this->auth->mobile) . "user_{$params['type']}_verify";
if ($captcha->check($params['captcha'], $key)) {
$uuid = Random::uuid();
Token::set($uuid, $params['type'] . '-pass', $this->auth->id, 600);
return $this->success('', [
'type' => $params['type'],
'accountVerificationToken' => $uuid,
]);
}
return $this->error(__('Please enter the correct verification code'));
}
public function changeBind(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
$captcha = new Captcha();
$params = $request->only(['type', 'captcha', 'email', 'mobile', 'accountVerificationToken', 'password']);
$user = $this->auth->getUser();
if ($user[$params['type']]) {
if (!Token::check($params['accountVerificationToken'], $params['type'] . '-pass', $user->id)) {
return $this->error(__('You need to verify your account before modifying the binding information'));
}
} elseif (!isset($params['password']) || !verify_password($params['password'], $user->password, ['salt' => $user->salt ?? ''])) {
return $this->error(__('Password error'));
}
if ($captcha->check($params['captcha'], $params[$params['type']] . "user_change_{$params['type']}")) {
try {
if ($params['type'] == 'email') {
Validator::make($params, ['email' => 'required|email'])->validate();
if (User::where('email', $params['email'])->find()) {
return $this->error(__('Email') . ' ' . __('already exists'));
}
} else {
Validator::make($params, ['mobile' => 'required|regex:/^1[3-9]\d{9}$/'])->validate();
if (User::where('mobile', $params['mobile'])->find()) {
return $this->error(__('Mobile') . ' ' . __('already exists'));
}
}
} catch (ValidationException $e) {
return $this->error(__($e->getMessage()));
}
if ($params['type'] == 'email') {
$user->email = $params['email'];
} else {
$user->mobile = $params['mobile'];
}
Token::delete($params['accountVerificationToken']);
$user->save();
return $this->success();
}
return $this->error(__('Please enter the correct verification code'));
}
public function changePassword(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
if ($request->method() === 'POST') {
$model = $this->auth->getUser();
$params = $request->only(['oldPassword', 'newPassword']);
if (!verify_password($params['oldPassword'], $model->password, ['salt' => $model->salt ?? ''])) {
return $this->error(__('Old password error'));
}
try {
Validator::make(
['password' => $params['newPassword']],
['password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/'],
['password.regex' => __('Please input correct password')]
)->validate();
} catch (ValidationException $e) {
return $this->error($e->getMessage());
}
$model->startTrans();
try {
$model->resetPassword($this->auth->id, $params['newPassword']);
$model->commit();
} catch (\Throwable $e) {
$model->rollback();
return $this->error($e->getMessage());
}
$this->auth->logout();
return $this->success(__('Password has been changed, please login again~'));
}
return $this->error(__('Method not allowed'), [], 0, ['statusCode' => 405]);
}
public function integral(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
$limit = $request->get('limit', $request->post('limit', 15));
$res = UserScoreLog::where('user_id', $this->auth->id)
->order('create_time', 'desc')
->paginate($limit);
return $this->success('', [
'list' => $res->items(),
'total' => $res->total(),
]);
}
public function balance(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
$limit = $request->get('limit', $request->post('limit', 15));
$res = UserMoneyLog::where('user_id', $this->auth->id)
->order('create_time', 'desc')
->paginate($limit);
return $this->success('', [
'list' => $res->items(),
'total' => $res->total(),
]);
}
public function retrievePassword(Request $request): Response
{
$response = $this->initializeFrontend($request);
if ($response !== null) return $response;
$params = $request->only(['type', 'account', 'captcha', 'password']);
try {
Validator::make($params, [
'type' => 'required|in:email,mobile',
'account' => 'required|string',
'captcha' => 'required|string',
'password' => 'required|string|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/',
], [
'password.regex' => __('Please input correct password'),
])->validate();
} catch (ValidationException $e) {
return $this->error($e->getMessage());
}
if ($params['type'] == 'email') {
$user = User::where('email', $params['account'])->find();
} else {
$user = User::where('mobile', $params['account'])->find();
}
if (!$user) {
return $this->error(__('Account does not exist~'));
}
$captchaObj = new Captcha();
if (!$captchaObj->check($params['captcha'], $params['account'] . 'user_retrieve_pwd')) {
return $this->error(__('Please enter the correct verification code'));
}
if ($user->resetPassword($user->id, $params['password'])) {
return $this->success(__('Password has been changed~'));
}
return $this->error(__('Failed to modify password, please try again later~'));
}
}