Commit 87c7b3fac2c291b45c3537d972d0ac3e690d4342

Authored by YunaiV
1 parent 20583417

【新增】system user 和 role 接入新操作日志

Showing 14 changed files with 232 additions and 108 deletions
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtils.java
@@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; @@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
4 import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder; 4 import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder;
5 import lombok.SneakyThrows; 5 import lombok.SneakyThrows;
6 6
  7 +import java.util.concurrent.Callable;
  8 +
7 /** 9 /**
8 * 数据权限 Util 10 * 数据权限 Util
9 * 11 *
@@ -40,4 +42,22 @@ public class DataPermissionUtils { @@ -40,4 +42,22 @@ public class DataPermissionUtils {
40 } 42 }
41 } 43 }
42 44
  45 + /**
  46 + * 忽略数据权限,执行对应的逻辑
  47 + *
  48 + * @param callable 逻辑
  49 + * @return 执行结果
  50 + */
  51 + @SneakyThrows
  52 + public static <T> T executeIgnore(Callable<T> callable) {
  53 + DataPermission dataPermission = getDisableDataPermissionDisable();
  54 + DataPermissionContextHolder.add(dataPermission);
  55 + try {
  56 + // 执行 callable
  57 + return callable.call();
  58 + } finally {
  59 + DataPermissionContextHolder.remove();
  60 + }
  61 + }
  62 +
43 } 63 }
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/LogRecordConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.enums;
  2 +
  3 +/**
  4 + * System 操作日志枚举
  5 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串
  6 + *
  7 + * @author 芋道源码
  8 + */
  9 +public interface LogRecordConstants {
  10 +
  11 + // ======================= SYSTEM_USER 用户 =======================
  12 +
  13 + String SYSTEM_USER_TYPE = "SYSTEM 用户";
  14 + String SYSTEM_USER_CREATE_SUB_TYPE = "创建用户";
  15 + String SYSTEM_USER_CREATE_SUCCESS = "创建了用户【{{#user.nickname}}】";
  16 + String SYSTEM_USER_UPDATE_SUB_TYPE = "更新用户";
  17 + String SYSTEM_USER_UPDATE_SUCCESS = "更新了用户【{{#user.nickname}}】: {_DIFF{#updateReqVO}}";
  18 + String SYSTEM_USER_DELETE_SUB_TYPE = "删除用户";
  19 + String SYSTEM_USER_DELETE_SUCCESS = "删除了用户【{{#user.nickname}}】";
  20 + String SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE = "重置用户密码";
  21 + String SYSTEM_USER_UPDATE_PASSWORD_SUCCESS = "将用户【{{#user.nickname}}】的密码从【{{#user.password}}】重置为【{{#newPassword}}】";
  22 +
  23 + // ======================= SYSTEM_ROLE 角色 =======================
  24 +
  25 + String SYSTEM_ROLE_TYPE = "SYSTEM 角色";
  26 + String SYSTEM_ROLE_CREATE_SUB_TYPE = "创建角色";
  27 + String SYSTEM_ROLE_CREATE_SUCCESS = "创建了角色【{{#role.name}}】";
  28 + String SYSTEM_ROLE_UPDATE_SUB_TYPE = "更新角色";
  29 + String SYSTEM_ROLE_UPDATE_SUCCESS = "更新了角色【{{#role.name}}】: {_DIFF{#updateReqVO}}";
  30 + String SYSTEM_ROLE_DELETE_SUB_TYPE = "删除角色";
  31 + String SYSTEM_ROLE_DELETE_SUCCESS = "删除了角色【{{#role.name}}】";
  32 +
  33 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java
@@ -52,14 +52,6 @@ public class RoleController { @@ -52,14 +52,6 @@ public class RoleController {
52 return success(true); 52 return success(true);
53 } 53 }
54 54
55 - @PutMapping("/update-status")  
56 - @Operation(summary = "修改角色状态")  
57 - @PreAuthorize("@ss.hasPermission('system:role:update')")  
58 - public CommonResult<Boolean> updateRoleStatus(@Valid @RequestBody RoleUpdateStatusReqVO reqVO) {  
59 - roleService.updateRoleStatus(reqVO.getId(), reqVO.getStatus());  
60 - return success(true);  
61 - }  
62 -  
63 @DeleteMapping("/delete") 55 @DeleteMapping("/delete")
64 @Operation(summary = "删除角色") 56 @Operation(summary = "删除角色")
65 @Parameter(name = "id", description = "角色编号", required = true, example = "1024") 57 @Parameter(name = "id", description = "角色编号", required = true, example = "1024")
@@ -87,10 +79,10 @@ public class RoleController { @@ -87,10 +79,10 @@ public class RoleController {
87 79
88 @GetMapping({"/list-all-simple", "/simple-list"}) 80 @GetMapping({"/list-all-simple", "/simple-list"})
89 @Operation(summary = "获取角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项") 81 @Operation(summary = "获取角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项")
90 - public CommonResult<List<RoleSimpleRespVO>> getSimpleRoleList() { 82 + public CommonResult<List<RoleRespVO>> getSimpleRoleList() {
91 List<RoleDO> list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus())); 83 List<RoleDO> list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus()));
92 list.sort(Comparator.comparing(RoleDO::getSort)); 84 list.sort(Comparator.comparing(RoleDO::getSort));
93 - return success(BeanUtils.toBean(list, RoleSimpleRespVO.class)); 85 + return success(BeanUtils.toBean(list, RoleRespVO.class));
94 } 86 }
95 87
96 @GetMapping("/export-excel") 88 @GetMapping("/export-excel")
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSaveReqVO.java
1 package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; 1 package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role;
2 2
  3 +import com.mzt.logapi.starter.annotation.DiffLogField;
