영상관리 파일 업로드 수정
This commit is contained in:
@@ -256,8 +256,7 @@ public class FIleChecker {
|
||||
return hasDriver;
|
||||
}
|
||||
|
||||
public static boolean mkDir(String dirPath)
|
||||
{
|
||||
public static boolean mkDir(String dirPath) {
|
||||
Path uploadTargetPath = Paths.get(dirPath);
|
||||
try {
|
||||
Files.createDirectories(uploadTargetPath);
|
||||
@@ -268,9 +267,6 @@ public class FIleChecker {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static List<Folder> getFolderAll(String dirPath, String sortType, int maxDepth) {
|
||||
|
||||
Path startPath = Paths.get(dirPath);
|
||||
@@ -454,12 +450,9 @@ public class FIleChecker {
|
||||
}
|
||||
|
||||
public static List<Basic> getFilesFromAllDepth(
|
||||
String dir,
|
||||
String targetFileNm,
|
||||
String extension) {
|
||||
String dir, String targetFileNm, String extension) {
|
||||
|
||||
return FIleChecker.getFilesFromAllDepth(
|
||||
dir, targetFileNm, extension, 100, "name", 0, 100);
|
||||
return FIleChecker.getFilesFromAllDepth(dir, targetFileNm, extension, 100, "name", 0, 100);
|
||||
}
|
||||
|
||||
public static Long getFileTotSize(List<FIleChecker.Basic> files) {
|
||||
@@ -472,21 +465,16 @@ public class FIleChecker {
|
||||
return fileTotSize;
|
||||
}
|
||||
|
||||
public static boolean checkExtensions(String fileName, String ext)
|
||||
{
|
||||
if( fileName == null )return false;
|
||||
public static boolean checkExtensions(String fileName, String ext) {
|
||||
if (fileName == null) return false;
|
||||
|
||||
if (!fileName
|
||||
.substring(fileName.lastIndexOf('.') + 1)
|
||||
.toLowerCase()
|
||||
.equals(ext)) {
|
||||
if (!fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase().equals(ext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static Set<String> createExtensionSet(String extensionString) {
|
||||
if (extensionString == null || extensionString.isBlank()) {
|
||||
return Set.of();
|
||||
|
||||
@@ -19,7 +19,8 @@ public class UserUtil {
|
||||
auth -> {
|
||||
CustomUserDetails user = (CustomUserDetails) auth.getPrincipal();
|
||||
MemberEntity m = user.getMember();
|
||||
return new MembersDto.Member(m.getId(), m.getName(), m.getEmployeeNo());
|
||||
return new MembersDto.Member(
|
||||
m.getId(), m.getName(), m.getEmployeeNo(), m.getUserRole());
|
||||
})
|
||||
.orElse(null);
|
||||
}
|
||||
@@ -38,4 +39,9 @@ public class UserUtil {
|
||||
MembersDto.Member user = getCurrentUser();
|
||||
return user != null ? user.getEmployeeNo() : null;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
MembersDto.Member user = getCurrentUser();
|
||||
return user != null ? user.getRole() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import org.springframework.stereotype.Component;
|
||||
@Setter
|
||||
public class FileConfig {
|
||||
|
||||
//private String rootSyncDir = "D:\\app\\original-images\\";
|
||||
//private String tmpSyncDir = rootSyncDir + "tmp\\";
|
||||
// private String rootSyncDir = "D:\\app\\original-images\\";
|
||||
// private String tmpSyncDir = rootSyncDir + "tmp\\";
|
||||
|
||||
private String rootSyncDir = "/app/original-images/";
|
||||
private String tmpSyncDir = rootSyncDir + "tmp/";
|
||||
|
||||
@@ -304,6 +304,4 @@ public class MapSheetMngDto {
|
||||
private Long hstUid;
|
||||
private Long fileSize;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -74,10 +74,7 @@ public class MapSheetMngService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public DmlReturn uploadPair(
|
||||
MultipartFile tfwFile,
|
||||
MultipartFile tifFile,
|
||||
Long hstUid) {
|
||||
public DmlReturn uploadPair(MultipartFile tfwFile, MultipartFile tifFile, Long hstUid) {
|
||||
|
||||
String rootPath = fileConfig.getRootSyncDir();
|
||||
String tmpPath = fileConfig.getTmpSyncDir();
|
||||
@@ -87,9 +84,8 @@ public class MapSheetMngService {
|
||||
return new DmlReturn("fail", "NO hstUid Data");
|
||||
}
|
||||
|
||||
//파일검증용 임시저장 폴더 확인
|
||||
if( ! FIleChecker.mkDir(tmpPath) )
|
||||
{
|
||||
// 파일검증용 임시저장 폴더 확인
|
||||
if (!FIleChecker.mkDir(tmpPath)) {
|
||||
return new DmlReturn("fail", "CREATE TEMP FOLDER ERROR");
|
||||
}
|
||||
|
||||
@@ -100,27 +96,22 @@ public class MapSheetMngService {
|
||||
return new DmlReturn("fail", "TIF SIZE 오류");
|
||||
}
|
||||
|
||||
//확장자명 체크
|
||||
if( ! FIleChecker.checkExtensions(tfwFile.getOriginalFilename(), "tfw") )
|
||||
{
|
||||
// 확장자명 체크
|
||||
if (!FIleChecker.checkExtensions(tfwFile.getOriginalFilename(), "tfw")) {
|
||||
return new DmlReturn("fail", "TFW FILENAME ERROR");
|
||||
}
|
||||
else if( ! FIleChecker.checkExtensions(tifFile.getOriginalFilename(), "tif") )
|
||||
{
|
||||
} else if (!FIleChecker.checkExtensions(tifFile.getOriginalFilename(), "tif")) {
|
||||
return new DmlReturn("fail", "TIF FILENAME ERROR");
|
||||
}
|
||||
|
||||
MngDto mngDto = mapSheetMngCoreService.findMapSheetMng(errDto.getMngYyyy());
|
||||
String targetYearDir = mngDto.getMngPath();
|
||||
|
||||
//중복체크
|
||||
// 중복체크
|
||||
List<FIleChecker.Basic> basicTfwList =
|
||||
FIleChecker.getFilesFromAllDepth(
|
||||
targetYearDir, tfwFile.getOriginalFilename(), "tfw");
|
||||
FIleChecker.getFilesFromAllDepth(targetYearDir, tfwFile.getOriginalFilename(), "tfw");
|
||||
|
||||
List<FIleChecker.Basic> basicTifList =
|
||||
FIleChecker.getFilesFromAllDepth(
|
||||
targetYearDir, tifFile.getOriginalFilename(), "tif");
|
||||
FIleChecker.getFilesFromAllDepth(targetYearDir, tifFile.getOriginalFilename(), "tif");
|
||||
|
||||
int tfwCnt =
|
||||
(int)
|
||||
@@ -138,7 +129,7 @@ public class MapSheetMngService {
|
||||
String tfwtifMsg = "";
|
||||
if (tfwCnt > 0) tfwtifMsg = tfwFile.getOriginalFilename();
|
||||
if (tifCnt > 0) {
|
||||
if( tfwCnt > 0 )tfwtifMsg = ","+tifFile.getOriginalFilename();
|
||||
if (tfwCnt > 0) tfwtifMsg = "," + tifFile.getOriginalFilename();
|
||||
else tfwtifMsg = tifFile.getOriginalFilename();
|
||||
}
|
||||
return new DmlReturn("duplicate", tfwtifMsg);
|
||||
@@ -172,7 +163,7 @@ public class MapSheetMngService {
|
||||
Path tfwTargetPath = null;
|
||||
Path tifTargetPath = null;
|
||||
|
||||
//파일이 존재하지 않을 경우(0개) 해당년도 다른 파일경로로 참조
|
||||
// 파일이 존재하지 않을 경우(0개) 해당년도 다른 파일경로로 참조
|
||||
if (uploadPath.isEmpty()) {
|
||||
MngFilesDto filesDto =
|
||||
mapSheetMngCoreService.findYyyyToMapSheetFilePathRefer(errDto.getMngYyyy());
|
||||
@@ -182,9 +173,8 @@ public class MapSheetMngService {
|
||||
tifTargetPath = Paths.get(uploadPath).resolve(tifFile.getOriginalFilename());
|
||||
}
|
||||
|
||||
//업로드 경로 확인(없으면 생성)
|
||||
if( ! FIleChecker.mkDir(uploadPath) )
|
||||
{
|
||||
// 업로드 경로 확인(없으면 생성)
|
||||
if (!FIleChecker.mkDir(uploadPath)) {
|
||||
return new DmlReturn("fail", "CREATE FOLDER ERROR");
|
||||
}
|
||||
|
||||
@@ -196,7 +186,8 @@ public class MapSheetMngService {
|
||||
}
|
||||
|
||||
// hst업데이트
|
||||
MapSheetMngDto.SyncCheckStateReqUpdateDto updReqSyncCheckState = new MapSheetMngDto.SyncCheckStateReqUpdateDto();
|
||||
MapSheetMngDto.SyncCheckStateReqUpdateDto updReqSyncCheckState =
|
||||
new MapSheetMngDto.SyncCheckStateReqUpdateDto();
|
||||
updReqSyncCheckState.setHstUid(hstUid);
|
||||
updReqSyncCheckState.setFilePath(uploadPath);
|
||||
updReqSyncCheckState.setSyncCheckTfwFileName(tfwFile.getOriginalFilename());
|
||||
@@ -234,7 +225,7 @@ public class MapSheetMngService {
|
||||
public DmlReturn deleteByFileUidMngFile(List<Long> fileUids) {
|
||||
|
||||
long hstUid = 0;
|
||||
//hstUid = 149049;
|
||||
// hstUid = 149049;
|
||||
|
||||
for (Long uid : fileUids) {
|
||||
MapSheetMngDto.MngFilesDto dto = mapSheetMngCoreService.findIdToMapSheetFile(uid);
|
||||
@@ -255,8 +246,8 @@ public class MapSheetMngService {
|
||||
DmlReturn dmlReturn = mapSheetMngCoreService.deleteByFileUidMngFile(uid);
|
||||
}
|
||||
|
||||
//중복제거 확인후 처리상태(DONE)변경
|
||||
if( hstUid > 0 )mapSheetMngCoreService.updateByHstUidSyncCheckState(hstUid);
|
||||
// 중복제거 확인후 처리상태(DONE)변경
|
||||
if (hstUid > 0) mapSheetMngCoreService.updateByHstUidSyncCheckState(hstUid);
|
||||
|
||||
return new DmlReturn("success", fileUids.size() + "개 파일이 삭제되었습니다.");
|
||||
}
|
||||
|
||||
@@ -179,5 +179,6 @@ public class MembersDto {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String employeeNo;
|
||||
private String role;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.kamco.cd.kamcoback.menu;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
||||
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
|
||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||
@@ -68,4 +69,12 @@ public class MenuApiController {
|
||||
|
||||
return ApiResponseDto.ok(ApiLogFunction.getUriMenuInfo(result, apiUri));
|
||||
}
|
||||
|
||||
@Operation(summary = "권한별 메뉴 조회", description = "권한별 메뉴 조")
|
||||
@GetMapping("/auth")
|
||||
public ApiResponseDto<String> getFindAllByRole() {
|
||||
UserUtil userUtil = new UserUtil();
|
||||
String role = userUtil.getRole();
|
||||
return null; // ApiResponseDto.ok(menuService.getFindByRole(role));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@@ -61,4 +62,23 @@ public class MenuDto {
|
||||
this.menuApiUrl = menuApiUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class RoleBasic {
|
||||
|
||||
private String menuUid;
|
||||
private String parentMenuUid;
|
||||
private String menuNm;
|
||||
private String menuUrl;
|
||||
private String description;
|
||||
private Long menuOrder;
|
||||
private Boolean isUse;
|
||||
private Boolean deleted;
|
||||
private Long createdUid;
|
||||
private Long updatedUid;
|
||||
private ZonedDateTime createdDttm;
|
||||
private ZonedDateTime updatedDttm;
|
||||
private String menuApiUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,21 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MenuService {
|
||||
|
||||
private final MenuCoreService menuCoreService;
|
||||
|
||||
@Cacheable(value = "menuFindAll")
|
||||
public List<MenuDto.Basic> getFindAll() {
|
||||
return menuCoreService.getFindAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한별 메뉴 목록
|
||||
*
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
// public List<MenuDto.MenuList> getFindByRole(String role) {
|
||||
// return menuCoreService.getFindByRole(role);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -246,18 +246,20 @@ public class MapSheetMngCoreService {
|
||||
|
||||
public MapSheetMngDto.DmlReturn updateByHstUidSyncCheckState(Long hstUid) {
|
||||
|
||||
MapSheetMngDto.SyncCheckStateReqUpdateDto reqDto = new MapSheetMngDto.SyncCheckStateReqUpdateDto();
|
||||
MapSheetMngDto.SyncCheckStateReqUpdateDto reqDto =
|
||||
new MapSheetMngDto.SyncCheckStateReqUpdateDto();
|
||||
reqDto.setHstUid(hstUid);
|
||||
|
||||
List<MapSheetMngDto.MngFilesDto> filesDto = mapSheetMngRepository.findHstUidToMapSheetFileList(hstUid);
|
||||
List<MapSheetMngDto.MngFilesDto> filesDto =
|
||||
mapSheetMngRepository.findHstUidToMapSheetFileList(hstUid);
|
||||
for (MapSheetMngDto.MngFilesDto dto : filesDto) {
|
||||
if( dto.getFileExt().equals("tif"))reqDto.setSyncCheckTifFileName(dto.getFileName());
|
||||
else if( dto.getFileExt().equals("tfw"))reqDto.setSyncCheckTfwFileName(dto.getFileName());
|
||||
if (dto.getFileExt().equals("tif")) reqDto.setSyncCheckTifFileName(dto.getFileName());
|
||||
else if (dto.getFileExt().equals("tfw")) reqDto.setSyncCheckTfwFileName(dto.getFileName());
|
||||
reqDto.setFilePath(dto.getFilePath());
|
||||
}
|
||||
|
||||
String fileState = "DONE";
|
||||
if( filesDto.size() > 2 )fileState = "DONE";
|
||||
if (filesDto.size() > 2) fileState = "DONE";
|
||||
|
||||
reqDto.setSyncCheckState(fileState);
|
||||
|
||||
@@ -266,5 +268,4 @@ public class MapSheetMngCoreService {
|
||||
|
||||
return new MapSheetMngDto.DmlReturn("success", hstUid + " : 상태변경되었습니다.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.kamco.cd.kamcoback.postgres.core;
|
||||
|
||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto.RoleBasic;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -16,4 +19,18 @@ public class MenuCoreService {
|
||||
public List<MenuDto.Basic> getFindAll() {
|
||||
return menuRepository.getFindAll().stream().map(MenuEntity::toDto).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한별 메뉴 목록
|
||||
*
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
public List<MenuDto.RoleBasic> getFindByRole(String role) {
|
||||
Map<String, RoleBasic> map = new LinkedHashMap<>();
|
||||
|
||||
List<MenuDto.RoleBasic> rows = menuRepository.getFindByRole(role);
|
||||
|
||||
return menuRepository.getFindByRole(role);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "tb_menu_mapp")
|
||||
public class MenuMappEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_menu_mapp_id_gen")
|
||||
@SequenceGenerator(
|
||||
name = "tb_menu_mapp_id_gen",
|
||||
sequenceName = "tb_menu_mapp_seq",
|
||||
allocationSize = 1)
|
||||
@Column(name = "mapp_uid", nullable = false)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "menu_uid", nullable = false)
|
||||
private MenuEntity menuUid;
|
||||
|
||||
@NotNull
|
||||
@ColumnDefault("false")
|
||||
@Column(name = "deleted", nullable = false)
|
||||
private Boolean deleted = false;
|
||||
|
||||
@Size(max = 50)
|
||||
@Column(name = "role_code", length = 50)
|
||||
private String roleCode;
|
||||
}
|
||||
@@ -642,7 +642,6 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
|
||||
.execute();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void mngFileSave(@Valid MapSheetMngDto.MngFileAddReq addReq) {
|
||||
long fileCount =
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.menu;
|
||||
|
||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||
import java.util.List;
|
||||
|
||||
public interface MenuRepositoryCustom {
|
||||
|
||||
List<MenuEntity> getFindAll();
|
||||
|
||||
/**
|
||||
* 권한별 메뉴 목록
|
||||
*
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
List<MenuDto.RoleBasic> getFindByRole(String role);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,65 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.menu;
|
||||
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuMappEntity.menuMappEntity;
|
||||
|
||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.StringExpression;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
public class MenuRepositoryImpl extends QuerydslRepositorySupport implements MenuRepositoryCustom {
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class MenuRepositoryImpl implements MenuRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
|
||||
|
||||
public MenuRepositoryImpl(JPAQueryFactory queryFactory) {
|
||||
super(MenuEntity.class);
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MenuEntity> getFindAll() {
|
||||
return queryFactory.selectFrom(menuEntity).where(menuEntity.deleted.isFalse()).fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한별 메뉴 목록
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<MenuDto.RoleBasic> getFindByRole(String role) {
|
||||
List<MenuDto.RoleBasic> content =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
MenuDto.RoleBasic.class,
|
||||
menuEntity.menuUid,
|
||||
menuEntity.parent.menuUid,
|
||||
menuEntity.menuNm,
|
||||
menuEntity.menuUrl,
|
||||
menuEntity.description,
|
||||
menuEntity.menuOrder,
|
||||
menuEntity.isUse,
|
||||
menuEntity.deleted,
|
||||
menuEntity.createdUid,
|
||||
menuEntity.updatedUid,
|
||||
menuEntity.createdDate,
|
||||
menuEntity.modifiedDate,
|
||||
menuEntity.menuApiUri))
|
||||
.from(menuMappEntity)
|
||||
.join(menuMappEntity.menuUid, menuEntity)
|
||||
.where(
|
||||
menuMappEntity.roleCode.eq(role),
|
||||
menuMappEntity.deleted.isFalse(),
|
||||
menuEntity.deleted.isFalse(),
|
||||
menuEntity.isUse.isTrue())
|
||||
.orderBy(menuEntity.menuOrder.asc().nullsLast(), menuEntity.menuNm.asc())
|
||||
.fetch();
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user