新增当前用户待办接口和权限测试

This commit is contained in:
jsowell
2026-07-16 16:20:34 +08:00
parent 181d4a5b40
commit f84ec43ceb
5 changed files with 386 additions and 4 deletions

View File

@@ -0,0 +1,118 @@
package com.jsowell.web.controller.system;
import com.jsowell.common.annotation.Log;
import com.jsowell.common.core.controller.BaseController;
import com.jsowell.common.core.domain.AjaxResult;
import com.jsowell.common.core.page.TableDataInfo;
import com.jsowell.common.enums.BusinessType;
import com.jsowell.system.domain.SysTodoTask;
import com.jsowell.system.domain.dto.TodoTaskCancelRequest;
import com.jsowell.system.domain.dto.TodoTaskQuery;
import com.jsowell.system.service.TodoTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
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 java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 当前登录用户待办任务接口。
*
* @author jsowell
*/
@RestController
@RequestMapping("/system/todo")
public class SysTodoTaskController extends BaseController {
@Autowired
private TodoTaskService todoTaskService;
/**
* 获取当前用户待办数量。
*/
@PreAuthorize("@ss.hasPermi('system:todo:list')")
@GetMapping("/unreadCount")
public AjaxResult unreadCount() {
Long userId = getUserId();
Map<String, Integer> counts = new HashMap<>(2);
counts.put("activeCount", todoTaskService.countActive(userId));
counts.put("unreadCount", todoTaskService.countUnread(userId));
return AjaxResult.success(counts);
}
/**
* 获取首页最近待办。
*/
@PreAuthorize("@ss.hasPermi('system:todo:list')")
@GetMapping("/homeList")
public AjaxResult homeList(@RequestParam(required = false) Integer limit) {
return AjaxResult.success(todoTaskService.homeList(getUserId(), limit));
}
/**
* 分页查询当前用户待办。
*/
@PreAuthorize("@ss.hasPermi('system:todo:list')")
@GetMapping("/list")
public TableDataInfo list(TodoTaskQuery query) {
startPage();
List<SysTodoTask> list = todoTaskService.listForAssignee(query, getUserId());
return getDataTable(list);
}
/**
* 查询当前用户待办详情。
*/
@PreAuthorize("@ss.hasPermi('system:todo:query')")
@GetMapping("/{todoId}")
public AjaxResult getInfo(@PathVariable Long todoId) {
return AjaxResult.success(todoTaskService.getForAssignee(todoId, getUserId()));
}
/**
* 标记当前用户的一条待办为已读。
*/
@PreAuthorize("@ss.hasPermi('system:todo:read')")
@PutMapping("/{todoId}/read")
public AjaxResult markRead(@PathVariable Long todoId) {
return toAjax(todoTaskService.markRead(todoId, getUserId(), getUsername()));
}
/**
* 标记当前用户全部待办为已读。
*/
@PreAuthorize("@ss.hasPermi('system:todo:read')")
@PutMapping("/readAll")
public AjaxResult markAllRead() {
return AjaxResult.success(todoTaskService.markAllRead(getUserId(), getUsername()));
}
/**
* 完成当前用户待办。
*/
@PreAuthorize("@ss.hasPermi('system:todo:complete')")
@Log(title = "待办任务", businessType = BusinessType.UPDATE)
@PutMapping("/{todoId}/complete")
public AjaxResult complete(@PathVariable Long todoId) {
return toAjax(todoTaskService.complete(todoId, getUserId(), getUsername()));
}
/**
* 取消当前用户待办。
*/
@PreAuthorize("@ss.hasPermi('system:todo:cancel')")
@Log(title = "待办任务", businessType = BusinessType.UPDATE)
@PutMapping("/{todoId}/cancel")
public AjaxResult cancel(@PathVariable Long todoId,
@Validated @RequestBody TodoTaskCancelRequest request) {
return toAjax(todoTaskService.cancelForAssignee(todoId, getUserId(), getUsername(), request.getReason()));
}
}

View File

