feat: add contact management and judge project assignment features
- Add MartialContact entity, mapper, service, and controller for contact management - Add updateProjects endpoint to MartialJudgeInviteController for project assignment - Fix MartialRegistrationOrderController for multi-project registration - Update MartialJudgeInviteVO with projects field Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
package org.springblade.modules.martial.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.boot.ctrl.BladeController;
|
||||||
|
import org.springblade.core.mp.support.Query;
|
||||||
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
|
import org.springblade.core.tool.api.R;
|
||||||
|
import org.springblade.core.tool.utils.Func;
|
||||||
|
import org.springblade.modules.martial.pojo.entity.MartialContact;
|
||||||
|
import org.springblade.modules.martial.service.IMartialContactService;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RequestMapping("/martial/contact")
|
||||||
|
@Tag(name = "联系人管理", description = "联系人接口")
|
||||||
|
public class MartialContactController extends BladeController {
|
||||||
|
|
||||||
|
private final IMartialContactService contactService;
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
@Operation(summary = "分页列表", description = "获取当前用户的联系人列表")
|
||||||
|
public R<IPage<MartialContact>> list(Query query) {
|
||||||
|
Long userId = AuthUtil.getUserId();
|
||||||
|
IPage<MartialContact> pages = contactService.getContactList(userId, query.getCurrent(), query.getSize());
|
||||||
|
return R.data(pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/detail")
|
||||||
|
@Operation(summary = "详情", description = "获取联系人详情")
|
||||||
|
public R<MartialContact> detail(@RequestParam Long id) {
|
||||||
|
return R.data(contactService.getContactDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/submit")
|
||||||
|
@Operation(summary = "保存", description = "新增或修改联系人")
|
||||||
|
public R<Boolean> submit(@RequestBody MartialContact contact) {
|
||||||
|
Long userId = AuthUtil.getUserId();
|
||||||
|
log.info("Contact submit - id: {}, name: {}, userId: {}", contact.getId(), contact.getName(), userId);
|
||||||
|
|
||||||
|
if (contact.getId() == null) {
|
||||||
|
contact.setCreateUser(userId);
|
||||||
|
contact.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
contact.setUpdateUser(userId);
|
||||||
|
contact.setUpdateTime(new Date());
|
||||||
|
|
||||||
|
return R.data(contactService.saveOrUpdate(contact));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/remove")
|
||||||
|
@Operation(summary = "删除", description = "删除联系人")
|
||||||
|
public R<Boolean> remove(@RequestParam String ids) {
|
||||||
|
return R.data(contactService.removeByIds(Func.toLongList(ids)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -224,4 +224,24 @@ public class MartialJudgeInviteController extends BladeController {
|
|||||||
// 使用EasyExcel或POI导出
|
// 使用EasyExcel或POI导出
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新邀请的项目分配
|
||||||
|
*/
|
||||||
|
@PutMapping("/updateProjects")
|
||||||
|
@Operation(summary = "更新项目分配", description = "更新裁判邀请的项目分配")
|
||||||
|
public R updateProjects(@RequestBody java.util.Map<String, Object> params) {
|
||||||
|
Long inviteId = Long.valueOf(params.get("inviteId").toString());
|
||||||
|
String projects = params.get("projects").toString();
|
||||||
|
|
||||||
|
MartialJudgeInvite invite = judgeInviteService.getById(inviteId);
|
||||||
|
if (invite == null) {
|
||||||
|
return R.fail("邀请记录不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
invite.setProjects(projects);
|
||||||
|
boolean success = judgeInviteService.updateById(invite);
|
||||||
|
return success ? R.success("更新成功") : R.fail("更新失败");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.springblade.modules.martial.controller;
|
package org.springblade.modules.martial.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@@ -25,7 +24,6 @@ import org.springblade.modules.martial.mapper.MartialTeamMemberMapper;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -84,7 +82,6 @@ public class MartialRegistrationOrderController extends BladeController {
|
|||||||
List<Long> athleteIds = Func.toLongList(dto.getAthleteIds());
|
List<Long> athleteIds = Func.toLongList(dto.getAthleteIds());
|
||||||
List<Long> teamIds = Func.toLongList(dto.getTeamIds());
|
List<Long> teamIds = Func.toLongList(dto.getTeamIds());
|
||||||
List<Long> projectIds = Func.toLongList(dto.getProjectIds());
|
List<Long> projectIds = Func.toLongList(dto.getProjectIds());
|
||||||
Long firstProjectId = projectIds.isEmpty() ? null : projectIds.get(0);
|
|
||||||
|
|
||||||
// Determine if this is a team registration
|
// Determine if this is a team registration
|
||||||
boolean isTeamRegistration = !teamIds.isEmpty();
|
boolean isTeamRegistration = !teamIds.isEmpty();
|
||||||
@@ -105,7 +102,7 @@ public class MartialRegistrationOrderController extends BladeController {
|
|||||||
log.info("订单创建成功,订单ID: {}", orderId);
|
log.info("订单创建成功,订单ID: {}", orderId);
|
||||||
|
|
||||||
if (isTeamRegistration) {
|
if (isTeamRegistration) {
|
||||||
// Handle team registration
|
// Handle team registration - create record for each team and each project
|
||||||
for (Long teamId : teamIds) {
|
for (Long teamId : teamIds) {
|
||||||
MartialTeam team = teamService.getById(teamId);
|
MartialTeam team = teamService.getById(teamId);
|
||||||
if (team == null) {
|
if (team == null) {
|
||||||
@@ -113,47 +110,60 @@ public class MartialRegistrationOrderController extends BladeController {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get team members
|
// Create a record for each project
|
||||||
LambdaQueryWrapper<MartialTeamMember> memberWrapper = new LambdaQueryWrapper<>();
|
for (Long projectId : projectIds) {
|
||||||
memberWrapper.eq(MartialTeamMember::getTeamId, teamId);
|
MartialAthlete teamAthlete = new MartialAthlete();
|
||||||
memberWrapper.eq(MartialTeamMember::getIsDeleted, 0);
|
teamAthlete.setOrderId(orderId);
|
||||||
List<MartialTeamMember> members = teamMemberMapper.selectList(memberWrapper);
|
teamAthlete.setCompetitionId(dto.getCompetitionId());
|
||||||
|
teamAthlete.setProjectId(projectId);
|
||||||
// Create a martial_athlete record for the team
|
teamAthlete.setTeamName(team.getTeamName());
|
||||||
MartialAthlete teamAthlete = new MartialAthlete();
|
teamAthlete.setPlayerName(team.getTeamName());
|
||||||
teamAthlete.setOrderId(orderId);
|
teamAthlete.setOrganization(team.getTeamName());
|
||||||
teamAthlete.setCompetitionId(dto.getCompetitionId());
|
teamAthlete.setRegistrationStatus(1);
|
||||||
teamAthlete.setProjectId(firstProjectId);
|
teamAthlete.setCompetitionStatus(0);
|
||||||
teamAthlete.setTeamName(team.getTeamName());
|
teamAthlete.setCreateUser(AuthUtil.getUserId());
|
||||||
teamAthlete.setPlayerName(team.getTeamName());
|
teamAthlete.setCreateTime(new java.util.Date());
|
||||||
teamAthlete.setOrganization(team.getTeamName());
|
teamAthlete.setTenantId("000000");
|
||||||
teamAthlete.setRegistrationStatus(1); // Auto confirm after payment
|
teamAthlete.setIsDeleted(0);
|
||||||
teamAthlete.setCompetitionStatus(0);
|
teamAthlete.setStatus(1);
|
||||||
teamAthlete.setCreateUser(AuthUtil.getUserId());
|
|
||||||
teamAthlete.setCreateTime(new java.util.Date());
|
athleteService.save(teamAthlete);
|
||||||
teamAthlete.setTenantId("000000");
|
log.info("创建集体参赛记录: teamName={}, projectId={}", team.getTeamName(), projectId);
|
||||||
teamAthlete.setIsDeleted(0);
|
}
|
||||||
teamAthlete.setStatus(1);
|
|
||||||
|
|
||||||
athleteService.save(teamAthlete);
|
|
||||||
log.info("创建集体参赛记录: teamName={}, athleteId={}", team.getTeamName(), teamAthlete.getId());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Handle individual registration
|
// Handle individual registration - create record for each athlete and each project
|
||||||
if (!athleteIds.isEmpty()) {
|
for (Long athleteId : athleteIds) {
|
||||||
LambdaUpdateWrapper<MartialAthlete> updateWrapper = new LambdaUpdateWrapper<>();
|
MartialAthlete existingAthlete = athleteService.getById(athleteId);
|
||||||
updateWrapper.in(MartialAthlete::getId, athleteIds)
|
if (existingAthlete == null) {
|
||||||
.set(MartialAthlete::getOrderId, orderId)
|
log.warn("选手不存在: {}", athleteId);
|
||||||
.set(MartialAthlete::getCompetitionId, dto.getCompetitionId());
|
continue;
|
||||||
|
|
||||||
if (firstProjectId != null) {
|
|
||||||
updateWrapper.set(MartialAthlete::getProjectId, firstProjectId);
|
|
||||||
}
|
}
|
||||||
// Auto confirm after payment
|
|
||||||
updateWrapper.set(MartialAthlete::getRegistrationStatus, 1);
|
|
||||||
|
|
||||||
boolean updated = athleteService.update(updateWrapper);
|
// Create a record for each project
|
||||||
log.info("更新选手关联,选手数量: {}, 更新结果: {}", athleteIds.size(), updated);
|
for (Long projectId : projectIds) {
|
||||||
|
MartialAthlete newRecord = new MartialAthlete();
|
||||||
|
newRecord.setOrderId(orderId);
|
||||||
|
newRecord.setCompetitionId(dto.getCompetitionId());
|
||||||
|
newRecord.setProjectId(projectId);
|
||||||
|
newRecord.setPlayerName(existingAthlete.getPlayerName());
|
||||||
|
newRecord.setGender(existingAthlete.getGender());
|
||||||
|
newRecord.setIdCard(existingAthlete.getIdCard());
|
||||||
|
newRecord.setIdCardType(existingAthlete.getIdCardType());
|
||||||
|
newRecord.setContactPhone(existingAthlete.getContactPhone());
|
||||||
|
newRecord.setOrganization(existingAthlete.getOrganization());
|
||||||
|
newRecord.setTeamName(existingAthlete.getTeamName());
|
||||||
|
newRecord.setRegistrationStatus(1);
|
||||||
|
newRecord.setCompetitionStatus(0);
|
||||||
|
newRecord.setCreateUser(AuthUtil.getUserId());
|
||||||
|
newRecord.setCreateTime(new java.util.Date());
|
||||||
|
newRecord.setTenantId("000000");
|
||||||
|
newRecord.setIsDeleted(0);
|
||||||
|
newRecord.setStatus(1);
|
||||||
|
|
||||||
|
athleteService.save(newRecord);
|
||||||
|
log.info("创建选手参赛记录: playerName={}, projectId={}", existingAthlete.getPlayerName(), projectId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.springblade.modules.martial.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.springblade.modules.martial.pojo.entity.MartialContact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact Mapper
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface MartialContactMapper extends BaseMapper<MartialContact> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package org.springblade.modules.martial.pojo.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springblade.core.tenant.mp.TenantEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact entity
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("martial_contact")
|
||||||
|
@Schema(description = "联系人")
|
||||||
|
public class MartialContact extends TenantEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "证件类型")
|
||||||
|
private String idType;
|
||||||
|
|
||||||
|
@Schema(description = "姓名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "证件号码")
|
||||||
|
private String idCard;
|
||||||
|
|
||||||
|
@Schema(description = "手机号码")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Schema(description = "邮箱")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Schema(description = "地址")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Schema(description = "是否默认联系人")
|
||||||
|
private Boolean isDefault;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -80,4 +80,15 @@ public class MartialJudgeInviteVO extends MartialJudgeInvite {
|
|||||||
@Schema(description = "场地名称")
|
@Schema(description = "场地名称")
|
||||||
private String venueName;
|
private String venueName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取场地名称
|
||||||
|
* 总裁(referee_type=3)显示全部场地
|
||||||
|
*/
|
||||||
|
public String getVenueName() {
|
||||||
|
if (this.getRefereeType() != null && this.getRefereeType() == 3) {
|
||||||
|
return "全部场地";
|
||||||
|
}
|
||||||
|
return venueName;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.springblade.modules.martial.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.springblade.modules.martial.pojo.entity.MartialContact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact Service Interface
|
||||||
|
*/
|
||||||
|
public interface IMartialContactService extends IService<MartialContact> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get contact list by user
|
||||||
|
*/
|
||||||
|
IPage<MartialContact> getContactList(Long userId, Integer current, Integer size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get contact detail
|
||||||
|
*/
|
||||||
|
MartialContact getContactDetail(Long id);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.springblade.modules.martial.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.modules.martial.mapper.MartialContactMapper;
|
||||||
|
import org.springblade.modules.martial.pojo.entity.MartialContact;
|
||||||
|
import org.springblade.modules.martial.service.IMartialContactService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact Service Implementation
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MartialContactServiceImpl extends ServiceImpl<MartialContactMapper, MartialContact> implements IMartialContactService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPage<MartialContact> getContactList(Long userId, Integer current, Integer size) {
|
||||||
|
Page<MartialContact> page = new Page<>(current, size);
|
||||||
|
LambdaQueryWrapper<MartialContact> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(MartialContact::getCreateUser, userId);
|
||||||
|
wrapper.eq(MartialContact::getIsDeleted, 0);
|
||||||
|
wrapper.orderByDesc(MartialContact::getIsDefault);
|
||||||
|
wrapper.orderByDesc(MartialContact::getCreateTime);
|
||||||
|
return this.page(page, wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MartialContact getContactDetail(Long id) {
|
||||||
|
return this.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -152,18 +152,25 @@ public class MartialRegistrationOrderServiceImpl extends ServiceImpl<MartialRegi
|
|||||||
if (!athletes.isEmpty()) {
|
if (!athletes.isEmpty()) {
|
||||||
String athleteNames = athletes.stream()
|
String athleteNames = athletes.stream()
|
||||||
.map(MartialAthlete::getPlayerName)
|
.map(MartialAthlete::getPlayerName)
|
||||||
|
.distinct()
|
||||||
.collect(Collectors.joining("、"));
|
.collect(Collectors.joining("、"));
|
||||||
vo.setAthleteNames(athleteNames);
|
vo.setAthleteNames(athleteNames);
|
||||||
|
|
||||||
List<MartialRegistrationOrderVO.AthleteInfo> athleteList = athletes.stream()
|
List<MartialRegistrationOrderVO.AthleteInfo> athleteList = athletes.stream()
|
||||||
.map(athlete -> {
|
.collect(Collectors.toMap(
|
||||||
MartialRegistrationOrderVO.AthleteInfo info = new MartialRegistrationOrderVO.AthleteInfo();
|
MartialAthlete::getPlayerName,
|
||||||
info.setId(athlete.getId());
|
athlete -> {
|
||||||
info.setPlayerName(athlete.getPlayerName());
|
MartialRegistrationOrderVO.AthleteInfo info = new MartialRegistrationOrderVO.AthleteInfo();
|
||||||
info.setGender(athlete.getGender());
|
info.setId(athlete.getId());
|
||||||
info.setIdCard(athlete.getIdCard());
|
info.setPlayerName(athlete.getPlayerName());
|
||||||
return info;
|
info.setGender(athlete.getGender());
|
||||||
})
|
info.setIdCard(athlete.getIdCard());
|
||||||
|
return info;
|
||||||
|
},
|
||||||
|
(existing, replacement) -> existing
|
||||||
|
))
|
||||||
|
.values()
|
||||||
|
.stream()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
vo.setAthleteList(athleteList);
|
vo.setAthleteList(athleteList);
|
||||||
|
|
||||||
@@ -242,18 +249,25 @@ public class MartialRegistrationOrderServiceImpl extends ServiceImpl<MartialRegi
|
|||||||
if (!athletes.isEmpty()) {
|
if (!athletes.isEmpty()) {
|
||||||
String athleteNames = athletes.stream()
|
String athleteNames = athletes.stream()
|
||||||
.map(MartialAthlete::getPlayerName)
|
.map(MartialAthlete::getPlayerName)
|
||||||
|
.distinct()
|
||||||
.collect(Collectors.joining("、"));
|
.collect(Collectors.joining("、"));
|
||||||
vo.setAthleteNames(athleteNames);
|
vo.setAthleteNames(athleteNames);
|
||||||
|
|
||||||
List<MartialRegistrationOrderVO.AthleteInfo> athleteList = athletes.stream()
|
List<MartialRegistrationOrderVO.AthleteInfo> athleteList = athletes.stream()
|
||||||
.map(athlete -> {
|
.collect(Collectors.toMap(
|
||||||
MartialRegistrationOrderVO.AthleteInfo info = new MartialRegistrationOrderVO.AthleteInfo();
|
MartialAthlete::getPlayerName,
|
||||||
info.setId(athlete.getId());
|
athlete -> {
|
||||||
info.setPlayerName(athlete.getPlayerName());
|
MartialRegistrationOrderVO.AthleteInfo info = new MartialRegistrationOrderVO.AthleteInfo();
|
||||||
info.setGender(athlete.getGender());
|
info.setId(athlete.getId());
|
||||||
info.setIdCard(athlete.getIdCard());
|
info.setPlayerName(athlete.getPlayerName());
|
||||||
return info;
|
info.setGender(athlete.getGender());
|
||||||
})
|
info.setIdCard(athlete.getIdCard());
|
||||||
|
return info;
|
||||||
|
},
|
||||||
|
(existing, replacement) -> existing
|
||||||
|
))
|
||||||
|
.values()
|
||||||
|
.stream()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
vo.setAthleteList(athleteList);
|
vo.setAthleteList(athleteList);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user