feat:产品管理-产品类型模块接口完成、公共TOOL类修改
This commit is contained in:
parent
d2a55e9e7e
commit
e7955eeef3
244
app/admin/controller/Works/WorksType.php
Normal file
244
app/admin/controller/Works/WorksType.php
Normal file
@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\Works;
|
||||
|
||||
use app\BaseController;
|
||||
use app\common\model\Works\WorksType as ModelWorksType;
|
||||
use app\Request;
|
||||
use think\Validate;
|
||||
use think\exception\ValidateException;
|
||||
use think\facade\Filesystem;
|
||||
use app\common\arw\adjfut\src\Excel;
|
||||
use app\common\arw\adjfut\src\Traverse;
|
||||
use app\common\arw\adjfut\src\UploadFile;
|
||||
use app\common\exception\Tool;
|
||||
use think\facade\Db;
|
||||
use think\facade\Env;
|
||||
|
||||
|
||||
class WorksType extends BaseController
|
||||
{
|
||||
/**
|
||||
* 获取作品类型列表接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function getWorksTypeList(Request $request): array
|
||||
{
|
||||
$con = Tool::getOptionalQuery(
|
||||
['b.works_type_delete_time', 'NULL'],
|
||||
['a.works_type_name', 'LIKE']
|
||||
);
|
||||
|
||||
$works_type = ModelWorksType::where($con)
|
||||
->field([
|
||||
'a.works_type_id',
|
||||
'a.works_type_guid',
|
||||
'a.works_type_name',
|
||||
'a.works_type_order',
|
||||
'a.works_type_parent_guid',
|
||||
'a.works_type_ancestors_guid',
|
||||
'b.works_type_name' => "works_type_parent_name",
|
||||
])
|
||||
->alias('a')
|
||||
->leftjoin('works_type b', 'a.works_type_parent_guid = b.works_type_guid')
|
||||
->order('works_type_order')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
$Traverse = new Traverse('works_type_guid', 'works_type_parent_guid');
|
||||
$works_type_tree = $Traverse->tree($works_type, '0', function ($v) {
|
||||
return [
|
||||
'works_type_name' => $v['works_type_name'],
|
||||
'works_type_parent_name' => $v['works_type_parent_name'],
|
||||
'works_type_guid' => $v['works_type_guid'],
|
||||
'works_type_parent_guid' => $v['works_type_parent_guid'],
|
||||
'works_type_ancestors_guid' => $v['works_type_ancestors_guid'],
|
||||
'works_type_order' => $v['works_type_order'],
|
||||
];
|
||||
});
|
||||
|
||||
return msg("获取作品类型列表成功!", $works_type_tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑作品类型接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function editWorksType(Request $request): array
|
||||
{
|
||||
Db::startTrans();
|
||||
try {
|
||||
$params = $request->param();
|
||||
$this->validate($params, [
|
||||
'works_type_name|作品类型名称' => 'require',
|
||||
'works_type_guid|作品类型guid' => 'require',
|
||||
'works_type_order|作品类型排序' => 'require',
|
||||
'works_type_parent_guid|作品类型父级guid' => 'require',
|
||||
'works_type_ancestors_guid|作品类型祖级guid' => 'require'
|
||||
]);
|
||||
|
||||
$works_type = ModelWorksType::where('works_type_guid', $params['works_type_guid'])->find();
|
||||
if (!$works_type) throwErrorMsg("该作品类型不存在", 1);
|
||||
$works_type->allowField([
|
||||
'works_type_update_user_guid',
|
||||
'works_type_name',
|
||||
'works_type_order',
|
||||
'works_type_parent_guid',
|
||||
'works_type_ancestors_guid',
|
||||
])->save($params);
|
||||
Db::commit();
|
||||
return msg('编辑成功!');
|
||||
} catch (\Throwable $th) {
|
||||
Db::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加作品类型接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function addWorksType(Request $request)
|
||||
{
|
||||
Db::startTrans();
|
||||
try {
|
||||
$params = $request->param();
|
||||
$this->validate($params, [
|
||||
'works_type_name|作品类型名称' => 'require',
|
||||
'works_type_order|作品类型排序' => 'require',
|
||||
'works_type_parent_guid|作品类型父级guid' => 'require',
|
||||
]);
|
||||
|
||||
ModelWorksType::create($params, [
|
||||
'works_type_guid',
|
||||
'works_type_create_user_guid',
|
||||
'works_type_update_user_guid',
|
||||
'works_type_name',
|
||||
'works_type_order',
|
||||
'works_type_ancestors_guid',
|
||||
'works_type_parent_guid'
|
||||
]);
|
||||
Db::commit();
|
||||
return msg('添加成功!');
|
||||
} catch (\Throwable $th) {
|
||||
Db::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除作品类型接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function deleteWorksType(Request $request): array
|
||||
{
|
||||
Db::startTrans();
|
||||
try {
|
||||
$params = $request->param();
|
||||
$this->validate($params, [
|
||||
'works_type_guid' => 'require',
|
||||
]);
|
||||
$works_type = ModelWorksType::where([
|
||||
'works_type_guid' => explode(',', $params['works_type_guid'])
|
||||
])->select();
|
||||
$works_type->delete();
|
||||
Db::commit();
|
||||
return msg('删除成功!');
|
||||
} catch (\Throwable $th) {
|
||||
Db::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出Excel接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function exportExcel(Request $request)
|
||||
{
|
||||
$params = $request->param();
|
||||
$con = [];
|
||||
if (isset($params['works_type_guids']) && $params['works_type_guids']) {
|
||||
$con['a.works_type_guid'] = explode(',', $params['works_type_guids']);
|
||||
}
|
||||
$select = ModelWorksType::field([
|
||||
'a.works_type_name',
|
||||
'a.works_type_order',
|
||||
'a.works_type_parent_guid',
|
||||
'b.works_type_name' => 'works_type_parent_name',
|
||||
])
|
||||
->where($con)
|
||||
->alias('a')
|
||||
->leftjoin('works_type b', 'a.works_type_parent_guid = b.works_type_guid')
|
||||
->order('works_type_order', 'desc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
ModelWorksType::exportExcel($select);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载导入模板接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function downloadTemplate(Request $request): void
|
||||
{
|
||||
$data = [
|
||||
array_values(ModelWorksType::EXCELFIELD),
|
||||
['', '素描', '1']
|
||||
];
|
||||
$excel = (new Excel())->exporTsheet($data);
|
||||
$excel->save('作品类型导入模板.xlsx');
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入excel接口
|
||||
*
|
||||
* @param Request request
|
||||
* @return array
|
||||
* @date 2023-04-17
|
||||
* @author xjh
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function importExcel(Request $request): array
|
||||
{
|
||||
$file = new UploadFile('uploads', 'fileExt:xlsx');
|
||||
$file->putFile('works_type');
|
||||
|
||||
$msg = ModelWorksType::importExcel($file);
|
||||
return [
|
||||
'code' => 0,
|
||||
'msg' => $msg
|
||||
];
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ use DateTime;
|
||||
use think\facade\Request;
|
||||
use think\facade\Log;
|
||||
use think\helper\Arr;
|
||||
use think\facade\Db;
|
||||
use app\common\arw\adjfut\src\Exception\ErrorMsg;
|
||||
|
||||
class Tool
|
||||
@ -347,68 +348,108 @@ class Tool
|
||||
|
||||
/**
|
||||
* 排序号更换处理
|
||||
*
|
||||
* 注意:使用该方法时候要启动事务!!
|
||||
* @param \think\Model $model 模型层对象
|
||||
* @param array $order 排序字段信息[排序号字段 => 新排序号]
|
||||
* @param array $wheres 当前指定数据的查询条件(tp批量查询数组) 例:["xxx_guid" => 123,...]
|
||||
* @param string $model 模型层命名空间地址
|
||||
* @param string $guid 主键
|
||||
* @param int $order 新排序号
|
||||
* @param array $extra_wheres 当前指定数据的额外查询条件(tp批量查询数组) 例:["xxx_type" => 1,...]
|
||||
*/
|
||||
public static function sortEditProc(\think\Model $model, array $order, array $wheres, array $extra_wheres = []): void
|
||||
public static function sortEditProc(string $model, string $guid, int $order, array $extra_wheres = []): void
|
||||
{
|
||||
$order_field_name = array_keys($order)[0];
|
||||
//模型层实例化
|
||||
$model = new $model;
|
||||
//表名
|
||||
$table_name = $model->db()->getTable();
|
||||
//获取当前的主键字段名
|
||||
$guld_field = $model->db()->getPk();
|
||||
//排序字段名
|
||||
$order_field_name = $model->order_field;
|
||||
//当前数据原排序号
|
||||
$original_oreder_value = $model->where($wheres)->where($extra_wheres)->value($order_field_name);
|
||||
if ($original_oreder_value === null) throwErrorMsg('Tool::sortProcessing() : 找不到该guid数据', 444);
|
||||
|
||||
$original_oreder_find = $model->where($guld_field, $guid)->find();
|
||||
if (!$original_oreder_find) throwErrorMsg('Tool::sortEditProc() : 找不到该数据原排序号', 444);
|
||||
//查找当前数据所想更换的新排序号是否已有数据占用
|
||||
//已被占用,则将它们的排序号互换
|
||||
$occupied_order_data = $model->where($order)->where($extra_wheres)->find();
|
||||
if ($occupied_order_data) {
|
||||
$occupied_order_data[$order_field_name] = $original_oreder_value;
|
||||
$occupied_order_data->save();
|
||||
if ($model->where($order_field_name, $order)->where($extra_wheres)->find()) {
|
||||
Db::name($table_name)->where($order_field_name, $order)->where($extra_wheres)->update([
|
||||
$order_field_name => $original_oreder_find[$order_field_name],
|
||||
$model->parent_guid_field => $original_oreder_find[$model->parent_guid_field],
|
||||
$model->ancestors_guid_field => $original_oreder_find[$model->ancestors_guid_field],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序号腾位处理
|
||||
*
|
||||
* 注意:使用该方法时候要启动事务!!
|
||||
* @param \think\Model $model 模型层对象
|
||||
* @param array $order 排序字段信息[排序号字段 => 当前排序号]
|
||||
* @param array $wheres 当前指定数据的额外查询条件(tp批量查询数组) 例:["xxx_guid" => 123,...]
|
||||
* @param string $model 模型层命名空间地址
|
||||
* @param int $order 当前排序号
|
||||
* @param array $wheres 当前指定数据的额外查询条件(tp批量查询数组) 例:["xxx_type" => 1,...]
|
||||
*/
|
||||
public static function sortInsertProc(\think\Model $model, array $order, array $wheres = []): void
|
||||
public static function sortInsertProc(string $model, int $order, array $wheres = []): void
|
||||
{
|
||||
$order_field_name = array_keys($order)[0];
|
||||
//模型层实例化
|
||||
$model = new $model;
|
||||
//表名
|
||||
$table_name = $model->db()->getTable();
|
||||
//排序字段名
|
||||
$order_field_name = $model->order_field;
|
||||
//新增数据的所属排序号已有数据占用,则腾位处理(已占用的数据及其后面所有数据一起排序号腾位+1)
|
||||
if ($model->where($order)->where($wheres)->value($order_field_name) !== null) {
|
||||
$model->where($wheres)->where($order_field_name, '>=', $order[$order_field_name])->inc($order_field_name)->save();
|
||||
Db::name($table_name)
|
||||
->where($wheres)
|
||||
->where($order_field_name, '>=', $order)
|
||||
->inc($order_field_name)
|
||||
->update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序号删除处理
|
||||
* 注意:使用该方法时候要启动事务!!
|
||||
* @param \think\Model $model 模型层对象
|
||||
* @param array $order 排序字段名称
|
||||
* @param array $guids 数据guid集合
|
||||
* @param string $model 模型层命名空间地址
|
||||
* @param array $guid 主键
|
||||
* @param array $correl_fields 关联字段 例:["xxx_guid",...] 代表删除排序号时会根据这些字段来关联(例:所属xxx类型、所属xxx系列)来进行排序处理
|
||||
*/
|
||||
public static function sortDeleteProc(\think\Model $model, string $order_field_name, array $guids, array $correl_fields = [])
|
||||
public static function sortDeleteProc(string $model, string $guid, array $correl_fields = []): void
|
||||
{
|
||||
$guld_field_name = array_keys($guids)[0];
|
||||
//模型层实例化
|
||||
$model = new $model;
|
||||
//获取当前的主键字段名
|
||||
$guld_field_name = $model->db()->getPk();
|
||||
//获取当前表排序字段名
|
||||
$order_field_name = $model->order_field;
|
||||
//在所删除的数据之后的数据所属排序号将进行减位处理减位-1
|
||||
foreach ($guids[$guld_field_name] as $guld) {
|
||||
$find = $model->where($guld_field_name, $guld)->find();
|
||||
if ($find) {
|
||||
$con = [];
|
||||
foreach ($correl_fields as $correl_field) {
|
||||
$con[$correl_field] = $find[$correl_field];
|
||||
}
|
||||
$model->where($order_field_name, '>', $find[$order_field_name])
|
||||
->where($con)
|
||||
->dec($order_field_name)
|
||||
->save();
|
||||
if ($find = $model->where($guld_field_name, $guid)->find()) {
|
||||
$con = [];
|
||||
foreach ($correl_fields as $correl_field) {
|
||||
$con[$correl_field] = $find[$correl_field];
|
||||
}
|
||||
$model->where($order_field_name, '>', $find[$order_field_name])
|
||||
->where($con)
|
||||
->dec($order_field_name)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 祖级guid构建
|
||||
* @param string 模型层对象
|
||||
* @param string $parent_guid 父级guid
|
||||
* @param string $first_parent 首父级值 默认"0"
|
||||
*/
|
||||
public static function buildAncestorsGuid(string $model, string $parent_guid, string $first_parent = "0"): string
|
||||
{
|
||||
//模型层实例化
|
||||
$model = new $model;
|
||||
//获取当前的主键字段名
|
||||
$guld_field_name = $model->db()->getPk();
|
||||
//获取当前祖级主键集字段名
|
||||
$ancestors_guid_field = $model->ancestors_guid_field;
|
||||
if ($parent_guid == $first_parent) return $first_parent;
|
||||
$parent = $model->where($guld_field_name, $parent_guid)->find();
|
||||
if (!$parent) throwErrorMsg('该父级数据不存在!');
|
||||
return $parent[$ancestors_guid_field] . ',' . $parent_guid;
|
||||
}
|
||||
}
|
||||
|
199
app/common/model/Works/WorksType.php
Normal file
199
app/common/model/Works/WorksType.php
Normal file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\Works;
|
||||
|
||||
use app\common\arw\adjfut\src\Validate;
|
||||
use app\BaseModel;
|
||||
use think\model\concern\SoftDelete;
|
||||
use app\common\arw\adjfut\src\Excel;
|
||||
use app\Request;
|
||||
use app\common\exception\Tool;
|
||||
use think\facade\Db;
|
||||
|
||||
class WorksType extends BaseModel
|
||||
{
|
||||
use SoftDelete;
|
||||
// 删除字段
|
||||
protected $deleteTime = 'works_type_delete_time';
|
||||
// 设置主键名
|
||||
protected $pk = 'works_type_guid';
|
||||
// 设置废弃字段
|
||||
protected $disuse = [];
|
||||
// 设置字段信息
|
||||
protected $schema = [
|
||||
"works_type_id" => "int",
|
||||
"works_type_guid" => "string",
|
||||
"works_type_name" => "string",
|
||||
"works_type_order" => "int",
|
||||
"works_type_create_time" => "datetime",
|
||||
"works_type_create_user_guid" => "string",
|
||||
"works_type_update_time" => "datetime",
|
||||
"works_type_update_user_guid" => "string",
|
||||
"works_type_delete_time" => "datetime",
|
||||
"works_type_delete_user_guid" => "string",
|
||||
"works_type_parent_guid" => "string",
|
||||
"works_type_ancestors_guid" => "string",
|
||||
|
||||
];
|
||||
// 设置json类型字段
|
||||
protected $json = [''];
|
||||
// 开启自动写入时间戳字段
|
||||
protected $autoWriteTimestamp = 'datetime';
|
||||
// 创建时间
|
||||
protected $createTime = 'works_type_create_time';
|
||||
// 修改时间
|
||||
protected $updateTime = 'works_type_update_time';
|
||||
|
||||
//排序字段
|
||||
public $order_field = 'works_type_order';
|
||||
//父级主键
|
||||
public $parent_guid_field = 'works_type_parent_guid';
|
||||
//祖级主键集字段
|
||||
public $ancestors_guid_field = 'works_type_ancestors_guid';
|
||||
|
||||
// excel导入/下载模板表头
|
||||
public const EXCELFIELD = [
|
||||
'works_type_parent_name' => '上级类型名称',
|
||||
'works_type_name' => '*作品类型名称',
|
||||
'works_type_order' => '作品类型排序',
|
||||
];
|
||||
|
||||
/**
|
||||
* 新增前
|
||||
*/
|
||||
public static function onBeforeInsert(self $model): void
|
||||
{
|
||||
Validate::unique(self::class, $model->works_type_guid, $model->getData(), [
|
||||
'works_type_name' => '作品类型名称',
|
||||
]);
|
||||
$model->works_type_ancestors_guid = Tool::buildAncestorsGuid(self::class, $model->works_type_parent_guid);
|
||||
Tool::sortInsertProc(
|
||||
self::class,
|
||||
$model->works_type_order,
|
||||
['works_type_parent_guid' => $model->works_type_parent_guid]
|
||||
);
|
||||
$model->completeCreateField();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前
|
||||
*/
|
||||
public static function onBeforeUpdate(self $model): void
|
||||
{
|
||||
Validate::unique(self::class, $model->works_type_guid, $model->getData(), [
|
||||
'works_type_name' => '作品类型名称',
|
||||
]);
|
||||
$model->works_type_ancestors_guid = Tool::buildAncestorsGuid(self::class, $model->works_type_parent_guid);
|
||||
Tool::sortEditProc(
|
||||
self::class,
|
||||
$model->works_type_guid,
|
||||
$model->works_type_order,
|
||||
["works_type_parent_guid" => $model->works_type_parent_guid],
|
||||
);
|
||||
$model->completeUpdateField();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除前
|
||||
*/
|
||||
public static function onBeforeDelete(self $model): void
|
||||
{
|
||||
Tool::sortDeleteProc(self::class, $model->works_type_guid, ["works_type_parent_guid"]);
|
||||
$model->completeDeleteField();
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出Excel
|
||||
*
|
||||
* @param array $select导出的数据集合
|
||||
*/
|
||||
public static function exportExcel(array $select): void
|
||||
{
|
||||
$data = [array_values(self::EXCELFIELD)];
|
||||
foreach ($select as $key => $val) {
|
||||
$data[] = [
|
||||
$val['works_type_parent_name'] ?? "无",
|
||||
$val['works_type_name'],
|
||||
strval($val['works_type_order']),
|
||||
];
|
||||
}
|
||||
$excel = (new Excel())->exporTsheet($data);
|
||||
$excel->save('作品类型.xlsx');
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入excel
|
||||
*
|
||||
* @param \app\common\arw\adjfut\src\UploadFile $file 导入excel下载后的地址
|
||||
*/
|
||||
public static function importExcel(\app\common\arw\adjfut\src\UploadFile $file): string
|
||||
{
|
||||
$msg = [];
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
$excel = new Excel($file);
|
||||
$data = $excel->parseExcel(
|
||||
Tool::getExcelRule(self::EXCELFIELD),
|
||||
[
|
||||
'titleLine' => [1]
|
||||
]
|
||||
);
|
||||
if (!$data) throwErrorMsg('excel无数据', 1);
|
||||
$msg = [];
|
||||
foreach ($data as $line => $value) {
|
||||
try {
|
||||
$op = self::importExcelInit($value);
|
||||
if ($op == 'create') {
|
||||
$msg[] = "{$line} <span style='color:#27af49'>新增成功!</span><br>";
|
||||
} else {
|
||||
$msg[] = "{$line} <span style='color:#ce723b'>修改成功!</span><br>";
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$msg[] = "{$line} <span style='color:red'>{$th->getMessage()}</span><br>";
|
||||
}
|
||||
}
|
||||
Db::commit();
|
||||
return implode(', ', $msg);
|
||||
} catch (\Throwable $th) {
|
||||
Db::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入excel初始化
|
||||
*
|
||||
* @param array $value 每行数据
|
||||
*/
|
||||
public static function importExcelInit(array $value): string
|
||||
{
|
||||
$works_type_parent_name = $value['works_type_parent_name'];
|
||||
$works_type_name = $value['works_type_name'];
|
||||
$works_type_order = $value['works_type_order'];
|
||||
|
||||
//上级类型验证
|
||||
$works_type_parent_guid = "0";
|
||||
if ($works_type_parent_name) {
|
||||
$works_type_parent = self::where('works_type_name', $works_type_parent_name)->find();
|
||||
if (!$works_type_parent) throwErrorMsg('该上级类型名称不存在!');
|
||||
$works_type_parent_guid = $works_type_parent->works_type_guid;
|
||||
}
|
||||
|
||||
//修改/新增
|
||||
if ($works_type = self::where('works_type_name', $works_type_name)->find()) {
|
||||
$works_type->works_type_name = $works_type_name;
|
||||
$works_type->works_type_order = $works_type_order;
|
||||
$works_type->works_type_parent_guid = $works_type_parent_guid;
|
||||
$works_type->save();
|
||||
return 'update';
|
||||
} else {
|
||||
self::create([
|
||||
'works_type_name' => $works_type_name,
|
||||
'works_type_order' => $works_type_order,
|
||||
'works_type_parent_guid' => $works_type_parent_guid,
|
||||
]);
|
||||
return 'create';
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user