@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller\PunchCard\User;
|
||||||
|
|
||||||
|
use App\Controller\BaseController;
|
||||||
|
use App\JsonRpc\PunchCardSystemExternalServiceInterface;
|
||||||
|
use App\JsonRpc\UserExternalServiceInterface;
|
||||||
|
use App\Middleware\AuthMiddleware;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Hyperf\HttpServer\Annotation\Controller;
|
||||||
|
use Hyperf\HttpServer\Annotation\GetMapping;
|
||||||
|
use Hyperf\HttpServer\Annotation\Middleware;
|
||||||
|
use Hyperf\HttpServer\Annotation\PostMapping;
|
||||||
|
|
||||||
|
#[Middleware(AuthMiddleware::class)]
|
||||||
|
#[Controller(prefix: "kq")]
|
||||||
|
class UserController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 用户中心对外RPC服务
|
||||||
|
*
|
||||||
|
* @var UserExternalServiceInterface
|
||||||
|
*/
|
||||||
|
#[Inject]
|
||||||
|
protected UserExternalServiceInterface $userExternalService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 考勤系统设置对外RPC服务
|
||||||
|
*
|
||||||
|
* @var PunchCardSystemExternalServiceInterface
|
||||||
|
*/
|
||||||
|
#[Inject]
|
||||||
|
protected PunchCardSystemExternalServiceInterface $punchCardSystemExternalService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取个人资料
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[GetMapping(path: "user/information")]
|
||||||
|
public function information() : array
|
||||||
|
{
|
||||||
|
$user = $this->request->getAttribute('AuthUser');
|
||||||
|
return $this->getServiceResult($this->userExternalService->getUserInfo($user['openid'], [
|
||||||
|
'user_name',
|
||||||
|
'user_phone',
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存个人资料
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[PostMapping(path: "user/save_information")]
|
||||||
|
public function saveInformation() : void
|
||||||
|
{
|
||||||
|
$phone = $this->request->input('phone', '');
|
||||||
|
// TODO 逻辑完善
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取问题反馈类型列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[GetMapping(path: "user/feedback_type")]
|
||||||
|
public function getFeedbackTypeList() : array
|
||||||
|
{
|
||||||
|
return $this->getServiceResult($this->punchCardSystemExternalService->getFeedbackTypeList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存问题反馈
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[PostMapping(path: "user/save_feedback")]
|
||||||
|
public function saveFeedback() : array
|
||||||
|
{
|
||||||
|
$user = $this->request->getAttribute('AuthUser');
|
||||||
|
return $this->getServiceResult($this->punchCardSystemExternalService->saveFeedback($this->request, $user['user_id']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取紧急联系人关系列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[GetMapping(path: "user/emergency_contact_kinship")]
|
||||||
|
public function getEmergencyContactKinshipList() : array
|
||||||
|
{
|
||||||
|
return $this->getServiceResult($this->userExternalService->getEmergencyContactKinshipList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存紧急联系人
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[PostMapping(path: "user/add_emergency_contact")]
|
||||||
|
public function addEmergencyContact() : array
|
||||||
|
{
|
||||||
|
return $this->getServiceResult($this->userExternalService->addEmergencyContact($this->request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试打印JWT认证信息
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[GetMapping(path: "user/test")]
|
||||||
|
public function test() : array
|
||||||
|
{
|
||||||
|
return $this->request->getAttribute('AuthUser');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Controller\PunchCard\User;
|
||||||
|
|
||||||
|
use App\Controller\BaseController;
|
||||||
|
use App\Exception\BusinessException;
|
||||||
|
use app\Constants\Wechat\AuthErrorCode;
|
||||||
|
use App\Middleware\AuthMiddleware;
|
||||||
|
use App\Service\User\WechatAuthService;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Hyperf\HttpServer\Annotation\Controller;
|
||||||
|
use Hyperf\HttpServer\Annotation\GetMapping;
|
||||||
|
use Hyperf\HttpServer\Annotation\Middleware;
|
||||||
|
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||||
|
use Phper666\JWTAuth\Middleware\JWTAuthDefaultSceneMiddleware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信授权处理控制器
|
||||||
|
*/
|
||||||
|
#[Controller(prefix: "kq")]
|
||||||
|
class WechatAuthController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 微信授权服务
|
||||||
|
*
|
||||||
|
* @var WechatAuthService
|
||||||
|
*/
|
||||||
|
#[Inject]
|
||||||
|
protected WechatAuthService $service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过微信授权新建用户
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[RequestMapping(path: "auth/code2OpenID", methods: "get,post")]
|
||||||
|
public function code2OpenID() : array
|
||||||
|
{
|
||||||
|
$code = $this->request->input('code', '');
|
||||||
|
|
||||||
|
if (empty($code)) {
|
||||||
|
throw new BusinessException(AuthErrorCode::CODE_EMPTY_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->service->codeToOpenID($code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[Middleware(AuthMiddleware::class)]
|
||||||
|
#[GetMapping(path: "auth/refresh_token")]
|
||||||
|
public function refreshToken() : array
|
||||||
|
{
|
||||||
|
return $this->service->refreshToken();
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Controller\Wechat;
|
|
||||||
|
|
||||||
use App\Controller\BaseController;
|
|
||||||
use App\Exception\BusinessException;
|
|
||||||
use app\Constants\Wechat\AuthErrorCode;
|
|
||||||
use App\Service\Wechat\AuthService;
|
|
||||||
use Hyperf\Di\Annotation\Inject;
|
|
||||||
use Hyperf\HttpServer\Annotation\Controller;
|
|
||||||
use Hyperf\HttpServer\Annotation\PostMapping;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微信授权处理控制器
|
|
||||||
*/
|
|
||||||
#[Controller]
|
|
||||||
class AuthController extends BaseController
|
|
||||||
{
|
|
||||||
#[Inject]
|
|
||||||
protected AuthService $service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过微信授权新建用户
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
#[PostMapping(path: "auth/code2OpenID")]
|
|
||||||
public function code2OpenID() : array
|
|
||||||
{
|
|
||||||
$code = $this->request->input('code', '');
|
|
||||||
|
|
||||||
if (empty($code)) {
|
|
||||||
throw new BusinessException(AuthErrorCode::CODE_EMPTY_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->service->codeToOpenID($code);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\JsonRpc;
|
||||||
|
|
||||||
|
use Hyperf\RpcClient\AbstractServiceClient;
|
||||||
|
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||||
|
|
||||||
|
class PunchCardSystemExternalServiceConsumer extends AbstractServiceClient implements PunchCardSystemExternalServiceInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 定义对应服务提供者的服务名称
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $serviceName = 'PunchCardSystemExternalService';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取问题反馈类型列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFeedbackTypeList() : array
|
||||||
|
{
|
||||||
|
return $this->__request(__FUNCTION__, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存问题反馈
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function saveFeedback(RequestInterface $request) : array
|
||||||
|
{
|
||||||
|
return $this->__request(__FUNCTION__, [...$request->all(), ...['user_id' => $request->getAttribute('AuthUser')['user_id']]]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\JsonRpc;
|
||||||
|
|
||||||
|
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||||
|
|
||||||
|
interface PunchCardSystemExternalServiceInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 获取问题反馈类型列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFeedbackTypeList() : array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存问题反馈
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function saveFeedback(RequestInterface $request) : array;
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\JsonRpc;
|
||||||
|
|
||||||
|
use Hyperf\RpcClient\AbstractServiceClient;
|
||||||
|
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||||
|
|
||||||
|
class UserExternalServiceConsumer extends AbstractServiceClient implements UserExternalServiceInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 定义对应服务提供者的服务名称
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $serviceName = 'UserExternalService';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户信息
|
||||||
|
*
|
||||||
|
* @param string $openid
|
||||||
|
* @param array $field
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUserInfo(string $openid, array $field = []) : array
|
||||||
|
{
|
||||||
|
return $this->__request(__FUNCTION__, compact('openid', 'field'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过微信授权新建用户
|
||||||
|
*
|
||||||
|
* @param string $openid
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function wechatNewUser(string $openid) : array
|
||||||
|
{
|
||||||
|
return $this->__request(__FUNCTION__, compact('openid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取紧急联系人关系列表
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getEmergencyContactKinshipList() : array
|
||||||
|
{
|
||||||
|
return $this->__request(__FUNCTION__, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存紧急联系人
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function addEmergencyContact(RequestInterface $request) : array
|
||||||
|
{
|
||||||
|
return $this->__request(__FUNCTION__, $request->all());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Middleware;
|
||||||
|
|
||||||
|
use App\Constants\ErrorCode;
|
||||||
|
use Hyperf\Context\Context;
|
||||||
|
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
|
||||||
|
use Phper666\JWTAuth\Exception\JWTException;
|
||||||
|
use Phper666\JWTAuth\Util\JWTUtil;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use Phper666\JWTAuth\JWT;
|
||||||
|
use Phper666\JWTAuth\Exception\TokenValidException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jwt token 校验的中间件,校验场景是否一致
|
||||||
|
*/
|
||||||
|
class AuthMiddleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
public function __construct(protected HttpResponse $response, protected JWT $jwt)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ServerRequestInterface $request
|
||||||
|
* @param RequestHandlerInterface $handler
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
|
{
|
||||||
|
$token = $request->getHeaderLine('Authorization') ?? '';
|
||||||
|
if ($token === "") {
|
||||||
|
throw new JWTException('Missing token', ErrorCode::COMMON_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = JWTUtil::handleToken($token);
|
||||||
|
if ($token !== false && $this->jwt->verifyTokenAndScene('default', $token)) {
|
||||||
|
// 封装认证用户信息
|
||||||
|
$request = $request->withAttribute('AuthUser', JWTUtil::getParserData($request));
|
||||||
|
Context::set(ServerRequestInterface::class, $request);
|
||||||
|
|
||||||
|
return $handler->handle($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TokenValidException('Token authentication does not pass', ErrorCode::COMMON_ERROR);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service\User;
|
||||||
|
|
||||||
|
use App\Constants\Wechat\AuthErrorCode;
|
||||||
|
use App\Exception\BusinessException;
|
||||||
|
use App\Helper\Curl;
|
||||||
|
use App\JsonRpc\UserExternalServiceInterface;
|
||||||
|
use Hyperf\Config\Annotation\Value;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Phper666\JWTAuth\JWT;
|
||||||
|
use Psr\SimpleCache\InvalidArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信授权处理服务层
|
||||||
|
*/
|
||||||
|
class WechatAuthService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 考勤系统小程序APPID
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
#[Value("app.wechat_punch_card_appid")]
|
||||||
|
protected string $appid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 考勤系统小程序APPSecret
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
#[Value("app.wechat_punch_card_secret")]
|
||||||
|
protected string $secret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户中心对外RPC服务
|
||||||
|
*
|
||||||
|
* @var UserExternalServiceInterface
|
||||||
|
*/
|
||||||
|
#[Inject]
|
||||||
|
protected UserExternalServiceInterface $userExternalService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JWT认证组件
|
||||||
|
*
|
||||||
|
* @var JWT
|
||||||
|
*/
|
||||||
|
#[Inject]
|
||||||
|
protected JWT $jwt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信通过code获取session信息请求地址
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected string $wechat_auth_url = 'https://api.weixin.qq.com/sns/jscode2session';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过微信授权新建用户
|
||||||
|
*
|
||||||
|
* @param string $code
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function codeToOpenID(string $code) : array
|
||||||
|
{
|
||||||
|
$url = $this->wechat_auth_url . '?' . http_build_query([
|
||||||
|
'appid' => $this->appid,
|
||||||
|
'secret' => $this->secret,
|
||||||
|
'js_code' => $code,
|
||||||
|
'grant_type' => 'authorization_code'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$result = Curl::get($url);
|
||||||
|
$res = $this->userExternalService->wechatNewUser($result['data']['openid']);
|
||||||
|
|
||||||
|
if (!$res['code'] !== 200) {
|
||||||
|
throw new BusinessException($res['code'], $res['msg']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($res['data']['user'])) {
|
||||||
|
throw new BusinessException(AuthErrorCode::CODE_TO_AUTH_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getToken($res['data']['user']['user_id'], $res['data']['user']['user_nickname'], $res['data']['user']['user_openid']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JWT认证token
|
||||||
|
*
|
||||||
|
* @param int $user_id
|
||||||
|
* @param string $nickname
|
||||||
|
* @param string $openid
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getToken(int $user_id, string $nickname, string $openid)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$token = $this->jwt->getToken('default', [
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'nickname' => $nickname,
|
||||||
|
'openid' => $openid
|
||||||
|
]);
|
||||||
|
} catch (InvalidArgumentException) {
|
||||||
|
// TODO 记录日志
|
||||||
|
throw new BusinessException(AuthErrorCode::CODE_TO_AUTH_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'token' => $token->toString(),
|
||||||
|
'exp' => $this->jwt->getTTL($token->toString())
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新token
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function refreshToken() : array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$token = $this->jwt->refreshToken();
|
||||||
|
} catch (InvalidArgumentException) {
|
||||||
|
// TODO 记录日志
|
||||||
|
throw new BusinessException(AuthErrorCode::CODE_TO_AUTH_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'token' => $token->toString(),
|
||||||
|
'exp' => $this->jwt->getTTL($token->toString())
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Service\Wechat;
|
|
||||||
|
|
||||||
use App\Exception\BusinessException;
|
|
||||||
use App\Helper\Curl;
|
|
||||||
use App\JsonRpc\UserExternalServiceInterface;
|
|
||||||
use Hyperf\Config\Annotation\Value;
|
|
||||||
use Hyperf\Di\Annotation\Inject;
|
|
||||||
|
|
||||||
class AuthService
|
|
||||||
{
|
|
||||||
#[Value("app.wechat_punch_card_appid")]
|
|
||||||
protected string $appid;
|
|
||||||
|
|
||||||
#[Value("app.wechat_punch_card_secret")]
|
|
||||||
protected string $secret;
|
|
||||||
|
|
||||||
#[Inject]
|
|
||||||
protected UserExternalServiceInterface $userExternalService;
|
|
||||||
|
|
||||||
protected string $wechat_auth_url = 'https://api.weixin.qq.com/sns/jscode2session';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过微信授权新建用户
|
|
||||||
*
|
|
||||||
* @param string $code
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function codeToOpenID(string $code) : array
|
|
||||||
{
|
|
||||||
$url = $this->wechat_auth_url . '?' . http_build_query([
|
|
||||||
'appid' => $this->appid,
|
|
||||||
'secret' => $this->secret,
|
|
||||||
'js_code' => $code,
|
|
||||||
'grant_type' => 'authorization_code'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$result = Curl::get($url);
|
|
||||||
$res = $this->userExternalService->wechatNewUser($result['data']['openid']);
|
|
||||||
|
|
||||||
if (!$res['code'] !== 200) {
|
|
||||||
throw new BusinessException($res['code'], $res['msg']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['openid' => $result['data']['openid']];
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue