feat: validate feature conversion priorities
parent
f5c61f8035
commit
bc263e93ab
@ -0,0 +1,37 @@
|
|||||||
|
package com.sztzjy.linkCommerce.entity.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FeatureConversionStepThreeValidationRequest {
|
||||||
|
private List<FeatureConversionStepTwoValidationRequest.RiceScoreRow> scoreRows;
|
||||||
|
private List<PriorityRow> rows;
|
||||||
|
|
||||||
|
public List<FeatureConversionStepTwoValidationRequest.RiceScoreRow> getScoreRows() {
|
||||||
|
return scoreRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScoreRows(List<FeatureConversionStepTwoValidationRequest.RiceScoreRow> scoreRows) {
|
||||||
|
this.scoreRows = scoreRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PriorityRow> getRows() {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRows(List<PriorityRow> rows) {
|
||||||
|
this.rows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PriorityRow {
|
||||||
|
private String name;
|
||||||
|
private String priority;
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
public String getPriority() { return priority; }
|
||||||
|
public void setPriority(String priority) { this.priority = priority; }
|
||||||
|
public String getReason() { return reason; }
|
||||||
|
public void setReason(String reason) { this.reason = reason; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.sztzjy.linkCommerce.entity.dto;
|
||||||
|
|
||||||
|
public class FeatureConversionStepThreeValidationResult {
|
||||||
|
private boolean valid;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public boolean isValid() { return valid; }
|
||||||
|
public void setValid(boolean valid) { this.valid = valid; }
|
||||||
|
public String getMessage() { return message; }
|
||||||
|
public void setMessage(String message) { this.message = message; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.sztzjy.linkCommerce.service;
|
||||||
|
|
||||||
|
import com.sztzjy.linkCommerce.config.security.JwtUser;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationRequest;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult;
|
||||||
|
|
||||||
|
public interface FeatureConversionStepThreeService {
|
||||||
|
FeatureConversionStepThreeValidationResult validate(FeatureConversionStepThreeValidationRequest request, JwtUser user);
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.sztzjy.linkCommerce.service.impl;
|
||||||
|
|
||||||
|
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
|
||||||
|
import com.sztzjy.linkCommerce.config.security.JwtUser;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationRequest;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepTwoValidationRequest;
|
||||||
|
import com.sztzjy.linkCommerce.service.FeatureConversionStepThreeService;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FeatureConversionStepThreeServiceImpl implements FeatureConversionStepThreeService {
|
||||||
|
private static final int MIN_ROWS = 8;
|
||||||
|
private static final int MAX_ROWS = 12;
|
||||||
|
private static final List<String> PRIORITIES = Arrays.asList("P0", "P1", "P2", "P3");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FeatureConversionStepThreeValidationResult validate(FeatureConversionStepThreeValidationRequest request, JwtUser user) {
|
||||||
|
requireStudent(user);
|
||||||
|
List<FeatureConversionStepTwoValidationRequest.RiceScoreRow> scoreRows = request == null ? null : request.getScoreRows();
|
||||||
|
List<FeatureConversionStepThreeValidationRequest.PriorityRow> rows = request == null ? null : request.getRows();
|
||||||
|
if (scoreRows == null || rows == null || scoreRows.size() < MIN_ROWS || scoreRows.size() > MAX_ROWS || scoreRows.size() != rows.size()) {
|
||||||
|
throw badRequest("功能优先级表必须与第二步 RICE 评分表保持一致,且为 8 至 12 行");
|
||||||
|
}
|
||||||
|
for (int index = 0; index < rows.size(); index++) {
|
||||||
|
FeatureConversionStepTwoValidationRequest.RiceScoreRow scoreRow = scoreRows.get(index);
|
||||||
|
FeatureConversionStepThreeValidationRequest.PriorityRow row = rows.get(index);
|
||||||
|
if (scoreRow == null || row == null || StringUtils.isBlank(scoreRow.getName()) || !scoreRow.getName().equals(row.getName())) {
|
||||||
|
throw badRequest("功能名称和行数必须与第二步 RICE 评分表保持一致");
|
||||||
|
}
|
||||||
|
if (!PRIORITIES.contains(row.getPriority()) || StringUtils.isBlank(row.getReason())) {
|
||||||
|
throw badRequest("请为每项功能选择 P0-P3 优先级并填写划分理由");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FeatureConversionStepThreeValidationResult result = new FeatureConversionStepThreeValidationResult();
|
||||||
|
result.setValid(true);
|
||||||
|
result.setMessage("功能优先级清单填写完整。");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireStudent(JwtUser user) {
|
||||||
|
if (user == null || StringUtils.isBlank(user.getUserId())) {
|
||||||
|
throw new ServiceException(HttpStatus.UNAUTHORIZED, "请先登录后再提交");
|
||||||
|
}
|
||||||
|
if (user.getRoleId() != 4) {
|
||||||
|
throw new ServiceException(HttpStatus.FORBIDDEN, "仅学生可以提交实训答案");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceException badRequest(String message) {
|
||||||
|
return new ServiceException(HttpStatus.BAD_REQUEST, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.sztzjy.linkCommerce.service.impl;
|
||||||
|
|
||||||
|
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
|
||||||
|
import com.sztzjy.linkCommerce.config.security.JwtUser;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationRequest;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult;
|
||||||
|
import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepTwoValidationRequest;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class FeatureConversionStepThreeServiceImplTest {
|
||||||
|
private final FeatureConversionStepThreeServiceImpl service = new FeatureConversionStepThreeServiceImpl();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void acceptsPriorityRowsSynchronizedWithRiceRows() {
|
||||||
|
FeatureConversionStepThreeValidationResult result = service.validate(request(), student());
|
||||||
|
|
||||||
|
assertTrue(result.isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rejectsPriorityNameNotSynchronizedWithRiceRows() {
|
||||||
|
FeatureConversionStepThreeValidationRequest request = request();
|
||||||
|
request.getRows().get(0).setName("被篡改的功能名称");
|
||||||
|
|
||||||
|
assertThrows(ServiceException.class, () -> service.validate(request, student()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rejectsBlankPriorityReason() {
|
||||||
|
FeatureConversionStepThreeValidationRequest request = request();
|
||||||
|
request.getRows().get(0).setReason(" ");
|
||||||
|
|
||||||
|
assertThrows(ServiceException.class, () -> service.validate(request, student()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FeatureConversionStepThreeValidationRequest request() {
|
||||||
|
FeatureConversionStepThreeValidationRequest request = new FeatureConversionStepThreeValidationRequest();
|
||||||
|
List<FeatureConversionStepTwoValidationRequest.RiceScoreRow> scoreRows = new ArrayList<>();
|
||||||
|
List<FeatureConversionStepThreeValidationRequest.PriorityRow> rows = new ArrayList<>();
|
||||||
|
for (int index = 0; index < 8; index++) {
|
||||||
|
String name = "功能定义" + (index + 1);
|
||||||
|
FeatureConversionStepTwoValidationRequest.RiceScoreRow scoreRow = new FeatureConversionStepTwoValidationRequest.RiceScoreRow();
|
||||||
|
scoreRow.setName(name);
|
||||||
|
scoreRows.add(scoreRow);
|
||||||
|
|
||||||
|
FeatureConversionStepThreeValidationRequest.PriorityRow row = new FeatureConversionStepThreeValidationRequest.PriorityRow();
|
||||||
|
row.setName(name);
|
||||||
|
row.setPriority(index == 0 ? "P0" : "P1");
|
||||||
|
row.setReason("结合 RICE 评分确定开发优先级");
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
request.setScoreRows(scoreRows);
|
||||||
|
request.setRows(rows);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JwtUser student() {
|
||||||
|
JwtUser user = new JwtUser();
|
||||||
|
user.setUserId("student-id");
|
||||||
|
user.setRoleId(4);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue