mirror of
http://124.126.16.154:8888/singularity/hdk-pay.git
synced 2026-01-15 02:15:07 +08:00
init: 初始化项目
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
composer.phar
|
||||
vendor/
|
||||
.idea/
|
||||
.phpunit.result.cache
|
||||
68
.versionrc
Normal file
68
.versionrc
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"header": "# 版本更新日志",
|
||||
"preMajor": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "feat",
|
||||
"section": "✨ Features | 新功能"
|
||||
},
|
||||
{
|
||||
"type": "fix",
|
||||
"section": "🐛 Bug Fixes | Bug 修复"
|
||||
},
|
||||
{
|
||||
"type": "init",
|
||||
"section": "🎉 Init | 初始化"
|
||||
},
|
||||
{
|
||||
"type": "docs",
|
||||
"section": "✏️ Documentation | 文档"
|
||||
},
|
||||
{
|
||||
"type": "style",
|
||||
"section": "💄 Styles | 风格"
|
||||
},
|
||||
{
|
||||
"type": "refactor",
|
||||
"section": "♻️ Code Refactoring | 代码重构"
|
||||
},
|
||||
{
|
||||
"type": "perf",
|
||||
"section": "⚡ Performance Improvements | 性能优化"
|
||||
},
|
||||
{
|
||||
"type": "tests",
|
||||
"section": "✅ Tests | 测试"
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"section": "✅ Tests | 测试"
|
||||
},
|
||||
{
|
||||
"type": "revert",
|
||||
"section": "⏪ Revert | 回退"
|
||||
},
|
||||
{
|
||||
"type": "build",
|
||||
"section": "📦 Build System | 打包构建"
|
||||
},
|
||||
{
|
||||
"type": "chore",
|
||||
"section": "🚀 Chore | 构建/工程依赖/工具"
|
||||
},
|
||||
{
|
||||
"type": "ci",
|
||||
"section": "👷 Continuous Integration | CI 配置"
|
||||
}
|
||||
],
|
||||
"bumpFiles": [
|
||||
{
|
||||
"filename": "VERSION_TRACKER.txt",
|
||||
"type": "plain-text"
|
||||
},
|
||||
{
|
||||
"filename": "composer.json",
|
||||
"type": "json"
|
||||
}
|
||||
]
|
||||
}
|
||||
0
Dockerfile
Normal file
0
Dockerfile
Normal file
22
LICENCE.md
Normal file
22
LICENCE.md
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Elliot J. Reed
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
61
README.md
Normal file
61
README.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# HDK-Pay
|
||||
|
||||
A sdk to connect to LuxPay.
|
||||
|
||||
## PHP Versions
|
||||
|
||||
This version will work on PHP version 8.0 and above.
|
||||
|
||||
## Getting Started
|
||||
|
||||
PHP 8.0 or above and Composer is expected to be installed on our system.
|
||||
|
||||
### Installing
|
||||
|
||||
```bash
|
||||
composer require singularity/hdk-pay
|
||||
```
|
||||
|
||||
This will install all dependencies needed for the project.
|
||||
|
||||
### Configurations
|
||||
|
||||
You need to add an item `http_request.pay.rpc_base_uri` in *config/autoload/common.php*.
|
||||
Usually, the value of this item will be *https://pay.luxcreo.cn* or *https://test-pay.luxcreo.cn*.
|
||||
**Don't need the following `/`**.
|
||||
|
||||
## Running the Tests
|
||||
|
||||
All tests can be run by executing
|
||||
|
||||
```bash
|
||||
vendor/bin/phpunit
|
||||
```
|
||||
|
||||
`phpunit` will automatically find all tests inside the `test` directory and run them based on the configuration in the `phpunit.xml` file.
|
||||
|
||||
### Testing Approach
|
||||
|
||||
The test for the class `Greeting` verifies that the return value of the `sayHello` method returns the string "Hello {name}", where {name} is the value passed through to the constructor.
|
||||
|
||||
## Running the Application
|
||||
|
||||
PHP has an in-built server for local development. This can be started by executing
|
||||
|
||||
```
|
||||
php -S localhost:8000 -t public
|
||||
```
|
||||
|
||||
Then open your browser at `http://localhost:8000/example.php`
|
||||
|
||||
You should see the text "Hello Ada Lovelace" on your screen.
|
||||
|
||||
## Built With
|
||||
|
||||
- [PHP](https://secure.php.net/)
|
||||
- [Composer](https://getcomposer.org/)
|
||||
- [PHPUnit](https://phpunit.de/)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENCE.md](LICENCE.md) file for details.
|
||||
51
composer.json
Executable file
51
composer.json
Executable file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "singularity/hdk-pay",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"description": "支付平台",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Singularity\\HDK\\Pay\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"hyperf": {
|
||||
"config": "Singularity\\HDK\\Pay\\ConfigProvider"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"composer/composer": ">=2.5.8",
|
||||
"singularity/hdk-core": "^0.2.20",
|
||||
"hyperf/guzzle": "~3.0.0",
|
||||
"moneyphp/money": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"firebase/php-jwt": "^6.8.0",
|
||||
"phpunit/phpunit": "^9.6.9"
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"sort-packages": true,
|
||||
"secure-http": false
|
||||
},
|
||||
"scripts": {
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"test": "vendor/bin/phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always",
|
||||
"cs-fix": "php-cs-fixer fix $1",
|
||||
"analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config"
|
||||
},
|
||||
"repositories": {
|
||||
"lux-map": {
|
||||
"type": "composer",
|
||||
"url": "https://satis.luxcreo.cn/"
|
||||
},
|
||||
"packagist": {
|
||||
"type": "composer",
|
||||
"url": "https://mirrors.cloud.tencent.com/composer/"
|
||||
}
|
||||
}
|
||||
}
|
||||
5736
composer.lock
generated
Normal file
5736
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
docs/overview.md
Normal file
18
docs/overview.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# 概览
|
||||
|
||||
[TOC]
|
||||
|
||||
## 模块
|
||||
|
||||
### SDK
|
||||
用于请求 LuxPay 。
|
||||
通过对 RPC 请求进行封装,包装成类普通数据库操作的 Service,对调用者隐藏 Guzzle/cURL 过程。
|
||||
|
||||
将用于交互的订单、商品等,包装成 Resource,类似 Model 的方式进行调用。
|
||||
|
||||
#### 订单
|
||||
#### 商品
|
||||
#### 支付
|
||||
* WeChat Pay
|
||||
* PayPal
|
||||
* Stripe
|
||||
128
guide.md
Normal file
128
guide.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# PHP Package boilerplate project explanation
|
||||
|
||||
PHP is a general-purpose server-side scripting language primarily used in web development. Originally created by Rasmus Lerdorf in 1994, it is now by The PHP Development Team.
|
||||
|
||||
PHP originally stood for "Personal Home Page", but now stands for "PHP: Hypertext Preprocessor".
|
||||
|
||||
## Further Material
|
||||
|
||||
- Homepage: [php.net](https://secure.php.net/)
|
||||
- Documentation: [php.net/docs.php](https://secure.php.net/docs.php)
|
||||
- PHP: The Right Way: [phptherightway.com](http://www.phptherightway.com/)
|
||||
- Interactive PHP Tutorial: [learn-php.org](http://www.learn-php.org/)
|
||||
|
||||
## Topics, Tools and Terms
|
||||
|
||||
PHP packages were traditionally installed via PEAR (PHP Extension and Application Repository), but more recently the standard package and dependency management tool is Composer.
|
||||
|
||||
Composer lets us run install commands to add packages to our system, for example `composer require phpunit` would add the unit testing framework PHPUnit to our system.
|
||||
|
||||
For instructions on how to install Composer visit [getcomposer.org](https://getcomposer.org/download/).
|
||||
|
||||
### Dependency Management
|
||||
|
||||
Managing dependencies manually is time-consuming, fortunately Composer can automate this.
|
||||
|
||||
We can list our dependencies in a `composer.json` file and run `composer install` to bring these into our project.
|
||||
|
||||
An example `composer.json` file looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "example-project",
|
||||
"require": {
|
||||
"twig/twig": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The "require" block tells Composer that the Twig templating package is required for production use and can install Twig with a version of 3.x.x (ie. up to, but not including, version 4).
|
||||
|
||||
The "require-dev" block tells Composer that PHPUnit is required in development, but not in production.
|
||||
|
||||
Dependencies can be added to `composer.json` by
|
||||
|
||||
```bash
|
||||
composer require author/package-name
|
||||
```
|
||||
|
||||
Development dependencies can be added by
|
||||
|
||||
```bash
|
||||
composer require author/package-name --dev
|
||||
```
|
||||
|
||||
Dependencies can be updated to their latest maximum version by running
|
||||
|
||||
```bash
|
||||
composer update
|
||||
```
|
||||
|
||||
Composer will also generate a `composer.lock` file on each `composer update` and the initial `composer install`. This is not meant to be edited directly, it tells Composer to use specific versions of packages - particularly useful when hyhou want your development dependencies to match what you will push to production.
|
||||
|
||||
### Testing Tools
|
||||
|
||||
There are a number of testing tools available for PHP. The most popular one is [PHPUnit](https://phpunit.de/). PHPUnit follows the classic xUnit approach.
|
||||
|
||||
[Behat](http://behat.org/en/latest/) is the most popular behaviour-driven development (BDD) testing framework.
|
||||
|
||||
[Codeception](http://codeception.com/) is a framework combining BDD, unit testing, and integration testing, and is cross-compatible with PHPUnit.
|
||||
|
||||
In this guide we will be using PHPUnit as the testing framework.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
A typical directory structure for a PHP project consists of a `src` directory that contains all source files and a `tests` directory that includes all tests. For web applications the publicly accessible files (eg. `index.php`) would reside in a `public` directory which would then be your webservers document root.
|
||||
|
||||
Another common convention is having a `bin` directory that may contain executable files to start your application.
|
||||
|
||||
- src/
|
||||
- test/
|
||||
- public/
|
||||
- composer.json
|
||||
- composer.lock
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
Directory names are in lower case. Class and interface files should be in upper case and match the class or interface names.
|
||||
Configuration, routes, and publicly accessible files should be in lower case.
|
||||
|
||||
For example the class `Example` should be contained in file `Example.php`, the publicly accessible route to the application should be `index.php`.
|
||||
|
||||
Tests match their production code file names with a `Test` suffix, e.g. tests for code in `src/Example.php` should be written in `test/ExampleTest.php`.
|
||||
|
||||
## Example Project
|
||||
|
||||
The main application consists of basically two files:
|
||||
|
||||
- `public/example.php` is the main executable that instantiates and runs:
|
||||
- `src/Example/Greeting.php` contains the main application.
|
||||
|
||||
### Running the Tests
|
||||
|
||||
All tests can be run by executing
|
||||
|
||||
```bash
|
||||
vendor/phpunit/phpunit/phpunit
|
||||
```
|
||||
|
||||
`phpunit` will automatically find all tests inside the `test` directory and run them based on the configuration in the `phpunit.xml` file.
|
||||
|
||||
#### Testing Approach
|
||||
|
||||
The test for the class `Greeting` verifies that the return value of the `sayHello` method returns the string "Hello {name}", where {name} is the value passed through to the constructor.
|
||||
|
||||
### Running the Application
|
||||
|
||||
PHP has an in-built server for local development. To run this change into the directory `public` and run
|
||||
|
||||
```bash
|
||||
php -S localhost:8000
|
||||
```
|
||||
|
||||
Then open your browser at `http://localhost:8000/example.php`
|
||||
|
||||
You should see the text "Hello Ada Lovelace" being printed.
|
||||
10
phpunit.xml
Normal file
10
phpunit.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false"
|
||||
colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd">
|
||||
<coverage/>
|
||||
<testsuites>
|
||||
<testsuite name="Example">
|
||||
<directory>./tests/Example/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
15
publish/payment.php
Normal file
15
publish/payment.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
/**
|
||||
* payment.php@Pay
|
||||
*
|
||||
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
|
||||
* Powered by PhpStorm
|
||||
* Created on 2023/7/17
|
||||
*/
|
||||
|
||||
return [
|
||||
'base_uri' => \Hyperf\Support\env('LUX_PAY_BASE_URI', 'https://pay.luxcreo.cn'),
|
||||
|
||||
// 由 LuxPay 分发的业务系统 id
|
||||
'sp_id' => \Hyperf\Support\env('SERVICE_PROVIDER_ID')
|
||||
];
|
||||
10
scripts/docker-env.sh
Executable file
10
scripts/docker-env.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
|
||||
docker run \
|
||||
--pull always \
|
||||
-ti --rm --name "hdk-pay" \
|
||||
-w "/srv/www" \
|
||||
-v "$(pwd)":/srv/www \
|
||||
-v ~/.ssh:/root/.ssh \
|
||||
harbor.luxcreo.cn/library/hyperf:8.0-swoole /bin/ash
|
||||
5
scripts/release.sh
Executable file
5
scripts/release.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
docker run --rm -it \
|
||||
-v $(pwd):/app -e "GIT_AUTHOR_NAME=ch4o5" -e "EMAIL=dongyun.li@luxcreo.ai" \
|
||||
detouched/standard-version:latest $1
|
||||
50
src/ConfigProvider.php
Normal file
50
src/ConfigProvider.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Singularity\HDK\Pay;
|
||||
|
||||
use Hyperf\Contract\StdoutLoggerInterface;
|
||||
use Hyperf\Framework\Logger\StdoutLogger;
|
||||
|
||||
/**
|
||||
* ConfigProvider.php@HyperfAuth
|
||||
*
|
||||
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
|
||||
* Powered by PhpStorm
|
||||
* Created on 2023/1/16
|
||||
*/
|
||||
class ConfigProvider
|
||||
{
|
||||
public function __invoke(): array
|
||||
{
|
||||
/** @noinspection PhpUndefinedConstantInspection */
|
||||
return [
|
||||
// 合并到 config/autoload/dependencies.php 文件
|
||||
'dependencies' => [
|
||||
StdoutLoggerInterface::class => StdoutLogger::class,
|
||||
],
|
||||
// 合并到 config/autoload/annotations.php 文件
|
||||
'annotations' => [
|
||||
'scan' => [
|
||||
'paths' => [
|
||||
__DIR__,
|
||||
],
|
||||
],
|
||||
],
|
||||
// 默认 Command 的定义,合并到 Hyperf\Contract\ConfigInterface 内,换个方式理解也就是与 config/autoload/commands.php 对应
|
||||
'commands' => [],
|
||||
// 与 commands 类似
|
||||
'listeners' => [],
|
||||
// 组件默认配置文件,即执行命令后会把 source 的对应的文件复制为 destination 对应的的文件
|
||||
'publish' => [
|
||||
[
|
||||
'id' => 'config',
|
||||
'description' => 'The config file for LuxPay',
|
||||
'source' => __DIR__ . '/../publish/payment.php',
|
||||
'destination' => BASE_PATH . '/config/autoload/payment.php',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
74
src/Sdk/WechatRpc.php
Normal file
74
src/Sdk/WechatRpc.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* WechatRpc.php@Pay
|
||||
*
|
||||
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
|
||||
* Powered by PhpStorm
|
||||
* Created on 2023/7/17
|
||||
*/
|
||||
|
||||
namespace Singularity\HDK\Pay\Sdk;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Hyperf\Codec\Json;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Lmc\HttpConstants\Header;
|
||||
use Money\Money;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Singularity\HDK\Core\Service\HttpRequestService;
|
||||
|
||||
use function Hyperf\Config\config;
|
||||
|
||||
/**
|
||||
* Singularity\HDK\Pay\Sdk\WechatRpc@Pay
|
||||
*
|
||||
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
|
||||
* Powered by PhpStorm
|
||||
* Created on 2023/7/17
|
||||
*/
|
||||
final class WechatRpc
|
||||
{
|
||||
#[Inject]
|
||||
private HttpRequestService $requestService;
|
||||
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param string $type
|
||||
* @param string $goodsName
|
||||
* @param Money $money
|
||||
* @param string $uid
|
||||
* @return array{uri: string, orderNo: string}
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function qrcode(
|
||||
RequestInterface $request,
|
||||
string $type,
|
||||
string $goodsName,
|
||||
Money $money,
|
||||
string $uid
|
||||
): array {
|
||||
$url = config('payment.base_uri') . '/rpc/v1/wechat/qrcode';
|
||||
$data = [
|
||||
'service' => config('payment.sp_id'),
|
||||
'amount' => (int)$money->getAmount(),
|
||||
'fileType' => $type,
|
||||
'uid' => $uid,
|
||||
'goods_detail' => [
|
||||
'goods_name' => $goodsName,
|
||||
],
|
||||
];
|
||||
$response = $this->requestService
|
||||
->setOptions([
|
||||
'headers' => [
|
||||
Header::ACCEPT => $request->getHeader(Header::ACCEPT),
|
||||
],
|
||||
])
|
||||
->requestPost($url, $data);
|
||||
|
||||
$content = $response->getBody()->getContents();
|
||||
return Json::decode($content);
|
||||
}
|
||||
|
||||
}
|
||||
24
src/Service/WechatService.php
Normal file
24
src/Service/WechatService.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* WechatService.php@Pay
|
||||
*
|
||||
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
|
||||
* Powered by PhpStorm
|
||||
* Created on 2023/7/17
|
||||
*/
|
||||
|
||||
namespace Singularity\HDK\Pay\Service;
|
||||
|
||||
/**
|
||||
* Singularity\HDK\Pay\Service\WechatService@Pay
|
||||
*
|
||||
* @author 李东云 <Dongyun.Li@LuxCreo.Ai>
|
||||
* Powered by PhpStorm
|
||||
* Created on 2023/7/17
|
||||
*/
|
||||
final class WechatService
|
||||
{
|
||||
|
||||
}
|
||||
18
tests/Example/GreetingTest.php
Normal file
18
tests/Example/GreetingTest.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Example;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Example\Greeting;
|
||||
|
||||
class GreetingTest extends TestCase
|
||||
{
|
||||
public function testItGreetsUser(): void
|
||||
{
|
||||
$greeting = new Greeting('Rasmus Lerdorf');
|
||||
|
||||
$this->assertSame('Hello Rasmus Lerdorf', $greeting->sayHello());
|
||||
}
|
||||
}
|
||||
16
tests/bootstrap.php
Normal file
16
tests/bootstrap.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
ini_set('display_errors', 'on');
|
||||
ini_set('display_startup_errors', 'on');
|
||||
|
||||
error_reporting(E_ALL);
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
Reference in New Issue
Block a user