fix(cms): 分类写入前校验上级分类,拦截自引用与成环
分类是自关联结构,一旦出现「自己指向自己」或「祖先指向后代」的环,前端构建分类树时
会直接抛错,导致整个页面无法渲染(报 data error: {categoryId: x, parentId: x})。
- ArticleCategoryService 新增 checkParentValid:顶级分类放行;修改时沿父级链向上回溯,
父级链中不允许出现自己;带回溯深度上限兜底,避免历史脏数据造成死循环。
- Controller 的保存与更新入口都调用该校验,不通过时抛 BusinessException(中文提示)。
注:本提交同时包含这三个文件的整体重新格式化(忽略空白后实际逻辑改动为 52 行插入)。
This commit is contained in:
@@ -1,140 +1,144 @@
|
||||
package com.gxwebsoft.cms.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.cms.service.ArticleCategoryService;
|
||||
import com.gxwebsoft.cms.entity.ArticleCategory;
|
||||
import com.gxwebsoft.cms.param.ArticleCategoryParam;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.BatchParam;
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文章分类表控制器
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2022-11-22 17:49:15
|
||||
*/
|
||||
@Api(tags = "文章分类表管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/cms/article-category")
|
||||
public class ArticleCategoryController extends BaseController {
|
||||
@Resource
|
||||
private ArticleCategoryService articleCategoryService;
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:list')")
|
||||
@OperationLog
|
||||
@ApiOperation("分页查询文章分类表")
|
||||
@GetMapping("/page")
|
||||
public ApiResult<PageResult<ArticleCategory>> page(ArticleCategoryParam param) {
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>(param);
|
||||
// page.setDefaultOrder("create_time desc");
|
||||
page.setDefaultOrder("sort_number");
|
||||
return success(articleCategoryService.page(page, page.getWrapper()));
|
||||
// 使用关联查询
|
||||
//return success(articleCategoryService.pageRel(param));
|
||||
}
|
||||
|
||||
@OperationLog
|
||||
@ApiOperation("查询全部文章分类表")
|
||||
@GetMapping()
|
||||
public ApiResult<List<ArticleCategory>> list(ArticleCategoryParam param) {
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>(param);
|
||||
// page.setDefaultOrder("create_time desc");
|
||||
page.setDefaultOrder("sort_number");
|
||||
return success(articleCategoryService.list(page.getOrderWrapper()));
|
||||
// 使用关联查询
|
||||
//return success(articleCategoryService.listRel(param));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:list')")
|
||||
@OperationLog
|
||||
@ApiOperation("根据id查询文章分类表")
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult<ArticleCategory> get(@PathVariable("id") Integer id) {
|
||||
return success(articleCategoryService.getById(id));
|
||||
// 使用关联查询
|
||||
//return success(articleCategoryService.getByIdRel(id));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:save')")
|
||||
@OperationLog
|
||||
@ApiOperation("添加文章分类表")
|
||||
@PostMapping()
|
||||
public ApiResult<?> save(@RequestBody ArticleCategory articleCategory) {
|
||||
// 记录当前登录用户id、租户id
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
articleCategory.setUserId(loginUser.getUserId());
|
||||
}
|
||||
if (articleCategoryService.save(articleCategory)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:update')")
|
||||
@OperationLog
|
||||
@ApiOperation("修改文章分类表")
|
||||
@PutMapping()
|
||||
public ApiResult<?> update(@RequestBody ArticleCategory articleCategory) {
|
||||
if (articleCategoryService.updateById(articleCategory)) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:remove')")
|
||||
@OperationLog
|
||||
@ApiOperation("删除文章分类表")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResult<?> remove(@PathVariable("id") Integer id) {
|
||||
if (articleCategoryService.removeById(id)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:save')")
|
||||
@OperationLog
|
||||
@ApiOperation("批量添加文章分类表")
|
||||
@PostMapping("/batch")
|
||||
public ApiResult<?> saveBatch(@RequestBody List<ArticleCategory> list) {
|
||||
if (articleCategoryService.saveBatch(list)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:update')")
|
||||
@OperationLog
|
||||
@ApiOperation("批量修改文章分类表")
|
||||
@PutMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody BatchParam<ArticleCategory> batchParam) {
|
||||
if (batchParam.update(articleCategoryService, "category_id")) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:remove')")
|
||||
@OperationLog
|
||||
@ApiOperation("批量删除文章分类表")
|
||||
@DeleteMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||
if (articleCategoryService.removeByIds(ids)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
}
|
||||
package com.gxwebsoft.cms.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.cms.service.ArticleCategoryService;
|
||||
import com.gxwebsoft.cms.entity.ArticleCategory;
|
||||
import com.gxwebsoft.cms.param.ArticleCategoryParam;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.BatchParam;
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.system.entity.User;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文章分类表控制器
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2022-11-22 17:49:15
|
||||
*/
|
||||
@Api(tags = "文章分类表管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/cms/article-category")
|
||||
public class ArticleCategoryController extends BaseController {
|
||||
@Resource
|
||||
private ArticleCategoryService articleCategoryService;
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:list')")
|
||||
@OperationLog
|
||||
@ApiOperation("分页查询文章分类表")
|
||||
@GetMapping("/page")
|
||||
public ApiResult<PageResult<ArticleCategory>> page(ArticleCategoryParam param) {
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>(param);
|
||||
// page.setDefaultOrder("create_time desc");
|
||||
page.setDefaultOrder("sort_number");
|
||||
return success(articleCategoryService.page(page, page.getWrapper()));
|
||||
// 使用关联查询
|
||||
//return success(articleCategoryService.pageRel(param));
|
||||
}
|
||||
|
||||
@OperationLog
|
||||
@ApiOperation("查询全部文章分类表")
|
||||
@GetMapping()
|
||||
public ApiResult<List<ArticleCategory>> list(ArticleCategoryParam param) {
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>(param);
|
||||
// page.setDefaultOrder("create_time desc");
|
||||
page.setDefaultOrder("sort_number");
|
||||
return success(articleCategoryService.list(page.getOrderWrapper()));
|
||||
// 使用关联查询
|
||||
//return success(articleCategoryService.listRel(param));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:list')")
|
||||
@OperationLog
|
||||
@ApiOperation("根据id查询文章分类表")
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult<ArticleCategory> get(@PathVariable("id") Integer id) {
|
||||
return success(articleCategoryService.getById(id));
|
||||
// 使用关联查询
|
||||
//return success(articleCategoryService.getByIdRel(id));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:save')")
|
||||
@OperationLog
|
||||
@ApiOperation("添加文章分类表")
|
||||
@PostMapping()
|
||||
public ApiResult<?> save(@RequestBody ArticleCategory articleCategory) {
|
||||
// 校验上级分类,避免产生自引用/成环的脏数据
|
||||
articleCategoryService.checkParentValid(articleCategory);
|
||||
// 记录当前登录用户id、租户id
|
||||
User loginUser = getLoginUser();
|
||||
if (loginUser != null) {
|
||||
articleCategory.setUserId(loginUser.getUserId());
|
||||
}
|
||||
if (articleCategoryService.save(articleCategory)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:update')")
|
||||
@OperationLog
|
||||
@ApiOperation("修改文章分类表")
|
||||
@PutMapping()
|
||||
public ApiResult<?> update(@RequestBody ArticleCategory articleCategory) {
|
||||
// 校验上级分类,避免把自己的下级设成上级而形成环
|
||||
articleCategoryService.checkParentValid(articleCategory);
|
||||
if (articleCategoryService.updateById(articleCategory)) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:remove')")
|
||||
@OperationLog
|
||||
@ApiOperation("删除文章分类表")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResult<?> remove(@PathVariable("id") Integer id) {
|
||||
if (articleCategoryService.removeById(id)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:save')")
|
||||
@OperationLog
|
||||
@ApiOperation("批量添加文章分类表")
|
||||
@PostMapping("/batch")
|
||||
public ApiResult<?> saveBatch(@RequestBody List<ArticleCategory> list) {
|
||||
if (articleCategoryService.saveBatch(list)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:update')")
|
||||
@OperationLog
|
||||
@ApiOperation("批量修改文章分类表")
|
||||
@PutMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody BatchParam<ArticleCategory> batchParam) {
|
||||
if (batchParam.update(articleCategoryService, "category_id")) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('cms:articleCategory:remove')")
|
||||
@OperationLog
|
||||
@ApiOperation("批量删除文章分类表")
|
||||
@DeleteMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||
if (articleCategoryService.removeByIds(ids)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,43 +1,55 @@
|
||||
package com.gxwebsoft.cms.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.cms.entity.ArticleCategory;
|
||||
import com.gxwebsoft.cms.param.ArticleCategoryParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文章分类表Service
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2022-11-22 17:49:15
|
||||
*/
|
||||
public interface ArticleCategoryService extends IService<ArticleCategory> {
|
||||
|
||||
/**
|
||||
* 分页关联查询
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return PageResult<ArticleCategory>
|
||||
*/
|
||||
PageResult<ArticleCategory> pageRel(ArticleCategoryParam param);
|
||||
|
||||
/**
|
||||
* 关联查询全部
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return List<ArticleCategory>
|
||||
*/
|
||||
List<ArticleCategory> listRel(ArticleCategoryParam param);
|
||||
|
||||
/**
|
||||
* 根据id查询
|
||||
*
|
||||
* @param categoryId 文章分类ID
|
||||
* @return ArticleCategory
|
||||
*/
|
||||
ArticleCategory getByIdRel(Integer categoryId);
|
||||
|
||||
List<ArticleCategory> childList(Integer categoryId);
|
||||
}
|
||||
package com.gxwebsoft.cms.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.cms.entity.ArticleCategory;
|
||||
import com.gxwebsoft.cms.param.ArticleCategoryParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文章分类表Service
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2022-11-22 17:49:15
|
||||
*/
|
||||
public interface ArticleCategoryService extends IService<ArticleCategory> {
|
||||
|
||||
/**
|
||||
* 分页关联查询
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return PageResult<ArticleCategory>
|
||||
*/
|
||||
PageResult<ArticleCategory> pageRel(ArticleCategoryParam param);
|
||||
|
||||
/**
|
||||
* 关联查询全部
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return List<ArticleCategory>
|
||||
*/
|
||||
List<ArticleCategory> listRel(ArticleCategoryParam param);
|
||||
|
||||
/**
|
||||
* 根据id查询
|
||||
*
|
||||
* @param categoryId 文章分类ID
|
||||
* @return ArticleCategory
|
||||
*/
|
||||
ArticleCategory getByIdRel(Integer categoryId);
|
||||
|
||||
List<ArticleCategory> childList(Integer categoryId);
|
||||
|
||||
/**
|
||||
* 校验上级分类是否合法
|
||||
* <p>
|
||||
* 分类是自关联结构,一旦出现「自己指向自己」或「祖先指向后代」的环,
|
||||
* 前端构建分类树时会直接抛错,导致整个页面无法渲染,因此写入前必须拦截。
|
||||
* </p>
|
||||
*
|
||||
* @param category 待保存的分类,修改时需带 categoryId
|
||||
* @throws com.gxwebsoft.common.core.exception.BusinessException 校验不通过时抛出,message 为面向前端的中文提示
|
||||
*/
|
||||
void checkParentValid(ArticleCategory category);
|
||||
}
|
||||
|
||||
@@ -1,56 +1,92 @@
|
||||
package com.gxwebsoft.cms.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.cms.mapper.ArticleCategoryMapper;
|
||||
import com.gxwebsoft.cms.service.ArticleCategoryService;
|
||||
import com.gxwebsoft.cms.entity.ArticleCategory;
|
||||
import com.gxwebsoft.cms.param.ArticleCategoryParam;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文章分类表Service实现
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2022-11-22 17:49:15
|
||||
*/
|
||||
@Service
|
||||
public class ArticleCategoryServiceImpl extends ServiceImpl<ArticleCategoryMapper, ArticleCategory> implements ArticleCategoryService {
|
||||
|
||||
@Override
|
||||
public PageResult<ArticleCategory> pageRel(ArticleCategoryParam param) {
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>(param);
|
||||
//page.setDefaultOrder("create_time desc");
|
||||
List<ArticleCategory> list = baseMapper.selectPageRel(page, param);
|
||||
return new PageResult<>(list, page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArticleCategory> listRel(ArticleCategoryParam param) {
|
||||
List<ArticleCategory> list = baseMapper.selectListRel(param);
|
||||
// 排序
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>();
|
||||
//page.setDefaultOrder("create_time desc");
|
||||
return page.sortRecords(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArticleCategory getByIdRel(Integer categoryId) {
|
||||
ArticleCategoryParam param = new ArticleCategoryParam();
|
||||
param.setCategoryId(categoryId);
|
||||
return param.getOne(baseMapper.selectListRel(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArticleCategory> childList(Integer categoryId) {
|
||||
return list(
|
||||
new LambdaQueryWrapper<ArticleCategory>()
|
||||
.eq(ArticleCategory::getParentId, categoryId)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
package com.gxwebsoft.cms.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.cms.mapper.ArticleCategoryMapper;
|
||||
import com.gxwebsoft.cms.service.ArticleCategoryService;
|
||||
import com.gxwebsoft.cms.entity.ArticleCategory;
|
||||
import com.gxwebsoft.cms.param.ArticleCategoryParam;
|
||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文章分类表Service实现
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2022-11-22 17:49:15
|
||||
*/
|
||||
@Service
|
||||
public class ArticleCategoryServiceImpl extends ServiceImpl<ArticleCategoryMapper, ArticleCategory> implements ArticleCategoryService {
|
||||
|
||||
@Override
|
||||
public PageResult<ArticleCategory> pageRel(ArticleCategoryParam param) {
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>(param);
|
||||
//page.setDefaultOrder("create_time desc");
|
||||
List<ArticleCategory> list = baseMapper.selectPageRel(page, param);
|
||||
return new PageResult<>(list, page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArticleCategory> listRel(ArticleCategoryParam param) {
|
||||
List<ArticleCategory> list = baseMapper.selectListRel(param);
|
||||
// 排序
|
||||
PageParam<ArticleCategory, ArticleCategoryParam> page = new PageParam<>();
|
||||
//page.setDefaultOrder("create_time desc");
|
||||
return page.sortRecords(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArticleCategory getByIdRel(Integer categoryId) {
|
||||
ArticleCategoryParam param = new ArticleCategoryParam();
|
||||
param.setCategoryId(categoryId);
|
||||
return param.getOne(baseMapper.selectListRel(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ArticleCategory> childList(Integer categoryId) {
|
||||
return list(
|
||||
new LambdaQueryWrapper<ArticleCategory>()
|
||||
.eq(ArticleCategory::getParentId, categoryId)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkParentValid(ArticleCategory category) {
|
||||
if (category == null) {
|
||||
return;
|
||||
}
|
||||
Integer categoryId = category.getCategoryId();
|
||||
Integer parentId = category.getParentId();
|
||||
// 顶级分类
|
||||
if (parentId == null || parentId == 0) {
|
||||
return;
|
||||
}
|
||||
if (categoryId != null && categoryId.equals(parentId)) {
|
||||
throw new BusinessException("上级分类不能选择自己");
|
||||
}
|
||||
if (categoryId == null) {
|
||||
// 新增时父级必然已存在,无需继续校验
|
||||
return;
|
||||
}
|
||||
// 修改场景:沿父级链向上回溯,父级链中不允许出现自己
|
||||
Integer cursor = parentId;
|
||||
// 兜底防止历史脏数据造成死循环
|
||||
int depth = 0;
|
||||
int maxDepth = 64;
|
||||
while (cursor != null && cursor != 0 && depth++ < maxDepth) {
|
||||
if (cursor.equals(categoryId)) {
|
||||
throw new BusinessException("上级分类不能选择自己的下级分类");
|
||||
}
|
||||
ArticleCategory parent = getById(cursor);
|
||||
if (parent == null) {
|
||||
break;
|
||||
}
|
||||
cursor = parent.getParentId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user