项目状态看板导出
This commit is contained in:
+15
-5
@@ -2,26 +2,35 @@ package com.jero.modules.ota.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.jero.common.api.vo.Result;
|
||||
import com.jero.common.aspect.annotation.AutoLog;
|
||||
import com.jero.common.system.base.controller.JeroController;
|
||||
import com.jero.common.util.PageUtil;
|
||||
import com.jero.modules.ota.entity.OtaManageApplyEO;
|
||||
import com.jero.modules.ota.entity.OtaManageReceive;
|
||||
import com.jero.modules.ota.service.IOtaManageApplyEOService;
|
||||
import com.jero.modules.ota.vo.VersionVO;
|
||||
import com.jero.modules.project.entity.ProjectLibraryBase;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
@@ -292,7 +301,8 @@ public class OtaManageApplyEOController extends JeroController<OtaManageApplyEO,
|
||||
@ApiOperation(value = "通过软件版本和项目ID查询状态", notes = "通过软件版本和项目ID查询状态")
|
||||
@GetMapping(value = "/getStatisticalStatus")
|
||||
public Result<?> getStatisticalStatus(String projectId, String plannedBpLaunchBatch, String cut) {
|
||||
List<Map<String, Object>> res = otaManageApplyEOService.getStatisticalStatus(projectId, plannedBpLaunchBatch, cut);
|
||||
List<ProjectLibraryBase> projectLibraryBaseList = new ArrayList<>();
|
||||
List<Map<String, Object>> res = otaManageApplyEOService.getStatisticalStatus(projectId, plannedBpLaunchBatch, cut,projectLibraryBaseList);
|
||||
if(!res.isEmpty()){
|
||||
return Result.OK("操作成功!", res.get(0));
|
||||
}else{
|
||||
|
||||
+7
-1
@@ -19,7 +19,13 @@
|
||||
select * from ota_manage_apply
|
||||
JOIN ota_manage_receive ON ota_manage_apply.vdr = ota_manage_receive.id
|
||||
<where>
|
||||
ota_manage_apply.project_version =#{projectId}
|
||||
<if test="projectId != null and projectId != ''">
|
||||
ota_manage_apply.project_version in
|
||||
<foreach collection="projectId.split(',')" index="index" item="item" open="(" separator="," close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
</if>
|
||||
|
||||
<if test="plannedBpLaunchBatch != null and plannedBpLaunchBatch != ''">
|
||||
and ota_manage_receive.planned_bp_launch_batch =#{plannedBpLaunchBatch}
|
||||
</if>
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ package com.jero.modules.ota.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.jero.modules.ota.entity.OtaManageApplyEO;
|
||||
import com.jero.modules.ota.entity.OtaManageReceive;
|
||||
import com.jero.modules.ota.vo.VersionVO;
|
||||
import com.jero.modules.project.entity.ProjectLibraryBase;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -127,7 +127,7 @@ public interface IOtaManageApplyEOService extends IService<OtaManageApplyEO> {
|
||||
|
||||
List<OtaManageApplyEO> getVdrListByProject(String projectId, String cut);
|
||||
|
||||
List<Map<String, Object>> getStatisticalStatus(String projectId, String plannedBpLaunchBatch, String cut);
|
||||
List<Map<String, Object>> getStatisticalStatus(String projectId, String plannedBpLaunchBatch, String cut,List<ProjectLibraryBase> projectLibraryBaseList);
|
||||
|
||||
ModelAndView otaExportXls(HttpServletRequest request, OtaManageApplyEO otaManageApplyEO);
|
||||
|
||||
|
||||
+11
-2
@@ -1470,9 +1470,14 @@ public class OtaManageApplyEOServiceImpl extends ServiceImpl<OtaManageApplyEOMap
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getStatisticalStatus(String projectId, String plannedBpLaunchBatch, String cut) {
|
||||
List<OtaManageApplyEO> receiveList = this.getBaseMapper().getListByProjectId(projectId, plannedBpLaunchBatch);
|
||||
public List<Map<String, Object>> getStatisticalStatus(String projectId, String plannedBpLaunchBatch, String cut,List<ProjectLibraryBase> plbEoList) {
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
List<ProjectLibraryBase> projectLibraryBaseList = new ArrayList<>();
|
||||
if(!plbEoList.isEmpty()){
|
||||
projectLibraryBaseList = plbEoList.stream().filter(e -> e.getId().equals(projectId)).collect(Collectors.toList());
|
||||
}
|
||||
List<OtaManageApplyEO> receiveList = this.getBaseMapper().getListByProjectId(projectId, plannedBpLaunchBatch);
|
||||
|
||||
if (!receiveList.isEmpty()) {
|
||||
List<String> plannedBpLaunchBatchList = receiveList.stream()
|
||||
.filter(e -> StringUtils.isNotBlank(e.getPlannedBpLaunchBatch()))
|
||||
@@ -1564,6 +1569,10 @@ public class OtaManageApplyEOServiceImpl extends ServiceImpl<OtaManageApplyEOMap
|
||||
attestationScheduleMap.put(CertificationProgressEnum.COMPONENT_REPORT_SUBMITTED.getValue().replace(" ", "_"), submitted);
|
||||
attestationScheduleMap.put(CertificationProgressEnum.COMPONENT_REPORT_HAS_BEEN_STORED.getValue().replace(" ", "_"), stored);
|
||||
statisticalMap.put("attestationScheduleMap", attestationScheduleMap);
|
||||
|
||||
if(!projectLibraryBaseList.isEmpty()){
|
||||
statisticalMap.put("showName", projectLibraryBaseList.get(0).getShowName());
|
||||
}
|
||||
result.add(statisticalMap);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3162,7 +3162,7 @@ public class ProjectLibraryBaseServiceImpl extends ServiceImpl<ProjectLibraryBas
|
||||
}
|
||||
|
||||
String projectLibraryId = (String) params.get("projectLibraryId");
|
||||
List<Map<String, Object>> mapList = otaManageApplyEOService.getStatisticalStatus(projectLibraryId, null, cut);
|
||||
List<Map<String, Object>> mapList = otaManageApplyEOService.getStatisticalStatus(projectLibraryId, null, cut,null);
|
||||
|
||||
if(ObjectUtils.isNotEmpty(mapList)){
|
||||
int dataIndex = 2;
|
||||
|
||||
+162
-10
@@ -1,13 +1,10 @@
|
||||
package com.jero.modules.project.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyuncs.utils.IOUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.jero.common.constant.enums.CutEnum;
|
||||
import com.jero.common.exception.JeroBootException;
|
||||
import com.jero.common.system.query.QueryGenerator;
|
||||
import com.jero.common.system.vo.DictModel;
|
||||
import com.jero.common.system.vo.LoginUser;
|
||||
import com.jero.common.util.DateUtils;
|
||||
import com.jero.modules.cert.collect.entity.ParamsCollectManifestEO;
|
||||
@@ -15,10 +12,22 @@ import com.jero.modules.cert.collect.entity.ParamsManifestEO;
|
||||
import com.jero.modules.cert.collect.enums.CollectManifestStatisticsStateEnum;
|
||||
import com.jero.modules.cert.collect.service.IParamsCollectManifestEOService;
|
||||
import com.jero.modules.cert.collect.service.IParamsManifestEOService;
|
||||
import com.jero.modules.cert.report.entity.ParamsReportConfigDataEO;
|
||||
import com.jero.modules.cert.template.enums.ControlTypeEnum;
|
||||
import com.jero.modules.project.entity.*;
|
||||
import com.jero.modules.project.enums.*;
|
||||
import com.jero.modules.ota.entity.OtaManageApplyEO;
|
||||
import com.jero.modules.ota.service.impl.OtaManageApplyEOServiceImpl;
|
||||
import com.jero.modules.project.entity.ConditionAssessmentEO;
|
||||
import com.jero.modules.project.entity.ProjectCertificationInventoryEO;
|
||||
import com.jero.modules.project.entity.ProjectLawsInventoryEO;
|
||||
import com.jero.modules.project.entity.ProjectLibraryBase;
|
||||
import com.jero.modules.project.entity.ProjectTaskInventoryEO;
|
||||
import com.jero.modules.project.entity.ProjectTaskPlanning;
|
||||
import com.jero.modules.project.enums.CertificationProgressEnum;
|
||||
import com.jero.modules.project.enums.CurrentProjectStatusEnum;
|
||||
import com.jero.modules.project.enums.InventoryAffirmStatusEnum;
|
||||
import com.jero.modules.project.enums.ProjectRoleEnum;
|
||||
import com.jero.modules.project.enums.ProjectTaskPlanningNameEnum;
|
||||
import com.jero.modules.project.enums.ReviewResultEnum;
|
||||
import com.jero.modules.project.enums.TaskAffirmStatusEnum;
|
||||
import com.jero.modules.project.mapper.ProjectUserPermissionMapper;
|
||||
import com.jero.modules.project.service.IConditionAssessmentEOService;
|
||||
import com.jero.modules.project.service.IProjectCertificationInventoryEOService;
|
||||
@@ -26,7 +35,6 @@ import com.jero.modules.project.service.IProjectLibraryStatisticsService;
|
||||
import com.jero.modules.project.service.IProjectStatusBoardService;
|
||||
import com.jero.modules.project.vo.TimeNodeVO;
|
||||
import com.jero.modules.system.entity.SysDictItem;
|
||||
import com.jero.modules.system.enums.DicCodeEnum;
|
||||
import com.jero.modules.system.mapper.SysRoleMapper;
|
||||
import com.jero.modules.system.service.IProjectUserBrandService;
|
||||
import com.jero.modules.system.service.ISysUserService;
|
||||
@@ -38,7 +46,12 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.CellType;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -53,8 +66,17 @@ import java.io.OutputStream;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -95,6 +117,8 @@ public class ProjectStatusBoardServiceImpl implements IProjectStatusBoardService
|
||||
private IParamsCollectManifestEOService paramsCollectManifestEOService;
|
||||
@Autowired
|
||||
private IProjectLibraryStatisticsService projectLibraryStatisticsService;
|
||||
@Autowired
|
||||
private OtaManageApplyEOServiceImpl otaManageApplyEOService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -641,6 +665,24 @@ public class ProjectStatusBoardServiceImpl implements IProjectStatusBoardService
|
||||
List<ProjectCertificationInventoryEO> pciEoList = this.projectCertificationInventoryEOService.list();
|
||||
List<ProjectTaskPlanning> ptpEoList = this.projectTaskPlanningService.list();
|
||||
List<ParamsManifestEO> pmEoList = this.paramsManifestEOService.list();
|
||||
|
||||
LambdaQueryWrapper<OtaManageApplyEO> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.isNotNull(OtaManageApplyEO::getProjectVersion);
|
||||
List<String> projectIdList = otaManageApplyEOService.list(wrapper).stream().map(OtaManageApplyEO::getProjectVersion).distinct().collect(Collectors.toList());
|
||||
List<Map<String, Object>> mapList = new ArrayList<>();
|
||||
if(!projectIdList.isEmpty()){
|
||||
List<String> projectIdListTemp = plbEoList.stream()
|
||||
.filter(e -> projectIdList.contains(e.getId())).map(ProjectLibraryBase::getId).distinct().collect(Collectors.toList());
|
||||
if(!projectIdListTemp.isEmpty()){
|
||||
for (String projectId : projectIdListTemp) {
|
||||
List<Map<String, Object>> statisticalStatus = otaManageApplyEOService.getStatisticalStatus(projectId,
|
||||
"",
|
||||
projectLibraryBase.getCut(),plbEoList);
|
||||
mapList.addAll(statisticalStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("一阶段消耗时间:" + (System.currentTimeMillis() - startTime));
|
||||
List<ParamsCollectManifestEO> pcmEoList = this.paramsCollectManifestEOService.getList(null);
|
||||
pcmEoList = pcmEoList.stream().filter(pcmEo -> !StringUtils.equals(pcmEo.getControlType(), ControlTypeEnum.Title.getValue())).collect(Collectors.toList());;
|
||||
@@ -652,6 +694,7 @@ public class ProjectStatusBoardServiceImpl implements IProjectStatusBoardService
|
||||
|
||||
HSSFSheet corssProjectProgressSheet = createCorssProjectProgressSheet(workbook, projectLibraryBase);
|
||||
HSSFSheet overviewCrossProjectProgressSheet = this.createOverviewCrossProjectProgressSheet(workbook, projectLibraryBase);
|
||||
HSSFSheet otaSheet = createOtaSheet(workbook, projectLibraryBase);
|
||||
CellStyle cellStyleTitle = workbook.createCellStyle();
|
||||
cellStyleTitle.setAlignment(HorizontalAlignment.CENTER);
|
||||
cellStyleTitle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
@@ -675,14 +718,24 @@ public class ProjectStatusBoardServiceImpl implements IProjectStatusBoardService
|
||||
}
|
||||
});
|
||||
|
||||
// 创建线程三
|
||||
Thread thread3 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
exportOtaSetData(mapList, otaSheet, finalPlbEoList);
|
||||
}
|
||||
});
|
||||
|
||||
// 启动线程一和线程二
|
||||
thread1.start();
|
||||
thread2.start();
|
||||
thread3.start();
|
||||
|
||||
// 等待线程一和线程二执行完毕
|
||||
try {
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
thread3.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -706,6 +759,45 @@ public class ProjectStatusBoardServiceImpl implements IProjectStatusBoardService
|
||||
log.info("总消耗时间:" + (System.currentTimeMillis() - startTime));
|
||||
}
|
||||
|
||||
private void exportOtaSetData(List<Map<String, Object>> finalStatisticalStatus, HSSFSheet otaSheet,List<ProjectLibraryBase> plbEoList) {
|
||||
if(ObjectUtils.isNotEmpty(finalStatisticalStatus)){
|
||||
int dataIndex = 2;
|
||||
for (Map<String, Object> map : finalStatisticalStatus) {
|
||||
String plannedBpLaunchBatch = (String) map.get("plannedBpLaunchBatch");
|
||||
Map<String, Object> matchStatusMap = (Map<String, Object>)map.get("matchStatusMap");
|
||||
Map<String, Object> attestationScheduleMap = (Map<String, Object>)map.get("attestationScheduleMap");
|
||||
|
||||
String showName = String.valueOf(map.get("showName"));
|
||||
String locked = String.valueOf(matchStatusMap.get("locked"));
|
||||
String rejected = String.valueOf(matchStatusMap.get("rejected"));
|
||||
String to_be_approved = String.valueOf(matchStatusMap.get("to_be_approved"));
|
||||
String to_be_matched = String.valueOf(matchStatusMap.get("to_be_matched"));
|
||||
String Component_report_has_been_stored = String.valueOf(attestationScheduleMap.get("Component_report_has_been_stored"));
|
||||
String Component_report_not_submitted = String.valueOf(attestationScheduleMap.get("Component_report_not_submitted"));
|
||||
String Component_report_submitted = String.valueOf(attestationScheduleMap.get("Component_report_submitted"));
|
||||
String In_progress = String.valueOf(attestationScheduleMap.get("In_progress"));
|
||||
String Not_start =String.valueOf(attestationScheduleMap.get("Not_start"));
|
||||
String Test_failed = String.valueOf(attestationScheduleMap.get("Test_failed"));
|
||||
String Test_passed = String.valueOf(attestationScheduleMap.get("Test_passed"));
|
||||
Row dataRow = otaSheet.createRow(dataIndex);
|
||||
dataRow.createCell(0).setCellValue(showName);
|
||||
dataRow.createCell(1).setCellValue(plannedBpLaunchBatch);
|
||||
dataRow.createCell(2).setCellValue(to_be_matched);
|
||||
dataRow.createCell(3).setCellValue(to_be_approved);
|
||||
dataRow.createCell(4).setCellValue(locked);
|
||||
dataRow.createCell(5).setCellValue(rejected);
|
||||
dataRow.createCell(6).setCellValue(Not_start);
|
||||
dataRow.createCell(7).setCellValue(In_progress);
|
||||
dataRow.createCell(8).setCellValue(Test_passed);
|
||||
dataRow.createCell(9).setCellValue(Test_failed);
|
||||
dataRow.createCell(10).setCellValue(Component_report_not_submitted);
|
||||
dataRow.createCell(11).setCellValue(Component_report_submitted);
|
||||
dataRow.createCell(12).setCellValue(Component_report_has_been_stored);
|
||||
dataIndex ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出跨项目进度
|
||||
* @param workbook
|
||||
@@ -1146,6 +1238,66 @@ public class ProjectStatusBoardServiceImpl implements IProjectStatusBoardService
|
||||
}
|
||||
return sheet;
|
||||
}
|
||||
public HSSFSheet createOtaSheet(HSSFWorkbook workbook, ProjectLibraryBase projectLibraryBase){
|
||||
String cut = projectLibraryBase.getCut();
|
||||
String sheetName = "OTA状态";
|
||||
String firstTitle = "项目,软件版本,匹配状态统计,OTA认证进度统计";
|
||||
String secondTitle = ",,待匹配,待审批,锁定,退回,未开始,进行中,实验通过,实验失败,部件报告未提交,部件报告已提交,部件报告已入库";
|
||||
if(com.jero.modules.system.util.StringUtils.equals(cut,CutEnum.EN.getValue())){
|
||||
sheetName = "OTA status";
|
||||
firstTitle = "Project,Software version,Matching state statistics,OTA authentication progress statistics";
|
||||
secondTitle = ",,To be matched," +
|
||||
"To be approved," +
|
||||
"lock," +
|
||||
"Reject,"+
|
||||
"Not started," +
|
||||
"Ongoing," +
|
||||
"Test Passed," +
|
||||
"Test Failed," +
|
||||
"Component report not submitted," +
|
||||
"Component report submitted," +
|
||||
"Component report has been stored";
|
||||
}
|
||||
HSSFSheet sheet = workbook.createSheet(sheetName);
|
||||
CellRangeAddress region1 = new CellRangeAddress(0, 1, 0, 0);
|
||||
sheet.addMergedRegion(region1);
|
||||
CellRangeAddress region2 = new CellRangeAddress(0, 1, 1, 1);
|
||||
sheet.addMergedRegion(region2);
|
||||
CellRangeAddress region3 = new CellRangeAddress(0, 0, 2, 5);
|
||||
sheet.addMergedRegion(region3);
|
||||
CellRangeAddress region4 = new CellRangeAddress(0, 0, 6, 12);
|
||||
sheet.addMergedRegion(region4);
|
||||
|
||||
String[] firstTitleArr = firstTitle.split(",");
|
||||
String[] secondTitleArr = secondTitle.split(",");
|
||||
Row firstRow = sheet.createRow(0);
|
||||
Row secondRow = sheet.createRow(1);
|
||||
|
||||
CellStyle cellStyleTitle = workbook.createCellStyle();
|
||||
cellStyleTitle.setAlignment(HorizontalAlignment.CENTER);
|
||||
cellStyleTitle.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
for (int i = 0; i <= 8; i++){
|
||||
sheet.setColumnWidth(i, 4000);
|
||||
Cell firstRowCell = firstRow.createCell(i);
|
||||
firstRowCell.setCellStyle(cellStyleTitle);
|
||||
if(i == 0){
|
||||
firstRowCell.setCellValue(firstTitleArr[0]);
|
||||
}else if(i == 1){
|
||||
firstRowCell.setCellValue(firstTitleArr[1]);
|
||||
}else if(i == 2){
|
||||
firstRowCell.setCellValue(firstTitleArr[2]);
|
||||
}else if(i == 6){
|
||||
firstRowCell.setCellValue(firstTitleArr[3]);
|
||||
}
|
||||
|
||||
if(i >= 2){
|
||||
Cell secondRowCell = secondRow.createCell(i);
|
||||
secondRowCell.setCellStyle(cellStyleTitle);
|
||||
secondRowCell.setCellValue(secondTitleArr[i]);
|
||||
}
|
||||
}
|
||||
return sheet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出跨项目进度概览-设置数据
|
||||
|
||||
Reference in New Issue
Block a user