@@ -0,0 +1,149 @@
package com.jsowell.system.service;
import com.jsowell.common.exception.ServiceException;
import com.jsowell.system.constant.TodoTaskConstants;
import com.jsowell.system.domain.SysTodoTask;
import com.jsowell.system.domain.dto.TodoTaskCreateCommand;
import com.jsowell.system.domain.dto.TodoTaskQuery;
import com.jsowell.system.mapper.SysTodoTaskMapper;
import com.jsowell.system.service.impl.TodoTaskServiceImpl;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.dao.DuplicateKeyException;
import java.lang.reflect.Field;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class TodoTaskServiceImplTest {
@Test
void createTask_shouldSetDefaultsAndInsert() {
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
TodoTaskServiceImpl service = newService(mapper);
TodoTaskCreateCommand command = createCommand();
when(mapper.selectActiveByIdempotentKey("INVOICE:100:8")).thenReturn(null);
doAnswer(invocation -> {
SysTodoTask task = invocation.getArgument(0);
task.setTodoId(11L);
return 1;
}).when(mapper).insertTodoTask(any(SysTodoTask.class));
SysTodoTask result = service.createTask(command);
ArgumentCaptor<SysTodoTask> captor = ArgumentCaptor.forClass(SysTodoTask.class);
verify(mapper).insertTodoTask(captor.capture());
SysTodoTask inserted = captor.getValue();
assertEquals(11L, result.getTodoId());
assertEquals(TodoTaskConstants.PRIORITY_NORMAL, inserted.getPriority());
assertEquals(TodoTaskConstants.STATUS_PENDING, inserted.getTaskStatus());
assertEquals(TodoTaskConstants.READ_UNREAD, inserted.getReadStatus());
assertEquals(inserted.getIdempotentKey(), inserted.getActiveIdempotentKey());
}
@Test
void createTask_shouldReturnExistingTask() {
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
TodoTaskServiceImpl service = newService(mapper);
SysTodoTask existing = new SysTodoTask();
existing.setTodoId(12L);
when(mapper.selectActiveByIdempotentKey("INVOICE:100:8")).thenReturn(existing);
SysTodoTask result = service.createTask(createCommand());
assertSame(existing, result);
verify(mapper, never()).insertTodoTask(any(SysTodoTask.class));
}
@Test
void createTask_shouldRecoverFromConcurrentDuplicate() {
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
TodoTaskServiceImpl service = newService(mapper);
SysTodoTask existing = new SysTodoTask();
existing.setTodoId(13L);
when(mapper.selectActiveByIdempotentKey("INVOICE:100:8")).thenReturn(null, existing);
doThrow(new DuplicateKeyException("duplicate"))
.when(mapper).insertTodoTask(any(SysTodoTask.class));
SysTodoTask result = service.createTask(createCommand());
assertSame(existing, result);
}
@Test
void listForAssignee_shouldOverrideRequestedUser() {
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
TodoTaskServiceImpl service = newService(mapper);
TodoTaskQuery query = new TodoTaskQuery();
query.setAssigneeUserId(999L);
when(mapper.selectTodoList(query)).thenReturn(Collections.emptyList());
service.listForAssignee(query, 8L);
assertEquals(8L, query.getAssigneeUserId());
verify(mapper).selectTodoList(query);
}
@Test
void complete_shouldBeIdempotentWhenAlreadyCompleted() {
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
TodoTaskServiceImpl service = newService(mapper);
SysTodoTask completed = new SysTodoTask();
completed.setTaskStatus(TodoTaskConstants.STATUS_COMPLETED);
when(mapper.completeTodoForAssignee(20L, 8L, 8L, "tester")).thenReturn(0);
when(mapper.selectTodoByIdForAssignee(20L, 8L)).thenReturn(completed);
assertTrue(service.complete(20L, 8L, "tester"));
}
@Test
void complete_shouldRejectCancelledTask() {
SysTodoTaskMapper mapper = mock(SysTodoTaskMapper.class);
TodoTaskServiceImpl service = newService(mapper);
SysTodoTask cancelled = new SysTodoTask();
cancelled.setTaskStatus(TodoTaskConstants.STATUS_CANCELLED);
when(mapper.completeTodoForAssignee(20L, 8L, 8L, "tester")).thenReturn(0);
when(mapper.selectTodoByIdForAssignee(20L, 8L)).thenReturn(cancelled);
assertThrows(ServiceException.class, () -> service.complete(20L, 8L, "tester"));
}
private static TodoTaskCreateCommand createCommand() {
return TodoTaskCreateCommand.builder()
.taskType("INVOICE_REVIEW")
.title("司机开票申请")
.businessType("INVOICE_APPLY")
.businessId("100")
.routeName("InvoiceApplyDetail")
.assigneeUserId(8L)
.idempotentKey("INVOICE:100:8")
.createBy("tester")
.build();
}
private static TodoTaskServiceImpl newService(SysTodoTaskMapper mapper) {
TodoTaskServiceImpl service = new TodoTaskServiceImpl();
setField(service, "todoTaskMapper", mapper);
return service;
}
private static void setField(Object target, String fieldName, Object value) {
try {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, value);
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}

View File

@@ -0,0 +1,93 @@
package com.jsowell.web.controller.system;
import com.jsowell.common.core.domain.AjaxResult;
import com.jsowell.system.domain.SysTodoTask;
import com.jsowell.system.service.TodoTaskService;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class SysTodoTaskControllerTest {
@Test
@SuppressWarnings("unchecked")
void unreadCount_shouldUseCurrentLoginUser() {
TodoTaskService service = mock(TodoTaskService.class);
TestController controller = newController(service, 8L, "tester");
when(service.countActive(8L)).thenReturn(5);
when(service.countUnread(8L)).thenReturn(3);
AjaxResult result = controller.unreadCount();
Map<String, Integer> data = (Map<String, Integer>) result.get(AjaxResult.DATA_TAG);
assertEquals(5, data.get("activeCount"));
assertEquals(3, data.get("unreadCount"));
}
@Test
void getInfo_shouldNotAcceptAnotherAssignee() {
TodoTaskService service = mock(TodoTaskService.class);
TestController controller = newController(service, 8L, "tester");
SysTodoTask task = new SysTodoTask();
task.setTodoId(20L);
when(service.getForAssignee(20L, 8L)).thenReturn(task);
AjaxResult result = controller.getInfo(20L);
assertSame(task, result.get(AjaxResult.DATA_TAG));
verify(service).getForAssignee(20L, 8L);
}
@Test
void complete_shouldPassCurrentUserAndOperator() {
TodoTaskService service = mock(TodoTaskService.class);
TestController controller = newController(service, 8L, "tester");
when(service.complete(20L, 8L, "tester")).thenReturn(true);
controller.complete(20L);
verify(service).complete(20L, 8L, "tester");
}
private static TestController newController(TodoTaskService service, Long userId, String username) {
TestController controller = new TestController(userId, username);
setField(controller, "todoTaskService", service);
return controller;
}
private static void setField(Object target, String fieldName, Object value) {
try {
Field field = SysTodoTaskController.class.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, value);
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
private static class TestController extends SysTodoTaskController {
private final Long userId;
private final String username;
private TestController(Long userId, String username) {
this.userId = userId;
this.username = username;
}
@Override
public Long getUserId() {
return userId;
}
@Override
public String getUsername() {
return username;
}
}
}