3 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 5 import lombok.Data;
5 6
@@ -7,7 +8,7 @@ import jakarta.validation.constraints.NotBlank; @@ -7,7 +8,7 @@ import jakarta.validation.constraints.NotBlank;
7 import jakarta.validation.constraints.NotNull; 8 import jakarta.validation.constraints.NotNull;
8 import jakarta.validation.constraints.Size; 9 import jakarta.validation.constraints.Size;
9 10
10 -@Schema(description = "管理后台 - 角色创建 Request VO") 11 +@Schema(description = "管理后台 - 角色创建/更新 Request VO")
11 @Data 12 @Data
12 public class RoleSaveReqVO { 13 public class RoleSaveReqVO {
13 14
@@ -16,19 +17,23 @@ public class RoleSaveReqVO { @@ -16,19 +17,23 @@ public class RoleSaveReqVO {
16 17
17 @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员") 18 @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员")
18 @NotBlank(message = "角色名称不能为空") 19 @NotBlank(message = "角色名称不能为空")
19 - @Size(max = 30, message = "角色名称长度不能超过30个字符") 20 + @Size(max = 30, message = "角色名称长度不能超过 30 个字符")
  21 + @DiffLogField(name = "角色名称")
20 private String name; 22 private String name;
21 23
22 @NotBlank(message = "角色标志不能为空") 24 @NotBlank(message = "角色标志不能为空")
23 - @Size(max = 100, message = "角色标志长度不能超过100个字符") 25 + @Size(max = 100, message = "角色标志长度不能超过 100 个字符")
24 @Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN") 26 @Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN")
  27 + @DiffLogField(name = "角色标志")
25 private String code; 28 private String code;
26 29
27 @Schema(description = "显示顺序不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 30 @Schema(description = "显示顺序不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
28 @NotNull(message = "显示顺序不能为空") 31 @NotNull(message = "显示顺序不能为空")
  32 + @DiffLogField(name = "显示顺序")
29 private Integer sort; 33 private Integer sort;
30 34
31 @Schema(description = "备注", example = "我是一个角色") 35 @Schema(description = "备注", example = "我是一个角色")
  36 + @DiffLogField(name = "备注")
32 private String remark; 37 private String remark;
33 38
34 } 39 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java deleted
1 -package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role;  
2 -  
3 -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;  
4 -import cn.iocoder.yudao.framework.common.validation.InEnum;  
5 -import io.swagger.v3.oas.annotations.media.Schema;  
6 -import lombok.Data;  
7 -  
8 -import jakarta.validation.constraints.NotNull;  
9 -  
10 -@Schema(description = "管理后台 - 角色更新状态 Request VO")  
11 -@Data  
12 -public class RoleUpdateStatusReqVO {  
13 -  
14 - @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
15 - @NotNull(message = "角色编号不能为空")  
16 - private Long id;  
17 -  
18 - @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
19 - @NotNull(message = "状态不能为空")  
20 - @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")  
21 - private Integer status;  
22 -  
23 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java
@@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; @@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
2 2
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.framework.common.validation.Mobile; 4 import cn.iocoder.yudao.framework.common.validation.Mobile;
  5 +import cn.iocoder.yudao.module.system.framework.operatelog.core.DeptParseFunction;
  6 +import cn.iocoder.yudao.module.system.framework.operatelog.core.PostParseFunction;
  7 +import cn.iocoder.yudao.module.system.framework.operatelog.core.SexParseFunction;
5 import com.fasterxml.jackson.annotation.JsonIgnore; 8 import com.fasterxml.jackson.annotation.JsonIgnore;
  9 +import com.mzt.logapi.starter.annotation.DiffLogField;
6 import io.swagger.v3.oas.annotations.media.Schema; 10 import io.swagger.v3.oas.annotations.media.Schema;
  11 +import jakarta.validation.constraints.*;
7 import lombok.Data; 12 import lombok.Data;
8 import org.hibernate.validator.constraints.Length; 13 import org.hibernate.validator.constraints.Length;
9 14
10 -import jakarta.validation.constraints.*;  
11 import java.util.Set; 15 import java.util.Set;
12 16
13 @Schema(description = "管理后台 - 用户创建/修改 Request VO") 17 @Schema(description = "管理后台 - 用户创建/修改 Request VO")
@@ -21,34 +25,43 @@ public class UserSaveReqVO { @@ -21,34 +25,43 @@ public class UserSaveReqVO {
21 @NotBlank(message = "用户账号不能为空") 25 @NotBlank(message = "用户账号不能为空")
22 @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成") 26 @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
23 @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符") 27 @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
  28 + @DiffLogField(name = "用户账号")
24 private String username; 29 private String username;
25 30
26 @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") 31 @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
27 @Size(max = 30, message = "用户昵称长度不能超过30个字符") 32 @Size(max = 30, message = "用户昵称长度不能超过30个字符")
  33 + @DiffLogField(name = "用户昵称")
28 private String nickname; 34 private String nickname;
29 35
30 @Schema(description = "备注", example = "我是一个用户") 36 @Schema(description = "备注", example = "我是一个用户")
  37 + @DiffLogField(name = "备注")
31 private String remark; 38 private String remark;
32 39
33 - @Schema(description = "部门ID", example = "我是一个用户") 40 + @Schema(description = "部门编号", example = "我是一个用户")
  41 + @DiffLogField(name = "部门", function = DeptParseFunction.NAME)
34 private Long deptId; 42 private Long deptId;
35 43
36 @Schema(description = "岗位编号数组", example = "1") 44 @Schema(description = "岗位编号数组", example = "1")
  45 + @DiffLogField(name = "岗位", function = PostParseFunction.NAME)
37 private Set<Long> postIds; 46 private Set<Long> postIds;
38 47
39 @Schema(description = "用户邮箱", example = "yudao@iocoder.cn") 48 @Schema(description = "用户邮箱", example = "yudao@iocoder.cn")
40 @Email(message = "邮箱格式不正确") 49 @Email(message = "邮箱格式不正确")
41 @Size(max = 50, message = "邮箱长度不能超过 50 个字符") 50 @Size(max = 50, message = "邮箱长度不能超过 50 个字符")
  51 + @DiffLogField(name = "用户邮箱")
42 private String email; 52 private String email;
43 53
44 @Schema(description = "手机号码", example = "15601691300") 54 @Schema(description = "手机号码", example = "15601691300")
45 @Mobile 55 @Mobile
  56 + @DiffLogField(name = "手机号码")
46 private String mobile; 57 private String mobile;
47 58
48 @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") 59 @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1")
  60 + @DiffLogField(name = "用户性别", function = SexParseFunction.NAME)
49 private Integer sex; 61 private Integer sex;
50 62
51 @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png") 63 @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
  64 + @DiffLogField(name = "用户头像")
52 private String avatar; 65 private String avatar;
53 66
54 // ========== 仅【创建】时,需要传递的字段 ========== 67 // ========== 仅【创建】时,需要传递的字段 ==========
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java
1 package cn.iocoder.yudao.module.system.framework.operatelog.core; 1 package cn.iocoder.yudao.module.system.framework.operatelog.core;
2 2
  3 +import cn.hutool.core.convert.Convert;
3 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;  
5 -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 5 +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
  6 +import cn.iocoder.yudao.module.system.service.user.AdminUserService;
6 import com.mzt.logapi.service.IParseFunction; 7 import com.mzt.logapi.service.IParseFunction;
7 import jakarta.annotation.Resource; 8 import jakarta.annotation.Resource;
8 import lombok.extern.slf4j.Slf4j; 9 import lombok.extern.slf4j.Slf4j;
@@ -20,7 +21,7 @@ public class AdminUserParseFunction implements IParseFunction { @@ -20,7 +21,7 @@ public class AdminUserParseFunction implements IParseFunction {
20 public static final String NAME = "getAdminUserById"; 21 public static final String NAME = "getAdminUserById";
21 22
22 @Resource 23 @Resource
23 - private AdminUserApi adminUserApi; 24 + private AdminUserService adminUserService;
24 25
25 @Override 26 @Override
26 public String functionName() { 27 public String functionName() {
@@ -34,7 +35,7 @@ public class AdminUserParseFunction implements IParseFunction { @@ -34,7 +35,7 @@ public class AdminUserParseFunction implements IParseFunction {
34 } 35 }
35 36
36 // 获取用户信息 37 // 获取用户信息
37 - AdminUserRespDTO user = adminUserApi.getUser(Long.parseLong(value.toString())); 38 + AdminUserDO user = adminUserService.getUser(Convert.toLong(value));
38 if (user == null) { 39 if (user == null) {
39 log.warn("[apply][获取用户{{}}为空", value); 40 log.warn("[apply][获取用户{{}}为空", value);
40 return ""; 41 return "";
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java
1 package cn.iocoder.yudao.module.system.framework.operatelog.core; 1 package cn.iocoder.yudao.module.system.framework.operatelog.core;
2 2
  3 +import cn.hutool.core.convert.Convert;
3 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; 5 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
5 import com.mzt.logapi.service.IParseFunction; 6 import com.mzt.logapi.service.IParseFunction;
@@ -32,7 +33,7 @@ public class AreaParseFunction implements IParseFunction { @@ -32,7 +33,7 @@ public class AreaParseFunction implements IParseFunction {
32 if (StrUtil.isEmptyIfStr(value)) { 33 if (StrUtil.isEmptyIfStr(value)) {
33 return ""; 34 return "";
34 } 35 }
35 - return AreaUtils.format(Integer.parseInt(value.toString())); 36 + return AreaUtils.format(Convert.toInt(value));
36 } 37 }
37 38
38 } 39 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java
1 package cn.iocoder.yudao.module.system.framework.operatelog.core; 1 package cn.iocoder.yudao.module.system.framework.operatelog.core;
2 2
  3 +import cn.hutool.core.convert.Convert;
3 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.module.system.api.dept.DeptApi;  
5 -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 5 +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
  6 +import cn.iocoder.yudao.module.system.service.dept.DeptService;
6 import com.mzt.logapi.service.IParseFunction; 7 import com.mzt.logapi.service.IParseFunction;
7 import jakarta.annotation.Resource; 8 import jakarta.annotation.Resource;
8 import lombok.extern.slf4j.Slf4j; 9 import lombok.extern.slf4j.Slf4j;
9 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
10 11
11 /** 12 /**
12 - * 管理员名字的 {@link IParseFunction} 实现类 13 + * 部门名字的 {@link IParseFunction} 实现类
13 * 14 *
14 * @author HUIHUI 15 * @author HUIHUI
15 */ 16 */
@@ -20,7 +21,7 @@ public class DeptParseFunction implements IParseFunction { @@ -20,7 +21,7 @@ public class DeptParseFunction implements IParseFunction {
20 public static final String NAME = "getDeptById"; 21 public static final String NAME = "getDeptById";
21 22
22 @Resource 23 @Resource
23 - private DeptApi deptApi; 24 + private DeptService deptService;
24 25
25 @Override 26 @Override
26 public String functionName() { 27 public String functionName() {
@@ -34,7 +35,7 @@ public class DeptParseFunction implements IParseFunction { @@ -34,7 +35,7 @@ public class DeptParseFunction implements IParseFunction {
34 } 35 }
35 36
36 // 获取部门信息 37 // 获取部门信息
37 - DeptRespDTO dept = deptApi.getDept(Long.parseLong(value.toString())); 38 + DeptDO dept = deptService.getDept(Convert.toLong(value));
38 if (dept == null) { 39 if (dept == null) {
39 log.warn("[apply][获取部门{{}}为空", value); 40 log.warn("[apply][获取部门{{}}为空", value);
40 return ""; 41 return "";
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/PostParseFunction.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.framework.operatelog.core;
  2 +
  3 +import cn.hutool.core.convert.Convert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
  6 +import cn.iocoder.yudao.module.system.service.dept.PostService;
  7 +import com.mzt.logapi.service.IParseFunction;
  8 +import jakarta.annotation.Resource;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +/**
  13 + * 岗位名字的 {@link IParseFunction} 实现类
  14 + *
  15 + * @author HUIHUI
  16 + */
  17 +@Slf4j
  18 +@Component
  19 +public class PostParseFunction implements IParseFunction {
  20 +
  21 + public static final String NAME = "getPostById";
  22 +
  23 + @Resource
  24 + private PostService postService;
  25 +
  26 + @Override
  27 + public String functionName() {
  28 + return NAME;
  29 + }
  30 +
  31 + @Override
  32 + public String apply(Object value) {
  33 + if (StrUtil.isEmptyIfStr(value)) {
  34 + return "";
  35 + }
  36 +
  37 + // 获取岗位信息
  38 + PostDO post = postService.getPost(Convert.toLong(value));
  39 + if (post == null) {
  40 + log.warn("[apply][获取岗位{{}}为空", value);
  41 + return "";
  42 + }
  43 + return post.getName();
  44 + }
  45 +
  46 +}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java
  1 +/**
  2 + * 占位文件,避免文件夹缩进
  3 + */
1 package cn.iocoder.yudao.module.system.framework.operatelog; 4 package cn.iocoder.yudao.module.system.framework.operatelog;
2 \ No newline at end of file 5 \ No newline at end of file
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
@@ -41,14 +41,6 @@ public interface RoleService { @@ -41,14 +41,6 @@ public interface RoleService {
41 void deleteRole(Long id); 41 void deleteRole(Long id);
42 42
43 /** 43 /**
44 - * 更新角色状态  
45 - *  
46 - * @param id 角色编号  
47 - * @param status 状态  
48 - */  
49 - void updateRoleStatus(Long id, Integer status);  
50 -  
51 - /**  
52 * 设置角色的数据权限 44 * 设置角色的数据权限
53 * 45 *
54 * @param id 角色编号 46 * @param id 角色编号
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
@@ -17,6 +17,8 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; @@ -17,6 +17,8 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
17 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; 17 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
18 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; 18 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
19 import com.google.common.annotations.VisibleForTesting; 19 import com.google.common.annotations.VisibleForTesting;
  20 +import com.mzt.logapi.context.LogRecordContext;
  21 +import com.mzt.logapi.starter.annotation.LogRecord;
20 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.cache.annotation.CacheEvict; 23 import org.springframework.cache.annotation.CacheEvict;
22 import org.springframework.cache.annotation.Cacheable; 24 import org.springframework.cache.annotation.Cacheable;
@@ -30,6 +32,7 @@ import java.util.*; @@ -30,6 +32,7 @@ import java.util.*;
30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 34 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  35 +import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
33 36
34 /** 37 /**
35 * 角色 Service 实现类 38 * 角色 Service 实现类
@@ -48,41 +51,40 @@ public class RoleServiceImpl implements RoleService { @@ -48,41 +51,40 @@ public class RoleServiceImpl implements RoleService {
48 51
49 @Override 52 @Override
50 @Transactional(rollbackFor = Exception.class) 53 @Transactional(rollbackFor = Exception.class)
  54 + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}",
  55 + success = SYSTEM_ROLE_CREATE_SUCCESS)
51 public Long createRole(RoleSaveReqVO createReqVO, Integer type) { 56 public Long createRole(RoleSaveReqVO createReqVO, Integer type) {
52 - // 校验角色 57 + // 1. 校验角色
53 validateRoleDuplicate(createReqVO.getName(), createReqVO.getCode(), null); 58 validateRoleDuplicate(createReqVO.getName(), createReqVO.getCode(), null);
54 - // 插入到数据库  
55 - RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class);  
56 - role.setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()));  
57 - role.setStatus(CommonStatusEnum.ENABLE.getStatus());  
58 - role.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限 59 +
  60 + // 2. 插入到数据库
  61 + RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class)
  62 + .setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()))
  63 + .setStatus(CommonStatusEnum.ENABLE.getStatus())
  64 + .setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限
59 roleMapper.insert(role); 65 roleMapper.insert(role);
60 - // 返回 66 +
  67 + // 3. 记录操作日志上下文
  68 + LogRecordContext.putVariable("role", role);
61 return role.getId(); 69 return role.getId();
62 } 70 }
63 71
64 @Override 72 @Override
65 @CacheEvict(value = RedisKeyConstants.ROLE, key = "#updateReqVO.id") 73 @CacheEvict(value = RedisKeyConstants.ROLE, key = "#updateReqVO.id")
  74 + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
  75 + success = SYSTEM_ROLE_UPDATE_SUCCESS)
66 public void updateRole(RoleSaveReqVO updateReqVO) { 76 public void updateRole(RoleSaveReqVO updateReqVO) {
67 - // 校验是否可以更新  
68 - validateRoleForUpdate(updateReqVO.getId());  
69 - // 校验角色的唯一字段是否重复 77 + // 1.1 校验是否可以更新
  78 + RoleDO role = validateRoleForUpdate(updateReqVO.getId());
  79 + // 1.2 校验角色的唯一字段是否重复
70 validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId()); 80 validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId());
71 81
72 - // 更新到数据库 82 + // 2. 更新到数据库
73 RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class); 83 RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class);
74 roleMapper.updateById(updateObj); 84 roleMapper.updateById(updateObj);
75 - }  
76 -  
77 - @Override  
78 - @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")  
79 - public void updateRoleStatus(Long id, Integer status) {  
80 - // 校验是否可以更新  
81 - validateRoleForUpdate(id);  
82 85
83 - // 更新状态  
84 - RoleDO updateObj = new RoleDO().setId(id).setStatus(status);  
85 - roleMapper.updateById(updateObj); 86 + // 3. 记录操作日志上下文
  87 + LogRecordContext.putVariable("role", role);
86 } 88 }
87 89
88 @Override 90 @Override
@@ -102,13 +104,19 @@ public class RoleServiceImpl implements RoleService { @@ -102,13 +104,19 @@ public class RoleServiceImpl implements RoleService {
102 @Override 104 @Override
103 @Transactional(rollbackFor = Exception.class) 105 @Transactional(rollbackFor = Exception.class)
104 @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") 106 @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
  107 + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_DELETE_SUB_TYPE, bizNo = "{{#id}}",
  108 + success = SYSTEM_ROLE_DELETE_SUCCESS)
105 public void deleteRole(Long id) { 109 public void deleteRole(Long id) {
106 - // 校验是否可以更新  
107 - validateRoleForUpdate(id);  
108 - // 标记删除 110 + // 1. 校验是否可以更新
  111 + RoleDO role = validateRoleForUpdate(id);
  112 +
  113 + // 2.1 标记删除
109 roleMapper.deleteById(id); 114 roleMapper.deleteById(id);
110 - // 删除相关数据 115 + // 2.2 删除相关数据
111 permissionService.processRoleDeleted(id); 116 permissionService.processRoleDeleted(id);
  117 +
  118 + // 3. 记录操作日志上下文
  119 + LogRecordContext.putVariable("role", role);
112 } 120 }
113 121
114 /** 122 /**
@@ -149,15 +157,16 @@ public class RoleServiceImpl implements RoleService { @@ -149,15 +157,16 @@ public class RoleServiceImpl implements RoleService {
149 * @param id 角色编号 157 * @param id 角色编号
150 */ 158 */
151 @VisibleForTesting 159 @VisibleForTesting
152 - void validateRoleForUpdate(Long id) {  
153 - RoleDO roleDO = roleMapper.selectById(id);  
154 - if (roleDO == null) { 160 + RoleDO validateRoleForUpdate(Long id) {
  161 + RoleDO role = roleMapper.selectById(id);
  162 + if (role == null) {
155 throw exception(ROLE_NOT_EXISTS); 163 throw exception(ROLE_NOT_EXISTS);
156 } 164 }
157 // 内置角色,不允许删除 165 // 内置角色,不允许删除
158 - if (RoleTypeEnum.SYSTEM.getType().equals(roleDO.getType())) { 166 + if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) {
159 throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); 167 throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
160 } 168 }
  169 + return role;
161 } 170 }
162 171
163 @Override 172 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
@@ -27,6 +27,10 @@ import cn.iocoder.yudao.module.system.service.dept.PostService; @@ -27,6 +27,10 @@ import cn.iocoder.yudao.module.system.service.dept.PostService;
27 import cn.iocoder.yudao.module.system.service.permission.PermissionService; 27 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
28 import cn.iocoder.yudao.module.system.service.tenant.TenantService; 28 import cn.iocoder.yudao.module.system.service.tenant.TenantService;
29 import com.google.common.annotations.VisibleForTesting; 29 import com.google.common.annotations.VisibleForTesting;
  30 +import com.mzt.logapi.context.LogRecordContext;
  31 +import com.mzt.logapi.service.impl.DiffParseFunction;
  32 +import com.mzt.logapi.starter.annotation.LogRecord;
  33 +import jakarta.annotation.Resource;
30 import lombok.extern.slf4j.Slf4j; 34 import lombok.extern.slf4j.Slf4j;
31 import org.springframework.beans.factory.annotation.Value; 35 import org.springframework.beans.factory.annotation.Value;
32 import org.springframework.context.annotation.Lazy; 36 import org.springframework.context.annotation.Lazy;
@@ -34,7 +38,6 @@ import org.springframework.security.crypto.password.PasswordEncoder; @@ -34,7 +38,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
34 import org.springframework.stereotype.Service; 38 import org.springframework.stereotype.Service;
35 import org.springframework.transaction.annotation.Transactional; 39 import org.springframework.transaction.annotation.Transactional;
36 40
37 -import jakarta.annotation.Resource;  
38 import java.io.InputStream; 41 import java.io.InputStream;
39 import java.time.LocalDateTime; 42 import java.time.LocalDateTime;
40 import java.util.*; 43 import java.util.*;
@@ -43,6 +46,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -43,6 +46,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
43 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 46 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
44 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 47 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
45 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 48 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  49 +import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
46 50
47 /** 51 /**
48 * 后台用户 Service 实现类 52 * 后台用户 Service 实现类
@@ -79,42 +83,54 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -79,42 +83,54 @@ public class AdminUserServiceImpl implements AdminUserService {
79 83
80 @Override 84 @Override
81 @Transactional(rollbackFor = Exception.class) 85 @Transactional(rollbackFor = Exception.class)
  86 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}",
  87 + success = SYSTEM_USER_CREATE_SUCCESS)
82 public Long createUser(UserSaveReqVO createReqVO) { 88 public Long createUser(UserSaveReqVO createReqVO) {
83 - // 校验账户配合 89 + // 1.1 校验账户配合
84 tenantService.handleTenantInfo(tenant -> { 90 tenantService.handleTenantInfo(tenant -> {
85 long count = userMapper.selectCount(); 91 long count = userMapper.selectCount();
86 if (count >= tenant.getAccountCount()) { 92 if (count >= tenant.getAccountCount()) {
87 throw exception(USER_COUNT_MAX, tenant.getAccountCount()); 93 throw exception(USER_COUNT_MAX, tenant.getAccountCount());
88 } 94 }
89 }); 95 });
90 - // 校验正确性 96 + // 1.2 校验正确性
91 validateUserForCreateOrUpdate(null, createReqVO.getUsername(), 97 validateUserForCreateOrUpdate(null, createReqVO.getUsername(),
92 createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds()); 98 createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
93 - // 插入用户 99 + // 2.1 插入用户
94 AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class); 100 AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
95 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启 101 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
96 user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码 102 user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
97 userMapper.insert(user); 103 userMapper.insert(user);
98 - // 插入关联岗位 104 + // 2.2 插入关联岗位
99 if (CollectionUtil.isNotEmpty(user.getPostIds())) { 105 if (CollectionUtil.isNotEmpty(user.getPostIds())) {
100 userPostMapper.insertBatch(convertList(user.getPostIds(), 106 userPostMapper.insertBatch(convertList(user.getPostIds(),
101 postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId))); 107 postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId)));
102 } 108 }
  109 +
  110 + // 3. 记录操作日志上下文
  111 + LogRecordContext.putVariable("user", user);
103 return user.getId(); 112 return user.getId();
104 } 113 }
105 114
106 @Override 115 @Override
107 @Transactional(rollbackFor = Exception.class) 116 @Transactional(rollbackFor = Exception.class)
  117 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
  118 + success = SYSTEM_USER_UPDATE_SUCCESS)
108 public void updateUser(UserSaveReqVO updateReqVO) { 119 public void updateUser(UserSaveReqVO updateReqVO) {
109 updateReqVO.setPassword(null); // 特殊:此处不更新密码 120 updateReqVO.setPassword(null); // 特殊:此处不更新密码
110 - // 校验正确性  
111 - validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(), 121 + // 1. 校验正确性
  122 + AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(),
112 updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds()); 123 updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds());
113 - // 更新用户 124 +
  125 + // 2.1 更新用户
114 AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class); 126 AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
115 userMapper.updateById(updateObj); 127 userMapper.updateById(updateObj);
116 - // 更新岗位 128 + // 2.2 更新岗位
117 updateUserPost(updateReqVO, updateObj); 129 updateUserPost(updateReqVO, updateObj);
  130 +
  131 + // 3. 记录操作日志上下文
  132 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class));
  133 + LogRecordContext.putVariable("user", oldUser);
118 } 134 }
119 135
120 private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) { 136 private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {
@@ -124,7 +140,7 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -124,7 +140,7 @@ public class AdminUserServiceImpl implements AdminUserService {
124 Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds()); 140 Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
125 Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds); 141 Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
126 Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds); 142 Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
127 - // 执行新增和删除。对于已经授权的菜单,不用做任何处理 143 + // 执行新增和删除。对于已经授权的岗位,不用做任何处理
128 if (!CollectionUtil.isEmpty(createPostIds)) { 144 if (!CollectionUtil.isEmpty(createPostIds)) {
129 userPostMapper.insertBatch(convertList(createPostIds, 145 userPostMapper.insertBatch(convertList(createPostIds,
130 postId -> new UserPostDO().setUserId(userId).setPostId(postId))); 146 postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
@@ -173,14 +189,21 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -173,14 +189,21 @@ public class AdminUserServiceImpl implements AdminUserService {
173 } 189 }
174 190
175 @Override 191 @Override
  192 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}",
  193 + success = SYSTEM_USER_UPDATE_PASSWORD_SUCCESS)
176 public void updateUserPassword(Long id, String password) { 194 public void updateUserPassword(Long id, String password) {
177 - // 校验用户存在  
178 - validateUserExists(id);  
179 - // 更新密码 195 + // 1. 校验用户存在
  196 + AdminUserDO user = validateUserExists(id);
  197 +
  198 + // 2. 更新密码
180 AdminUserDO updateObj = new AdminUserDO(); 199 AdminUserDO updateObj = new AdminUserDO();
181 updateObj.setId(id); 200 updateObj.setId(id);
182 updateObj.setPassword(encodePassword(password)); // 加密密码 201 updateObj.setPassword(encodePassword(password)); // 加密密码
183 userMapper.updateById(updateObj); 202 userMapper.updateById(updateObj);
  203 +
  204 + // 3. 记录操作日志上下文
  205 + LogRecordContext.putVariable("user", user);
  206 + LogRecordContext.putVariable("newPassword", updateObj.getPassword());
184 } 207 }
185 208
186 @Override 209 @Override
@@ -196,15 +219,21 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -196,15 +219,21 @@ public class AdminUserServiceImpl implements AdminUserService {
196 219
197 @Override 220 @Override
198 @Transactional(rollbackFor = Exception.class) 221 @Transactional(rollbackFor = Exception.class)
  222 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
  223 + success = SYSTEM_USER_DELETE_SUCCESS)
199 public void deleteUser(Long id) { 224 public void deleteUser(Long id) {
200 - // 校验用户存在  
201 - validateUserExists(id);  
202 - // 删除用户 225 + // 1. 校验用户存在
  226 + AdminUserDO user = validateUserExists(id);
  227 +
  228 + // 2.1 删除用户
203 userMapper.deleteById(id); 229 userMapper.deleteById(id);
204 - // 删除用户关联数据 230 + // 2.2 删除用户关联数据
205 permissionService.processUserDeleted(id); 231 permissionService.processUserDeleted(id);
206 - // 删除用户岗位 232 + // 2.2 删除用户岗位
207 userPostMapper.deleteByUserId(id); 233 userPostMapper.deleteByUserId(id);
  234 +
  235 + // 3. 记录操作日志上下文
  236 + LogRecordContext.putVariable("user", user);
208 } 237 }
209 238
210 @Override 239 @Override
@@ -294,12 +323,12 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -294,12 +323,12 @@ public class AdminUserServiceImpl implements AdminUserService {
294 return deptIds; 323 return deptIds;
295 } 324 }
296 325
297 - private void validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, 326 + private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email,
298 Long deptId, Set<Long> postIds) { 327 Long deptId, Set<Long> postIds) {
299 // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确 328 // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确
300 - DataPermissionUtils.executeIgnore(() -> { 329 + return DataPermissionUtils.executeIgnore(() -> {
301 // 校验用户存在 330 // 校验用户存在
302 - validateUserExists(id); 331 + AdminUserDO user = validateUserExists(id);
303 // 校验用户名唯一 332 // 校验用户名唯一
304 validateUsernameUnique(id, username); 333 validateUsernameUnique(id, username);
305 // 校验手机号唯一 334 // 校验手机号唯一
@@ -310,18 +339,20 @@ public class AdminUserServiceImpl implements AdminUserService { @@ -310,18 +339,20 @@ public class AdminUserServiceImpl implements AdminUserService {
310 deptService.validateDeptList(CollectionUtils.singleton(deptId)); 339 deptService.validateDeptList(CollectionUtils.singleton(deptId));
311 // 校验岗位处于开启状态 340 // 校验岗位处于开启状态
312 postService.validatePostList(postIds); 341 postService.validatePostList(postIds);
  342 + return user;
313 }); 343 });
314 } 344 }
315 345
316 @VisibleForTesting 346 @VisibleForTesting
317 - void validateUserExists(Long id) { 347 + AdminUserDO validateUserExists(Long id) {
318 if (id == null) { 348 if (id == null) {
319 - return; 349 + return null;
320 } 350 }
321 AdminUserDO user = userMapper.selectById(id); 351 AdminUserDO user = userMapper.selectById(id);
322 if (user == null) { 352 if (user == null) {
323 throw exception(USER_NOT_EXISTS); 353 throw exception(USER_NOT_EXISTS);
324 } 354 }
  355 + return user;
325 } 356 }
326 357
327 @VisibleForTesting 358 @VisibleForTesting