Commit 09a3162dc0322ec7c3665fe611d36401b351e2f0

Authored by 黄 x
1 parent 699e9493

feat: 合并yunteng的IOT代码

Showing 187 changed files with 8072 additions and 430 deletions
  1 +package org.thingsboard.server.controller.yunteng;
  2 +
  3 +
  4 +import lombok.RequiredArgsConstructor;
  5 +import org.springframework.util.Assert;
  6 +import org.springframework.web.bind.annotation.*;
  7 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  8 +import org.thingsboard.server.common.data.yunteng.dto.RoleDTO;
  9 +import org.thingsboard.server.common.data.yunteng.dto.request.RoleReqDTO;
  10 +import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
  11 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
  12 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  13 +import org.thingsboard.server.controller.BaseController;
  14 +import org.thingsboard.server.dao.yunteng.service.RoleService;
  15 +
  16 +import java.util.HashMap;
  17 +import java.util.List;
  18 +import java.util.Set;
  19 +
  20 +import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.*;
  21 +
  22 +
  23 +@RestController
  24 +@RequestMapping("api/v1/role")
  25 +@RequiredArgsConstructor
  26 +public class RoleController extends BaseController {
  27 +
  28 + private final RoleService roleService;
  29 +
  30 + @GetMapping(params = {PAGE_SIZE, PAGE})
  31 + public PageData<RoleDTO> pageRole(
  32 + @RequestParam(PAGE_SIZE) int pageSize,
  33 + @RequestParam(PAGE) int page,
  34 + @RequestParam(value = "roleName", required = false) String roleName,
  35 + @RequestParam(value = "status", required = false) Integer status,
  36 + @RequestParam(value = "roleType", required = false) RoleEnum roleType,
  37 + @RequestParam(value = ORDER_FILED, required = false) String orderBy,
  38 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType) throws ThingsboardException {
  39 + HashMap<String, Object> queryMap = new HashMap<>();
  40 + queryMap.put(PAGE_SIZE, pageSize);
  41 + queryMap.put(PAGE, page);
  42 + queryMap.put(ORDER_FILED, orderBy);
  43 + queryMap.put("roleName", roleName);
  44 + if (status != null) {
  45 + queryMap.put("status", status == 1);
  46 + }
  47 + if(roleType !=null){
  48 + queryMap.put("roleType", roleType.name());
  49 + }
  50 + if (orderType != null) {
  51 + queryMap.put(ORDER_TYPE, orderType.name());
  52 + }
  53 + return roleService.page(getCurrentUser().isSysadmin(), getCurrentUser().isPlatformAdmin(), getCurrentUser().getCurrentTenantId(),queryMap);
  54 + }
  55 +
  56 + @DeleteMapping
  57 + public void deleteRole(@RequestBody String[] ids) throws ThingsboardException {
  58 + roleService.deleteRole(ids,getCurrentUser().getCurrentTenantId());
  59 + }
  60 +
  61 + @GetMapping("/me/permissions")
  62 + public Set<String> getPermissions() throws ThingsboardException {
  63 + return roleService.getPermissions(getCurrentUser().isSysadmin(), getCurrentUser().isTenantAdmin(), getCurrentUser().getCurrentTenantId(), getCurrentUser().getCurrentUserId());
  64 + }
  65 +
  66 + @PutMapping("updateRoleStatus/{roleId}/{status}")
  67 + public void updateRoleStatus(
  68 + @PathVariable("roleId") String roleId, @PathVariable("status") int status) throws ThingsboardException {
  69 + Assert.isTrue(status == 0 || status == 1, "role status is not correct");
  70 + roleService.updateRoleStatus(roleId, status, getCurrentUser().isSysadmin() ,getCurrentUser().getCurrentTenantId());
  71 + }
  72 +
  73 + @PostMapping("saveOrUpdateRoleInfoWithMenu")
  74 + public RoleDTO saveOrUpdateRoleInfoWithMenu(@RequestBody RoleReqDTO roleReqDTO) throws ThingsboardException {
  75 + return roleService.saveOrUpdateRoleInfoWithMenu(
  76 + roleReqDTO,
  77 + getCurrentUser().isSysadmin(),
  78 + getCurrentUser().isPlatformAdmin(),
  79 + getCurrentUser().getCurrentTenantId());
  80 + }
  81 +
  82 + @PostMapping("/find/list")
  83 + public List<RoleDTO> findRoleInfoList(@RequestBody RoleDTO roleDTO) throws ThingsboardException {
  84 + return roleService.findRoleInfo(getCurrentUser().isTenantAdmin(), getCurrentUser().getCurrentTenantId(),getCurrentUser().getCurrentUserId(), roleDTO);
  85 + }
  86 +}
... ...
  1 +package org.thingsboard.server.controller.yunteng;
  2 +
  3 +import lombok.RequiredArgsConstructor;
  4 +import org.springframework.http.ResponseEntity;
  5 +import org.springframework.security.access.prepost.PreAuthorize;
  6 +import org.springframework.util.Assert;
  7 +import org.springframework.validation.annotation.Validated;
  8 +import org.springframework.web.bind.annotation.*;
  9 +import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
  10 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  11 +import org.thingsboard.server.common.data.yunteng.common.UpdateGroup;
  12 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  13 +import org.thingsboard.server.common.data.yunteng.dto.MenuDTO;
  14 +import org.thingsboard.server.common.data.yunteng.dto.TenantDTO;
  15 +import org.thingsboard.server.common.data.yunteng.dto.UserDTO;
  16 +import org.thingsboard.server.common.data.yunteng.dto.request.TenantReqDTO;
  17 +import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
  18 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  19 +import org.thingsboard.server.controller.BaseController;
  20 +import org.thingsboard.server.dao.yunteng.service.MenuService;
  21 +import org.thingsboard.server.dao.yunteng.service.YtTenantService;
  22 +import org.thingsboard.server.dao.yunteng.service.YtUserService;
  23 +
  24 +import java.net.URI;
  25 +import java.util.*;
  26 +
  27 +import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.*;
  28 +
  29 +@RestController
  30 +@RequestMapping("api/v1/admin")
  31 +@RequiredArgsConstructor
  32 +@PreAuthorize("hasAnyRole('SYS_ADMIN','PLATFORM_ADMIN')")
  33 +public class YtAdminController extends BaseController {
  34 +
  35 + private final YtTenantService ytTenantService;
  36 + private final MenuService menuService;
  37 + private final YtUserService userService;
  38 +
  39 + @PostMapping("/tenant")
  40 + public ResponseEntity<TenantDTO> saveTenant(@RequestBody TenantReqDTO tenantReqDTO) {
  41 + TenantDTO newTenant = ytTenantService.createNewTenant(tenantReqDTO);
  42 + URI location =
  43 + ServletUriComponentsBuilder.fromCurrentRequest()
  44 + .path("/tenant/getById/{id}")
  45 + .buildAndExpand(newTenant.getId())
  46 + .toUri();
  47 + return ResponseEntity.created(location).body(newTenant);
  48 + }
  49 +
  50 + @GetMapping(
  51 + path = "tenant/page",
  52 + params = {PAGE_SIZE, PAGE})
  53 + public PageData<TenantDTO> pageUser(
  54 + @RequestParam(PAGE_SIZE) int pageSize,
  55 + @RequestParam(PAGE) int page,
  56 + @RequestParam(value = "tenantName", required = false) String tenantName,
  57 + @RequestParam(value = ORDER_FILED, required = false) String orderBy,
  58 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType) {
  59 + HashMap<String, Object> queryMap = new HashMap<>();
  60 + queryMap.put(PAGE_SIZE, pageSize);
  61 + queryMap.put(PAGE, page);
  62 + queryMap.put(ORDER_FILED, orderBy);
  63 + if (orderType != null) {
  64 + queryMap.put(ORDER_TYPE, orderType.name());
  65 + }
  66 + queryMap.put("tenantName", tenantName);
  67 + return ytTenantService.page(queryMap);
  68 + }
  69 +
  70 + @PutMapping("/tenant")
  71 + public TenantDTO updateTenant(@RequestBody TenantDTO tenantDTO) {
  72 + Assert.notNull(tenantDTO, "tenant cannot be null");
  73 + Assert.notNull(tenantDTO.getId(), "tenant id cannot be null when update");
  74 + return ytTenantService.updateTenant(tenantDTO);
  75 + }
  76 +
  77 + @GetMapping("/tenant/roles/{tenantCode}")
  78 + public ResponseEntity<List<String>> getTenantRolesByTenantCode(
  79 + @PathVariable("tenantCode") String tenantCode) {
  80 + return ResponseEntity.ok(ytTenantService.getTenantRolesByTenantCode(tenantCode));
  81 + }
  82 +
  83 + @DeleteMapping("/tenant")
  84 + public void deleteTenant(@RequestBody String[] ids) {
  85 + Assert.notNull(ids, "ids cannot be null");
  86 + if (ids.length == 0) {
  87 + throw new DataValidationException("id cannot be empty");
  88 + }
  89 + ytTenantService.deleteTenants(ids);
  90 + }
  91 +
  92 + @DeleteMapping("/user/deleteTenantAdmin")
  93 + public void deleteTenantAdmin(@RequestBody String[] ids) throws ThingsboardException {
  94 + Assert.notNull(ids, "ids cannot be null");
  95 + userService.deleteUser(
  96 + new HashSet<>(Arrays.asList(ids)),
  97 + getCurrentUser().isSysadmin(),
  98 + getCurrentUser().getCurrentTenantId());
  99 + }
  100 +
  101 + @GetMapping("/tenant/getById/{id}")
  102 + public ResponseEntity<TenantDTO> getTenant(@PathVariable("id") String id) {
  103 + return ResponseEntity.of(ytTenantService.findById(id));
  104 + }
  105 +
  106 + @PostMapping("/tenant/adminUser")
  107 + public ResponseEntity<UserDTO> createTenantAdmin(
  108 + @RequestParam(value = "sendEmail", required = false, defaultValue = "false")
  109 + boolean sendEmail,
  110 + @RequestParam(value = "sendMsg", required = false, defaultValue = "false") boolean sendMsg,
  111 + @RequestBody UserDTO userDTO)
  112 + throws ThingsboardException {
  113 + UserDTO newUserDTO =
  114 + userService.saveAccount(
  115 + userDTO,
  116 + sendEmail,
  117 + sendMsg,
  118 + getCurrentUser().isSysadmin(),
  119 + getCurrentUser().getCurrentTenantId());
  120 + Optional<UserDTO> optional =
  121 + userService.getUser(
  122 + newUserDTO.getId(),
  123 + getCurrentUser().isSysadmin(),
  124 + getCurrentUser().getCurrentTenantId());
  125 + return ResponseEntity.ok(optional.get());
  126 + }
  127 +
  128 + @GetMapping("/menu/getAll")
  129 + public ResponseEntity<List<MenuDTO>> getMenus() throws ThingsboardException {
  130 + return ResponseEntity.ok(menuService.getAllMenus(getCurrentUser().getCurrentTenantId()));
  131 + }
  132 +
  133 + @GetMapping("me/menus")
  134 + public ResponseEntity<List<MenuDTO>> getMyMenus() throws ThingsboardException {
  135 + return ResponseEntity.ok(
  136 + menuService.getMyMenus(
  137 + getCurrentUser().getCurrentTenantId(),
  138 + getCurrentUser().getCurrentUserId(),
  139 + getCurrentUser().isSysadmin(), getCurrentUser().isTenantAdmin()));
  140 + }
  141 +
  142 + @PutMapping("/menu/assign/{tenantCode}")
  143 + public void assignMenuToTenant(
  144 + @RequestBody String[] menuIds, @PathVariable("tenantCode") String tenantCode) throws ThingsboardException {
  145 + menuService.assignMenuToTenant(getCurrentUser().getCurrentTenantId(), menuIds);
  146 + }
  147 +
  148 + @PostMapping("tenant/updateOrCreateTenant")
  149 + public TenantDTO updateOrCreateTenant(
  150 + @Validated(UpdateGroup.class) @RequestBody TenantReqDTO tenantReqDTO) {
  151 + return ytTenantService.updateOrCreateTenant(tenantReqDTO);
  152 + }
  153 +}
... ...
  1 +package org.thingsboard.server.controller.yunteng;
  2 +
  3 +import io.swagger.annotations.Api;
  4 +import io.swagger.annotations.ApiOperation;
  5 +import io.swagger.annotations.ApiResponse;
  6 +import io.swagger.annotations.ApiResponses;
  7 +import lombok.RequiredArgsConstructor;
  8 +import org.apache.commons.lang3.StringUtils;
  9 +import org.springframework.http.ResponseEntity;
  10 +import org.springframework.security.access.prepost.PreAuthorize;
  11 +import org.springframework.util.Assert;
  12 +import org.springframework.validation.annotation.Validated;
  13 +import org.springframework.web.bind.annotation.*;
  14 +import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
  15 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  16 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  17 +import org.thingsboard.server.common.data.yunteng.common.DeleteGroup;
  18 +import org.thingsboard.server.common.data.yunteng.utils.Demo;
  19 +import org.thingsboard.server.common.data.yunteng.utils.ExcelUtil;
  20 +import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
  21 +import org.thingsboard.server.common.data.yunteng.dto.UserDTO;
  22 +import org.thingsboard.server.common.data.yunteng.dto.UserInfoDTO;
  23 +import org.thingsboard.server.common.data.yunteng.dto.request.AccountReqDTO;
  24 +import org.thingsboard.server.common.data.yunteng.dto.request.RoleOrOrganizationReqDTO;
  25 +import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
  26 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
  27 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  28 +import org.thingsboard.server.common.data.yunteng.utils.tools.ResponseResult;
  29 +import org.thingsboard.server.controller.BaseController;
  30 +import org.thingsboard.server.dao.yunteng.service.YtUserService;
  31 +
  32 +import javax.servlet.http.HttpServletRequest;
  33 +import javax.servlet.http.HttpServletResponse;
  34 +import java.io.IOException;
  35 +import java.net.URI;
  36 +import java.util.HashMap;
  37 +import java.util.List;
  38 +
  39 +import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.*;
  40 +
  41 +@RestController
  42 +@RequestMapping("api/v1/user")
  43 +@RequiredArgsConstructor
  44 +@Api(value = "用户接口")
  45 +public class YtUserController extends BaseController {
  46 +
  47 + private final YtUserService userService;
  48 +
  49 + @GetMapping("{userId}")
  50 + public ResponseEntity<UserDTO> getUser(@PathVariable("userId") String userId)
  51 + throws ThingsboardException {
  52 + return ResponseEntity.of(
  53 + userService.getUser(
  54 + userId, getCurrentUser().isSysadmin(), getCurrentUser().getCurrentTenantId()));
  55 + }
  56 +
  57 + @GetMapping("me/info")
  58 + @ApiResponses({@ApiResponse(code = 200, message = "OK", response = UserInfoDTO.class)})
  59 + @ApiOperation(value = "获取当前用户信息")
  60 + public UserInfoDTO myInfo() throws ThingsboardException {
  61 + return userService.me(
  62 + getCurrentUser().getCurrentUserId(),
  63 + getCurrentUser().getCurrentTenantId(),
  64 + getCurrentUser().getRoles());
  65 + }
  66 +
  67 + @GetMapping(
  68 + path = "page",
  69 + params = {PAGE_SIZE, PAGE})
  70 + public PageData<UserDTO> pageUser(
  71 + @RequestParam(PAGE_SIZE) int pageSize,
  72 + @RequestParam(PAGE) int page,
  73 + @RequestParam(value = "realName", required = false) String realName,
  74 + @RequestParam(value = "username", required = false) String username,
  75 + @RequestParam(value = "tenantCode", required = false) String tenantCode,
  76 + @RequestParam(value = "roleType", required = false) RoleEnum roleType,
  77 + @RequestParam(value = ORDER_FILED, required = false) String orderBy,
  78 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType)
  79 + throws ThingsboardException {
  80 + HashMap<String, Object> queryMap = new HashMap<>();
  81 + queryMap.put(PAGE_SIZE, pageSize);
  82 + queryMap.put(PAGE, page);
  83 + queryMap.put(ORDER_FILED, orderBy);
  84 + queryMap.put("realName", realName);
  85 + queryMap.put("username", username);
  86 + if (getCurrentUser().isSysadmin()) {
  87 + if (StringUtils.isEmpty(tenantCode)) {
  88 + tenantCode = getCurrentUser().getCurrentTenantId();
  89 + }
  90 + queryMap.put("tenantCode", tenantCode);
  91 + }
  92 + if (null != roleType) {
  93 + queryMap.put("roleType", roleType.name());
  94 + }
  95 + if (orderType != null) {
  96 + queryMap.put(ORDER_TYPE, orderType.name());
  97 + }
  98 + return userService.page(
  99 + queryMap,
  100 + getCurrentUser().isSysadmin(),
  101 + getCurrentUser().isPlatformAdmin(),
  102 + getCurrentUser().isTenantAdmin(),
  103 + getCurrentUser().getCurrentTenantId());
  104 + }
  105 +
  106 + @PutMapping
  107 + public UserDTO updateUser(@RequestBody UserDTO userDTO) throws ThingsboardException {
  108 + return userService.updateUser(
  109 + userDTO, getCurrentUser().isSysadmin(), getCurrentUser().getCurrentTenantId());
  110 + }
  111 +
  112 + @PostMapping
  113 + public ResponseEntity<UserDTO> addUser(
  114 + @RequestParam(value = "sendEmail", required = false, defaultValue = "false")
  115 + boolean sendEmail,
  116 + @RequestParam(value = "sendMsg", required = false, defaultValue = "false") boolean sendMsg,
  117 + @Validated({AddGroup.class}) @RequestBody UserDTO userDTO)
  118 + throws ThingsboardException {
  119 + UserDTO newUserDTO =
  120 + userService.saveAccount(
  121 + userDTO,
  122 + sendEmail,
  123 + sendMsg,
  124 + getCurrentUser().isSysadmin(),
  125 + getCurrentUser().getCurrentTenantId());
  126 + URI location =
  127 + ServletUriComponentsBuilder.fromCurrentRequest()
  128 + .path("{id}")
  129 + .buildAndExpand(newUserDTO.getId())
  130 + .toUri();
  131 + return ResponseEntity.created(location).body(newUserDTO);
  132 + }
  133 +
  134 + @PreAuthorize("hasRole('SYS_ADMIN')")
  135 + @PostMapping("saveTenantAdmin")
  136 + public UserDTO saveTenantAdmin(@RequestBody UserDTO userDTO) throws ThingsboardException {
  137 + Assert.isTrue(StringUtils.isNotBlank(userDTO.getTenantCode()), "tenant code must exist");
  138 + Assert.notNull(userDTO.getUsername(), "username must exist");
  139 + Assert.notNull(userDTO.getRealName(), "real name must exist");
  140 + return userService.saveTenantAdmin(
  141 + userDTO, getCurrentUser().isSysadmin(), getCurrentUser().getCurrentTenantId());
  142 + }
  143 +
  144 + @DeleteMapping
  145 + public void deleteUser(@Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO)
  146 + throws ThingsboardException {
  147 + userService.deleteUser(
  148 + deleteDTO.getIds(), getCurrentUser().isSysadmin(), getCurrentUser().getCurrentTenantId());
  149 + }
  150 +
  151 + @RequestMapping(
  152 + value = "/{userId}/activationLink",
  153 + method = RequestMethod.GET,
  154 + produces = "text/plain")
  155 + public String getActivationLink(
  156 + @PathVariable("userId") String strUserId, HttpServletRequest request) {
  157 +
  158 + return null;
  159 + }
  160 +
  161 + @GetMapping("getGroupUserByGroupId/{groupId}")
  162 + public ResponseEntity<List<UserDTO>> getGroupUserByGroupId(
  163 + @PathVariable("groupId") String groupId) throws ThingsboardException {
  164 + return ResponseEntity.of(
  165 + userService.getOrganizationUserByOrganizationId(
  166 + groupId, getCurrentUser().getCurrentTenantId()));
  167 + }
  168 +
  169 + @Demo("这是一个演示的请求,查询当前用户,并将其导出到excel,参照完毕请务必删除")
  170 + @GetMapping("export")
  171 + public void export(HttpServletResponse response) throws IOException, ThingsboardException {
  172 + UserInfoDTO me =
  173 + userService.me(
  174 + getCurrentUser().getCurrentUserId(),
  175 + getCurrentUser().getCurrentTenantId(),
  176 + getCurrentUser().getRoles());
  177 + ExcelUtil.exportExcel(response, "用户信息", "user info", List.of(me), UserInfoDTO.class);
  178 + }
  179 +
  180 + @GetMapping("/accountExist/{username}")
  181 + public ResponseResult<UserDTO> accountExist(@PathVariable String username)
  182 + throws ThingsboardException {
  183 + return ResponseResult.success(
  184 + userService.accountExist(username, getCurrentUser().getCurrentTenantId()));
  185 + }
  186 +
  187 + @PostMapping("/relation")
  188 + public String[] getUserRoleOrGroup(
  189 + @Validated @RequestBody RoleOrOrganizationReqDTO roleOrGroupReqDTO) {
  190 + return userService.getUserRoleOrOrganization(roleOrGroupReqDTO);
  191 + }
  192 +
  193 + @PostMapping("/reset")
  194 + @ApiOperation(value = "修改密码")
  195 + public ResponseResult<Boolean> changePassword(@RequestBody AccountReqDTO accountReqDTO) {
  196 + return ResponseResult.success(userService.changePassword(accountReqDTO));
  197 + }
  198 +}
... ...
... ... @@ -20,13 +20,16 @@ import org.springframework.security.authentication.AuthenticationProvider;
20 20 import org.springframework.security.core.Authentication;
21 21 import org.springframework.security.core.AuthenticationException;
22 22 import org.springframework.stereotype.Component;
23   -import org.thingsboard.server.service.security.auth.TokenOutdatingService;
24 23 import org.thingsboard.server.service.security.auth.JwtAuthenticationToken;
  24 +import org.thingsboard.server.service.security.auth.TokenOutdatingService;
25 25 import org.thingsboard.server.service.security.exception.JwtExpiredTokenException;
26 26 import org.thingsboard.server.service.security.model.SecurityUser;
27 27 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
28 28 import org.thingsboard.server.service.security.model.token.RawAccessJwtToken;
29 29
  30 +/**
  31 + * Jwt身份提供者
  32 + */
30 33 @Component
31 34 @RequiredArgsConstructor
32 35 public class JwtAuthenticationProvider implements AuthenticationProvider {
... ... @@ -34,11 +37,18 @@ public class JwtAuthenticationProvider implements AuthenticationProvider {
34 37 private final JwtTokenFactory tokenFactory;
35 38 private final TokenOutdatingService tokenOutdatingService;
36 39
  40 + /**
  41 + * 进行身份鉴定
  42 + * @param authentication 证明
  43 + * @return 证明
  44 + * @throws AuthenticationException 身份验证异常
  45 + */
37 46 @Override
38 47 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
39 48 RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials();
40 49 SecurityUser securityUser = tokenFactory.parseAccessJwtToken(rawAccessToken);
41 50
  51 + //token失效了 过时了
42 52 if (tokenOutdatingService.isOutdated(rawAccessToken, securityUser.getId())) {
43 53 throw new JwtExpiredTokenException("Token is outdated");
44 54 }
... ...
... ... @@ -33,15 +33,15 @@ import org.thingsboard.server.common.data.id.EntityId;
33 33 import org.thingsboard.server.common.data.id.TenantId;
34 34 import org.thingsboard.server.common.data.id.UserId;
35 35 import org.thingsboard.server.common.data.security.Authority;
36   -import org.thingsboard.server.service.security.auth.TokenOutdatingService;
37   -import org.thingsboard.server.common.data.security.UserCredentials;
38   -import org.thingsboard.server.dao.customer.CustomerService;
39   -import org.thingsboard.server.dao.user.UserService;
40 36 import org.thingsboard.server.service.security.auth.RefreshAuthenticationToken;
  37 +import org.thingsboard.server.service.security.auth.TokenOutdatingService;
41 38 import org.thingsboard.server.service.security.model.SecurityUser;
42 39 import org.thingsboard.server.service.security.model.UserPrincipal;
43 40 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
44 41 import org.thingsboard.server.service.security.model.token.RawAccessJwtToken;
  42 +import org.thingsboard.server.common.data.security.UserCredentials;
  43 +import org.thingsboard.server.dao.customer.CustomerService;
  44 +import org.thingsboard.server.dao.user.UserService;
45 45
46 46 import java.util.UUID;
47 47
... ...
... ... @@ -17,6 +17,14 @@ package org.thingsboard.server.service.security.auth.jwt.extractor;
17 17
18 18 import javax.servlet.http.HttpServletRequest;
19 19
  20 +/**
  21 + * 令牌器接口
  22 + */
20 23 public interface TokenExtractor {
  24 + /**
  25 + * 提取令牌
  26 + * @param request 请求
  27 + * @return 令牌
  28 + */
21 29 public String extract(HttpServletRequest request);
22 30 }
\ No newline at end of file
... ...
... ... @@ -16,7 +16,6 @@
16 16 package org.thingsboard.server.service.security.auth.oauth2;
17 17
18 18 import org.springframework.beans.factory.annotation.Autowired;
19   -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
20 19 import org.springframework.security.core.AuthenticationException;
21 20 import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
22 21 import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
... ... @@ -26,7 +25,6 @@ import org.thingsboard.server.common.data.id.CustomerId;
26 25 import org.thingsboard.server.common.data.id.EntityId;
27 26 import org.thingsboard.server.common.data.id.TenantId;
28 27 import org.thingsboard.server.service.security.system.SystemSecurityService;
29   -import org.thingsboard.server.utils.MiscUtils;
30 28
31 29 import javax.servlet.ServletException;
32 30 import javax.servlet.http.HttpServletRequest;
... ...
... ... @@ -31,10 +31,10 @@ import org.thingsboard.server.common.data.id.TenantId;
31 31 import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
32 32 import org.thingsboard.server.common.data.security.model.JwtToken;
33 33 import org.thingsboard.server.dao.oauth2.OAuth2Service;
  34 +import org.thingsboard.server.service.security.system.SystemSecurityService;
34 35 import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
35 36 import org.thingsboard.server.service.security.model.SecurityUser;
36 37 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
37   -import org.thingsboard.server.service.security.system.SystemSecurityService;
38 38
39 39 import javax.servlet.http.HttpServletRequest;
40 40 import javax.servlet.http.HttpServletResponse;
... ...
1 1 /**
2 2 * Copyright © 2016-2021 The Thingsboard Authors
3 3 *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
  4 + * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5 + * except in compliance with the License. You may obtain a copy of the License at
7 6 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  7 + * <p>http://www.apache.org/licenses/LICENSE-2.0
9 8 *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
  9 + * <p>Unless required by applicable law or agreed to in writing, software distributed under the
  10 + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  11 + * express or implied. See the License for the specific language governing permissions and
14 12 * limitations under the License.
15 13 */
16 14 package org.thingsboard.server.service.security.auth.rest;
17 15
18 16 import lombok.extern.slf4j.Slf4j;
19 17 import org.springframework.beans.factory.annotation.Autowired;
20   -import org.springframework.security.authentication.AuthenticationProvider;
21   -import org.springframework.security.authentication.BadCredentialsException;
22   -import org.springframework.security.authentication.InsufficientAuthenticationException;
23   -import org.springframework.security.authentication.LockedException;
24   -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  18 +import org.springframework.security.authentication.*;
25 19 import org.springframework.security.core.Authentication;
26 20 import org.springframework.security.core.AuthenticationException;
27 21 import org.springframework.security.core.userdetails.UsernameNotFoundException;
  22 +import org.springframework.security.crypto.password.PasswordEncoder;
28 23 import org.springframework.stereotype.Component;
29 24 import org.springframework.util.Assert;
30 25 import org.thingsboard.server.common.data.Customer;
... ... @@ -36,167 +31,331 @@ import org.thingsboard.server.common.data.id.TenantId;
36 31 import org.thingsboard.server.common.data.id.UserId;
37 32 import org.thingsboard.server.common.data.security.Authority;
38 33 import org.thingsboard.server.common.data.security.UserCredentials;
  34 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  35 +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils;
  36 +import org.thingsboard.server.common.data.yunteng.dto.UserDetailsDTO;
  37 +import org.thingsboard.server.common.data.yunteng.dto.request.CodeTTL;
  38 +import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum;
  39 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
39 40 import org.thingsboard.server.dao.audit.AuditLogService;
40 41 import org.thingsboard.server.dao.customer.CustomerService;
41   -import org.thingsboard.server.dao.user.UserService;
42 42 import org.thingsboard.server.service.security.model.SecurityUser;
43 43 import org.thingsboard.server.service.security.model.UserPrincipal;
44 44 import org.thingsboard.server.service.security.system.SystemSecurityService;
  45 +import org.thingsboard.server.dao.user.UserService;
  46 +import org.thingsboard.server.dao.yunteng.service.YtUserService;
45 47 import ua_parser.Client;
46 48
  49 +import java.time.LocalDateTime;
  50 +import java.util.List;
  51 +import java.util.Objects;
  52 +import java.util.Optional;
47 53 import java.util.UUID;
48 54
  55 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CacheConfigKey.MOBILE_LOGIN_SMS_CODE;
  56 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.DEFAULT_DELIMITER;
49 57
50 58 @Component
51 59 @Slf4j
52 60 public class RestAuthenticationProvider implements AuthenticationProvider {
53 61
54   - private final SystemSecurityService systemSecurityService;
55   - private final UserService userService;
56   - private final CustomerService customerService;
57   - private final AuditLogService auditLogService;
58   -
59   - @Autowired
60   - public RestAuthenticationProvider(final UserService userService,
61   - final CustomerService customerService,
62   - final SystemSecurityService systemSecurityService,
63   - final AuditLogService auditLogService) {
64   - this.userService = userService;
65   - this.customerService = customerService;
66   - this.systemSecurityService = systemSecurityService;
67   - this.auditLogService = auditLogService;
68   - }
69   -
70   - @Override
71   - public Authentication authenticate(Authentication authentication) throws AuthenticationException {
72   - Assert.notNull(authentication, "No authentication data provided");
73   -
74   - Object principal = authentication.getPrincipal();
75   - if (!(principal instanceof UserPrincipal)) {
76   - throw new BadCredentialsException("Authentication Failed. Bad user principal.");
77   - }
  62 + private final SystemSecurityService systemSecurityService;
  63 + private final UserService userService;
  64 + private final CustomerService customerService;
  65 + private final AuditLogService auditLogService;
78 66
79   - UserPrincipal userPrincipal = (UserPrincipal) principal;
80   - if (userPrincipal.getType() == UserPrincipal.Type.USER_NAME) {
81   - String username = userPrincipal.getValue();
82   - String password = (String) authentication.getCredentials();
83   - return authenticateByUsernameAndPassword(authentication, userPrincipal, username, password);
84   - } else {
85   - String publicId = userPrincipal.getValue();
86   - return authenticateByPublicId(userPrincipal, publicId);
87   - }
  67 + @Autowired
  68 + public RestAuthenticationProvider(
  69 + final UserService userService,
  70 + final CustomerService customerService,
  71 + final SystemSecurityService systemSecurityService,
  72 + final AuditLogService auditLogService) {
  73 + this.userService = userService;
  74 + this.customerService = customerService;
  75 + this.systemSecurityService = systemSecurityService;
  76 + this.auditLogService = auditLogService;
  77 + }
  78 +
  79 + @Override
  80 + public Authentication authenticate(Authentication authentication) throws AuthenticationException {
  81 + Assert.notNull(authentication, "No authentication data provided");
  82 +
  83 + Object principal = authentication.getPrincipal();
  84 + if (!(principal instanceof UserPrincipal)) {
  85 + throw new BadCredentialsException("Authentication Failed. Bad user principal.");
88 86 }
89 87
90   - private Authentication authenticateByUsernameAndPassword(Authentication authentication, UserPrincipal userPrincipal, String username, String password) {
91   - User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, username);
92   - if (user == null) {
93   - throw new UsernameNotFoundException("User not found: " + username);
94   - }
  88 + UserPrincipal userPrincipal = (UserPrincipal) principal;
  89 + if (userPrincipal.getType() == UserPrincipal.Type.USER_NAME) {
  90 + String username = userPrincipal.getValue();
  91 + String password = (String) authentication.getCredentials();
  92 + String ytUserName = username;
  93 + UserDetailsDTO ytDetailDTO = new UserDetailsDTO();
  94 + if (!FastIotConstants.EMAIL_PATTERN.matcher(username).matches()) {
  95 + username += FastIotConstants.DEFAULT_EMAIL_SUFFIX_FOR_TB;
  96 + ytDetailDTO = ytUserDetailsByUserName(ytUserName, password).get();
  97 + }
  98 + return authenticateByUsernameAndPassword(
  99 + ytDetailDTO, authentication, userPrincipal, username, password);
  100 + } else if (userPrincipal.getType() == UserPrincipal.Type.SMS_CODE) {
  101 + return ytUserDetailsByPhone(
  102 + authentication,
  103 + userPrincipal,
  104 + userPrincipal.getValue(),
  105 + (String) authentication.getCredentials());
  106 + } else {
  107 + String publicId = userPrincipal.getValue();
  108 + return authenticateByPublicId(userPrincipal, publicId);
  109 + }
  110 + }
95 111
96   - try {
  112 + private Authentication authenticateByUsernameAndPassword(
  113 + UserDetailsDTO ytDetailDTO,
  114 + Authentication authentication,
  115 + UserPrincipal userPrincipal,
  116 + String username,
  117 + String password) {
97 118
98   - UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId());
99   - if (userCredentials == null) {
100   - throw new UsernameNotFoundException("User credentials not found");
101   - }
  119 + // TODO 先验证sys_user账号密码是否正确,正确后,在账号后面加上后缀验证TB用户是否正确
  120 + Object principal = authentication.getPrincipal();
  121 + if (!(principal instanceof UserPrincipal)) {
  122 + throw new BadCredentialsException("Authentication Failed. Bad user principal.");
  123 + }
102 124
103   - try {
104   - systemSecurityService.validateUserCredentials(user.getTenantId(), userCredentials, username, password);
105   - } catch (LockedException e) {
106   - logLoginAction(user, authentication, ActionType.LOCKOUT, null);
107   - throw e;
108   - }
  125 + User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, username);
  126 + if (user == null) {
  127 + throw new UsernameNotFoundException("User not found: " + username);
  128 + }
109 129
110   - if (user.getAuthority() == null)
111   - throw new InsufficientAuthenticationException("User has no authority assigned");
  130 + try {
112 131
113   - SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), userPrincipal);
114   - logLoginAction(user, authentication, ActionType.LOGIN, null);
115   - return new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities());
116   - } catch (Exception e) {
117   - logLoginAction(user, authentication, ActionType.LOGIN, e);
118   - throw e;
119   - }
  132 + UserCredentials userCredentials =
  133 + userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId());
  134 + if (userCredentials == null) {
  135 + throw new UsernameNotFoundException("User credentials not found");
  136 + }
  137 +
  138 + try {
  139 + systemSecurityService.validateUserCredentials(
  140 + user.getTenantId(), userCredentials, username, password);
  141 + } catch (LockedException e) {
  142 + logLoginAction(user, authentication, ActionType.LOCKOUT, null);
  143 + throw e;
  144 + }
  145 +
  146 + if (user.getAuthority() == null)
  147 + throw new InsufficientAuthenticationException("User has no authority assigned");
  148 +
  149 + user.setUserDetailsDTO(ytDetailDTO);
  150 + SecurityUser securityUser =
  151 + new SecurityUser(user, userCredentials.isEnabled(), userPrincipal);
  152 + logLoginAction(user, authentication, ActionType.LOGIN, null);
  153 + return new UsernamePasswordAuthenticationToken(
  154 + securityUser, null, securityUser.getAuthorities());
  155 + } catch (Exception e) {
  156 + logLoginAction(user, authentication, ActionType.LOGIN, e);
  157 + throw e;
120 158 }
  159 + }
121 160
122   - private Authentication authenticateByPublicId(UserPrincipal userPrincipal, String publicId) {
123   - CustomerId customerId;
124   - try {
125   - customerId = new CustomerId(UUID.fromString(publicId));
126   - } catch (Exception e) {
127   - throw new BadCredentialsException("Authentication Failed. Public Id is not valid.");
128   - }
129   - Customer publicCustomer = customerService.findCustomerById(TenantId.SYS_TENANT_ID, customerId);
130   - if (publicCustomer == null) {
131   - throw new UsernameNotFoundException("Public entity not found: " + publicId);
132   - }
133   - if (!publicCustomer.isPublic()) {
134   - throw new BadCredentialsException("Authentication Failed. Public Id is not valid.");
135   - }
136   - User user = new User(new UserId(EntityId.NULL_UUID));
137   - user.setTenantId(publicCustomer.getTenantId());
138   - user.setCustomerId(publicCustomer.getId());
139   - user.setEmail(publicId);
140   - user.setAuthority(Authority.CUSTOMER_USER);
141   - user.setFirstName("Public");
142   - user.setLastName("Public");
143   -
144   - SecurityUser securityUser = new SecurityUser(user, true, userPrincipal);
145   -
146   - return new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities());
147   - }
148   -
149   - @Override
150   - public boolean supports(Class<?> authentication) {
151   - return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
152   - }
153   -
154   - private void logLoginAction(User user, Authentication authentication, ActionType actionType, Exception e) {
155   - String clientAddress = "Unknown";
156   - String browser = "Unknown";
157   - String os = "Unknown";
158   - String device = "Unknown";
159   - if (authentication != null && authentication.getDetails() != null) {
160   - if (authentication.getDetails() instanceof RestAuthenticationDetails) {
161   - RestAuthenticationDetails details = (RestAuthenticationDetails)authentication.getDetails();
162   - clientAddress = details.getClientAddress();
163   - if (details.getUserAgent() != null) {
164   - Client userAgent = details.getUserAgent();
165   - if (userAgent.userAgent != null) {
166   - browser = userAgent.userAgent.family;
167   - if (userAgent.userAgent.major != null) {
168   - browser += " " + userAgent.userAgent.major;
169   - if (userAgent.userAgent.minor != null) {
170   - browser += "." + userAgent.userAgent.minor;
171   - if (userAgent.userAgent.patch != null) {
172   - browser += "." + userAgent.userAgent.patch;
173   - }
174   - }
175   - }
176   - }
177   - if (userAgent.os != null) {
178   - os = userAgent.os.family;
179   - if (userAgent.os.major != null) {
180   - os += " " + userAgent.os.major;
181   - if (userAgent.os.minor != null) {
182   - os += "." + userAgent.os.minor;
183   - if (userAgent.os.patch != null) {
184   - os += "." + userAgent.os.patch;
185   - if (userAgent.os.patchMinor != null) {
186   - os += "." + userAgent.os.patchMinor;
187   - }
188   - }
189   - }
190   - }
191   - }
192   - if (userAgent.device != null) {
193   - device = userAgent.device.family;
194   - }
  161 + private Authentication authenticateByPublicId(UserPrincipal userPrincipal, String publicId) {
  162 + CustomerId customerId;
  163 + try {
  164 + customerId = new CustomerId(UUID.fromString(publicId));
  165 + } catch (Exception e) {
  166 + throw new BadCredentialsException("Authentication Failed. Public Id is not valid.");
  167 + }
  168 + Customer publicCustomer = customerService.findCustomerById(TenantId.SYS_TENANT_ID, customerId);
  169 + if (publicCustomer == null) {
  170 + throw new UsernameNotFoundException("Public entity not found: " + publicId);
  171 + }
  172 + if (!publicCustomer.isPublic()) {
  173 + throw new BadCredentialsException("Authentication Failed. Public Id is not valid.");
  174 + }
  175 + User user = new User(new UserId(EntityId.NULL_UUID));
  176 + user.setTenantId(publicCustomer.getTenantId());
  177 + user.setCustomerId(publicCustomer.getId());
  178 + user.setEmail(publicId);
  179 + user.setAuthority(Authority.CUSTOMER_USER);
  180 + user.setFirstName("Public");
  181 + user.setLastName("Public");
  182 +
  183 + SecurityUser securityUser = new SecurityUser(user, true, userPrincipal);
  184 +
  185 + return new UsernamePasswordAuthenticationToken(
  186 + securityUser, null, securityUser.getAuthorities());
  187 + }
  188 +
  189 + @Override
  190 + public boolean supports(Class<?> authentication) {
  191 + return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
  192 + }
  193 +
  194 + private void logLoginAction(
  195 + User user, Authentication authentication, ActionType actionType, Exception e) {
  196 + String clientAddress = "Unknown";
  197 + String browser = "Unknown";
  198 + String os = "Unknown";
  199 + String device = "Unknown";
  200 + if (authentication != null && authentication.getDetails() != null) {
  201 + if (authentication.getDetails() instanceof RestAuthenticationDetails) {
  202 + RestAuthenticationDetails details = (RestAuthenticationDetails) authentication.getDetails();
  203 + clientAddress = details.getClientAddress();
  204 + if (details.getUserAgent() != null) {
  205 + Client userAgent = details.getUserAgent();
  206 + if (userAgent.userAgent != null) {
  207 + browser = userAgent.userAgent.family;
  208 + if (userAgent.userAgent.major != null) {
  209 + browser += " " + userAgent.userAgent.major;
  210 + if (userAgent.userAgent.minor != null) {
  211 + browser += "." + userAgent.userAgent.minor;
  212 + if (userAgent.userAgent.patch != null) {
  213 + browser += "." + userAgent.userAgent.patch;
  214 + }
  215 + }
  216 + }
  217 + }
  218 + if (userAgent.os != null) {
  219 + os = userAgent.os.family;
  220 + if (userAgent.os.major != null) {
  221 + os += " " + userAgent.os.major;
  222 + if (userAgent.os.minor != null) {
  223 + os += "." + userAgent.os.minor;
  224 + if (userAgent.os.patch != null) {
  225 + os += "." + userAgent.os.patch;
  226 + if (userAgent.os.patchMinor != null) {
  227 + os += "." + userAgent.os.patchMinor;
  228 + }
195 229 }
  230 + }
196 231 }
  232 + }
  233 + if (userAgent.device != null) {
  234 + device = userAgent.device.family;
  235 + }
197 236 }
198   - auditLogService.logEntityAction(
199   - user.getTenantId(), user.getCustomerId(), user.getId(),
200   - user.getName(), user.getId(), null, actionType, e, clientAddress, browser, os, device);
  237 + }
  238 + }
  239 + auditLogService.logEntityAction(
  240 + user.getTenantId(),
  241 + user.getCustomerId(),
  242 + user.getId(),
  243 + user.getName(),
  244 + user.getId(),
  245 + null,
  246 + actionType,
  247 + e,
  248 + clientAddress,
  249 + browser,
  250 + os,
  251 + device);
  252 + }
  253 +
  254 + @Autowired private YtUserService ytUserService;
  255 + @Autowired private CacheUtils cacheUtils;
  256 + @Autowired private PasswordEncoder passwordEncoder;
  257 +
  258 + private Optional<UserDetailsDTO> ytUserDetailsByUserName(String username, String password) {
  259 + List<UserDetailsDTO> users = ytUserService.findUserDetailsByUsername(username);
  260 +
  261 + if (users.isEmpty()) {
  262 + throw new UsernameNotFoundException("User not found: " + username);
  263 + }
  264 + Optional<UserDetailsDTO> optionalUser =
  265 + users.stream()
  266 + .filter(user -> passwordEncoder.matches(password, user.getPassword()))
  267 + .findAny();
  268 + if (optionalUser.isEmpty()) {
  269 + throw new BadCredentialsException("Authentication Failed. Username or Password not valid.");
  270 + }
  271 + if (doValidate(optionalUser)) {
  272 + return optionalUser;
  273 + }
  274 + return Optional.empty();
  275 + }
  276 +
  277 + private Authentication ytUserDetailsByPhone(
  278 + Authentication authentication, UserPrincipal userPrincipal, String phoneNumber, String code) {
  279 + List<UserDetailsDTO> users = ytUserService.getUserByPhoneNumber(phoneNumber);
  280 + if (users.isEmpty()) {
  281 + throw new UsernameNotFoundException("phone number not found: " + phoneNumber);
  282 + }
  283 + String key =
  284 + MsgTemplatePurposeEnum.FOR_LOGIN.name()
  285 + + DEFAULT_DELIMITER
  286 + + MessageTypeEnum.PHONE_MESSAGE.name()
  287 + + DEFAULT_DELIMITER
  288 + + phoneNumber;
  289 +
  290 + boolean correct =
  291 + cacheUtils
  292 + .get(MOBILE_LOGIN_SMS_CODE, key)
  293 + .map(
  294 + o -> {
  295 + CodeTTL codeTTL = (CodeTTL) o;
  296 + if (System.currentTimeMillis() - codeTTL.getSendTs() < 5 * 60 * 1000) {
  297 + return Objects.equals(codeTTL.getCode(), code);
  298 + } else {
  299 + return false;
  300 + }
  301 + })
  302 + .orElse(false);
  303 + Optional<UserDetailsDTO> optionalUser;
  304 + if (!correct) {
  305 + optionalUser = Optional.empty();
  306 + } else {
  307 + optionalUser = Optional.of(users.get(0));
  308 + }
  309 + if (optionalUser.isEmpty()) {
  310 + throw new BadCredentialsException("验证码不正确");
  311 + }
  312 +
  313 + String tbEmail =
  314 + optionalUser.get().getUsername() + FastIotConstants.DEFAULT_EMAIL_SUFFIX_FOR_TB;
  315 + User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, tbEmail);
  316 + if (user == null) {
  317 + throw new UsernameNotFoundException("User not found: " + tbEmail);
  318 + }
  319 +
  320 + try {
  321 + if (user.getAuthority() == null)
  322 + throw new InsufficientAuthenticationException("User has no authority assigned");
  323 +
  324 + user.setUserDetailsDTO(optionalUser.get());
  325 + SecurityUser securityUser = new SecurityUser(user, true, userPrincipal);
  326 + logLoginAction(user, authentication, ActionType.LOGIN, null);
  327 + return new UsernamePasswordAuthenticationToken(
  328 + securityUser, null, securityUser.getAuthorities());
  329 + } catch (Exception e) {
  330 + logLoginAction(user, authentication, ActionType.LOGIN, e);
  331 + throw e;
  332 + }
  333 + }
  334 +
  335 + private boolean doValidate(Optional<UserDetailsDTO> optionalUser) {
  336 + UserDetailsDTO detailsDTO = optionalUser.get();
  337 + boolean tenantEnabled = detailsDTO.getTenant().isEnabled();
  338 + if (!tenantEnabled) {
  339 + throw new LockedException("tenant has been disabled");
  340 + }
  341 + Optional.ofNullable(detailsDTO.getTenant().getTenantExpireTime())
  342 + .ifPresent(
  343 + expireTime -> {
  344 + if (LocalDateTime.now().isAfter(expireTime)) {
  345 + throw new AccountExpiredException("tenant has expired");
  346 + }
  347 + });
  348 + Optional.ofNullable(detailsDTO.getAccountExpireTime())
  349 + .ifPresent(
  350 + expireTime -> {
  351 + if (LocalDateTime.now().isAfter(expireTime)) {
  352 + throw new AccountExpiredException("user account has expired");
  353 + }
  354 + });
  355 + boolean enabled = detailsDTO.isEnabled();
  356 + if (!enabled) {
  357 + throw new LockedException("account has been disabled");
201 358 }
  359 + return true;
  360 + }
202 361 }
... ...
... ... @@ -24,9 +24,9 @@ import org.springframework.security.web.WebAttributes;
24 24 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
25 25 import org.springframework.stereotype.Component;
26 26 import org.thingsboard.server.common.data.security.model.JwtToken;
27   -import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
28 27 import org.thingsboard.server.service.security.model.SecurityUser;
29 28 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
  29 +import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
30 30
31 31 import javax.servlet.ServletException;
32 32 import javax.servlet.http.HttpServletRequest;
... ...
... ... @@ -28,7 +28,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
28 28 import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
29 29 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
30 30 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
31   -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
32 31 import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException;
33 32 import org.thingsboard.server.service.security.model.UserPrincipal;
34 33
... ...
1 1 /**
2 2 * Copyright © 2016-2021 The Thingsboard Authors
3 3 *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
  4 + * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5 + * except in compliance with the License. You may obtain a copy of the License at
7 6 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  7 + * <p>http://www.apache.org/licenses/LICENSE-2.0
9 8 *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
  9 + * <p>Unless required by applicable law or agreed to in writing, software distributed under the
  10 + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  11 + * express or implied. See the License for the specific language governing permissions and
14 12 * limitations under the License.
15 13 */
16 14 package org.thingsboard.server.service.security.model;
17 15
  16 +import lombok.Getter;
  17 +import lombok.Setter;
18 18 import org.springframework.security.core.GrantedAuthority;
19 19 import org.springframework.security.core.authority.SimpleGrantedAuthority;
20 20 import org.thingsboard.server.common.data.User;
21 21 import org.thingsboard.server.common.data.id.UserId;
  22 +import org.thingsboard.server.common.data.yunteng.dto.UserDetailRoleDTO;
  23 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
22 24
  25 +import java.time.LocalDateTime;
23 26 import java.util.Collection;
  27 +import java.util.Optional;
  28 +import java.util.Set;
24 29 import java.util.stream.Collectors;
25 30 import java.util.stream.Stream;
26 31
27 32 public class SecurityUser extends User {
28 33
29   - private static final long serialVersionUID = -797397440703066079L;
  34 + private static final long serialVersionUID = -797397440703066079L;
30 35
31   - private Collection<GrantedAuthority> authorities;
32   - private boolean enabled;
33   - private UserPrincipal userPrincipal;
  36 + private Collection<GrantedAuthority> authorities;
  37 + private boolean enabled;
  38 + private UserPrincipal userPrincipal;
  39 + @Getter
  40 + private String currentTenantId;
  41 + @Getter
  42 + private String currentUserId;
  43 + @Getter @Setter private LocalDateTime userExpireTime;
  44 + @Getter @Setter private LocalDateTime tenantExpireTime;
  45 + @Getter @Setter private boolean sysadmin = false;
  46 + @Getter @Setter private boolean tenantAdmin = false;
  47 + @Getter @Setter private boolean platformAdmin = false;
  48 + @Getter @Setter private Set<String> roles;
34 49
35   - public SecurityUser() {
36   - super();
37   - }
  50 + public SecurityUser() {
  51 + super();
  52 + }
38 53
39   - public SecurityUser(UserId id) {
40   - super(id);
41   - }
  54 + public SecurityUser(UserId id) {
  55 + super(id);
  56 + }
42 57
43   - public SecurityUser(User user, boolean enabled, UserPrincipal userPrincipal) {
44   - super(user);
45   - this.enabled = enabled;
46   - this.userPrincipal = userPrincipal;
47   - }
  58 + public SecurityUser(User user, boolean enabled, UserPrincipal userPrincipal) {
  59 + super(user);
  60 + this.enabled = enabled;
  61 + this.userPrincipal = userPrincipal;
  62 + this.currentTenantId = user.getTenantId().getId().toString();
  63 + this.currentUserId = user.getUserDetailsDTO().getId();
  64 + Optional.ofNullable(user.getUserDetailsDTO().getRoles()).map(roleDTOS -> {
  65 + this.roles =
  66 + roleDTOS.stream()
  67 + .map(UserDetailRoleDTO::getRoleType)
  68 + .map(RoleEnum::name)
  69 + .collect(Collectors.toSet());
  70 + this.sysadmin =
  71 + this.roles.stream().anyMatch(role -> role.equals(RoleEnum.ROLE_SYS_ADMIN.name()));
  72 + this.tenantAdmin =
  73 + this.roles.stream().anyMatch(role -> role.equals(RoleEnum.ROLE_TENANT_ADMIN.name()));
  74 + this.platformAdmin =
  75 + this.roles.stream().anyMatch(role -> role.equals(RoleEnum.ROLE_PLATFORM_ADMIN.name()));
  76 + return roleDTOS;
  77 + });
48 78
49   - public Collection<GrantedAuthority> getAuthorities() {
50   - if (authorities == null) {
51   - authorities = Stream.of(SecurityUser.this.getAuthority())
52   - .map(authority -> new SimpleGrantedAuthority(authority.name()))
53   - .collect(Collectors.toList());
54   - }
55   - return authorities;
56   - }
  79 + }
57 80
58   - public boolean isEnabled() {
59   - return enabled;
  81 + public Collection<GrantedAuthority> getAuthorities() {
  82 + if (authorities == null) {
  83 + authorities =
  84 + Stream.of(SecurityUser.this.getAuthority())
  85 + .map(authority -> new SimpleGrantedAuthority(authority.name()))
  86 + .collect(Collectors.toList());
60 87 }
  88 + return authorities;
  89 + }
61 90
62   - public UserPrincipal getUserPrincipal() {
63   - return userPrincipal;
64   - }
  91 + public boolean isEnabled() {
  92 + return enabled;
  93 + }
65 94
66   - public void setEnabled(boolean enabled) {
67   - this.enabled = enabled;
68   - }
  95 + public UserPrincipal getUserPrincipal() {
  96 + return userPrincipal;
  97 + }
69 98
70   - public void setUserPrincipal(UserPrincipal userPrincipal) {
71   - this.userPrincipal = userPrincipal;
72   - }
  99 + public void setEnabled(boolean enabled) {
  100 + this.enabled = enabled;
  101 + }
73 102
  103 + public void setUserPrincipal(UserPrincipal userPrincipal) {
  104 + this.userPrincipal = userPrincipal;
  105 + }
74 106 }
... ...
... ... @@ -37,7 +37,8 @@ public class UserPrincipal implements Serializable {
37 37
38 38 public enum Type {
39 39 USER_NAME,
40   - PUBLIC_ID
  40 + PUBLIC_ID,
  41 + SMS_CODE
41 42 }
42 43
43 44 }
... ...
... ... @@ -15,10 +15,8 @@
15 15 */
16 16 package org.thingsboard.server.service.security.permission;
17 17
18   -import org.thingsboard.server.common.data.HasCustomerId;
19 18 import org.thingsboard.server.common.data.HasTenantId;
20 19 import org.thingsboard.server.common.data.id.EntityId;
21   -import org.thingsboard.server.common.data.id.TenantId;
22 20 import org.thingsboard.server.service.security.model.SecurityUser;
23 21
24 22 import java.util.Arrays;
... ...
... ... @@ -22,7 +22,6 @@ import io.jsonwebtoken.Claims;
22 22 import io.jsonwebtoken.Header;
23 23 import io.jsonwebtoken.Jwt;
24 24 import io.jsonwebtoken.Jwts;
25   -import lombok.Getter;
26 25 import lombok.extern.slf4j.Slf4j;
27 26 import org.apache.commons.lang3.RandomStringUtils;
28 27 import org.apache.commons.lang3.StringUtils;
... ...
... ... @@ -15,81 +15,27 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
18   -import com.fasterxml.jackson.core.type.TypeReference;
19   -import com.fasterxml.jackson.databind.JsonNode;
20   -import com.fasterxml.jackson.databind.ObjectMapper;
21   -import io.jsonwebtoken.Claims;
22   -import io.jsonwebtoken.Header;
23   -import io.jsonwebtoken.Jwt;
24   -import io.jsonwebtoken.Jwts;
25 18 import lombok.extern.slf4j.Slf4j;
26   -import org.apache.commons.lang3.StringUtils;
27   -import org.hamcrest.Matcher;
28   -import org.junit.After;
29 19 import org.junit.Assert;
30   -import org.junit.Before;
31   -import org.junit.Rule;
32   -import org.junit.rules.TestRule;
33   -import org.junit.rules.TestWatcher;
34   -import org.junit.runner.Description;
35 20 import org.junit.runner.RunWith;
36   -import org.springframework.beans.factory.annotation.Autowired;
37 21 import org.springframework.boot.test.context.SpringBootContextLoader;
38 22 import org.springframework.boot.test.context.SpringBootTest;
39 23 import org.springframework.boot.web.server.LocalServerPort;
40 24 import org.springframework.context.annotation.ComponentScan;
41 25 import org.springframework.context.annotation.Configuration;
42   -import org.springframework.http.HttpHeaders;
43   -import org.springframework.http.MediaType;
44   -import org.springframework.http.converter.HttpMessageConverter;
45   -import org.springframework.http.converter.StringHttpMessageConverter;
46   -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
47   -import org.springframework.mock.http.MockHttpInputMessage;
48   -import org.springframework.mock.http.MockHttpOutputMessage;
49 26 import org.springframework.test.annotation.DirtiesContext;
50 27 import org.springframework.test.context.ActiveProfiles;
51 28 import org.springframework.test.context.ContextConfiguration;
52 29 import org.springframework.test.context.junit4.SpringRunner;
53   -import org.springframework.test.web.servlet.MockMvc;
54   -import org.springframework.test.web.servlet.MvcResult;
55   -import org.springframework.test.web.servlet.ResultActions;
56   -import org.springframework.test.web.servlet.ResultMatcher;
57   -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
58   -import org.springframework.util.LinkedMultiValueMap;
59   -import org.springframework.util.MultiValueMap;
60   -import org.springframework.web.context.WebApplicationContext;
61   -import org.thingsboard.server.common.data.BaseData;
62   -import org.thingsboard.server.common.data.Customer;
63   -import org.thingsboard.server.common.data.Tenant;
64   -import org.thingsboard.server.common.data.User;
65   -import org.thingsboard.server.common.data.id.TenantId;
66   -import org.thingsboard.server.common.data.id.UUIDBased;
67   -import org.thingsboard.server.common.data.page.PageLink;
68   -import org.thingsboard.server.common.data.page.TimePageLink;
69   -import org.thingsboard.server.common.data.security.Authority;
70   -import org.thingsboard.server.config.ThingsboardSecurityConfiguration;
71   -import org.thingsboard.server.service.mail.TestMailService;
72   -import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest;
73   -import org.thingsboard.server.service.security.auth.rest.LoginRequest;
74 30
75   -import java.io.IOException;
76 31 import java.net.URI;
77 32 import java.net.URISyntaxException;
78   -import java.util.ArrayList;
79   -import java.util.Arrays;
80   -import java.util.Comparator;
81   -import java.util.List;
82 33
83 34 import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
84   -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
85 35 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
86 36 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
87 37 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
88   -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
89 38 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
90   -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
91   -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
92   -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
93 39
94 40 @ActiveProfiles("test")
95 41 @RunWith(SpringRunner.class)
... ...
application/src/test/java/org/thingsboard/server/controller/BaseYtAdminControllerTest.java renamed from application/src/test/java/org/thingsboard/server/controller/BaseAdminControllerTest.java
... ... @@ -24,7 +24,7 @@ import static org.hamcrest.Matchers.*;
24 24 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
25 25
26 26
27   -public abstract class BaseAdminControllerTest extends AbstractControllerTest {
  27 +public abstract class BaseYtAdminControllerTest extends AbstractControllerTest {
28 28
29 29 @Test
30 30 public void testFindAdminSettingsByKey() throws Exception {
... ...
application/src/test/java/org/thingsboard/server/controller/sql/YtAdminControllerSqlTest.java renamed from application/src/test/java/org/thingsboard/server/controller/sql/AdminControllerSqlTest.java
... ... @@ -15,12 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.controller.sql;
17 17
18   -import org.thingsboard.server.controller.BaseAdminControllerTest;
  18 +import org.thingsboard.server.controller.BaseYtAdminControllerTest;
19 19 import org.thingsboard.server.dao.service.DaoSqlTest;
20 20
21 21 /**
22 22 * Created by Valerii Sosliuk on 6/28/2017.
23 23 */
24 24 @DaoSqlTest
25   -public class AdminControllerSqlTest extends BaseAdminControllerTest {
  25 +public class YtAdminControllerSqlTest extends BaseYtAdminControllerTest {
26 26 }
... ...
... ... @@ -100,6 +100,78 @@
100 100 <groupId>io.swagger</groupId>
101 101 <artifactId>swagger-annotations</artifactId>
102 102 </dependency>
  103 + <dependency>
  104 + <groupId>org.springframework.boot</groupId>
  105 + <artifactId>spring-boot-autoconfigure</artifactId>
  106 + </dependency>
  107 + <dependency>
  108 + <groupId>org.springframework</groupId>
  109 + <artifactId>spring-context</artifactId>
  110 + </dependency>
  111 + <dependency>
  112 + <groupId>org.springframework</groupId>
  113 + <artifactId>spring-context-support</artifactId>
  114 + </dependency>
  115 + <dependency>
  116 + <groupId>org.springframework.data</groupId>
  117 + <artifactId>spring-data-redis</artifactId>
  118 + </dependency>
  119 +
  120 + <!--阿里短信SDK -->
  121 + <dependency>
  122 + <groupId>com.aliyun</groupId>
  123 + <artifactId>aliyun-java-sdk-core</artifactId>
  124 + <version>${aliyun.sdk.core}</version>
  125 + </dependency>
  126 + <dependency>
  127 + <groupId>com.aliyun</groupId>
  128 + <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
  129 + <version>${aliyun.sdk.dysmsapi}</version>
  130 + </dependency>
  131 + <!-- 邮件发送 -->
  132 + <dependency>
  133 + <groupId>com.sun.mail</groupId>
  134 + <artifactId>jakarta.mail</artifactId>
  135 + <version>${jakarta.mail.version}</version>
  136 + </dependency>
  137 +
  138 + <!--minio-->
  139 + <dependency>
  140 + <groupId>io.minio</groupId>
  141 + <artifactId>minio</artifactId>
  142 + <version>${io.minio.version}</version>
  143 + </dependency>
  144 + <!--alibaba easyExcel-->
  145 + <dependency>
  146 + <groupId>com.alibaba</groupId>
  147 + <artifactId>easyexcel</artifactId>
  148 + <version>${com.alibaba.easyexcel.version}</version>
  149 + </dependency>
  150 + <!-- aspectj -->
  151 + <dependency>
  152 + <groupId>org.aspectj</groupId>
  153 + <artifactId>aspectjweaver</artifactId>
  154 + <version>1.9.6</version>
  155 + <scope>runtime</scope>
  156 + </dependency>
  157 + <dependency>
  158 + <groupId>org.thingsboard.common</groupId>
  159 + <artifactId>util</artifactId>
  160 + </dependency>
  161 + <dependency>
  162 + <groupId>org.springframework</groupId>
  163 + <artifactId>spring-web</artifactId>
  164 + </dependency>
  165 +
  166 + <dependency>
  167 + <groupId>org.springframework.boot</groupId>
  168 + <artifactId>spring-boot-starter-web</artifactId>
  169 + </dependency>
  170 + <dependency>
  171 + <groupId>org.aspectj</groupId>
  172 + <artifactId>aspectjrt</artifactId>
  173 + <version>1.9.6</version>
  174 + </dependency>
103 175 </dependencies>
104 176
105 177 <build>
... ...
1 1 /**
2 2 * Copyright © 2016-2021 The Thingsboard Authors
3 3 *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
  4 + * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5 + * except in compliance with the License. You may obtain a copy of the License at
7 6 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  7 + * <p>http://www.apache.org/licenses/LICENSE-2.0
9 8 *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
  9 + * <p>Unless required by applicable law or agreed to in writing, software distributed under the
  10 + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  11 + * express or implied. See the License for the specific language governing permissions and
14 12 * limitations under the License.
15 13 */
16 14 package org.thingsboard.server.common.data;
... ... @@ -21,6 +19,8 @@ import com.fasterxml.jackson.databind.JsonNode;
21 19 import io.swagger.annotations.ApiModel;
22 20 import io.swagger.annotations.ApiModelProperty;
23 21 import lombok.EqualsAndHashCode;
  22 +import lombok.Getter;
  23 +import lombok.Setter;
24 24 import org.thingsboard.server.common.data.id.CustomerId;
25 25 import org.thingsboard.server.common.data.id.EntityId;
26 26 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -28,167 +28,202 @@ import org.thingsboard.server.common.data.id.UserId;
28 28 import org.thingsboard.server.common.data.security.Authority;
29 29 import org.thingsboard.server.common.data.validation.Length;
30 30 import org.thingsboard.server.common.data.validation.NoXss;
  31 +import org.thingsboard.server.common.data.yunteng.dto.UserDetailRoleDTO;
  32 +import org.thingsboard.server.common.data.yunteng.dto.UserDetailsDTO;
  33 +
  34 +import java.util.Set;
31 35
32 36 @ApiModel
33 37 @EqualsAndHashCode(callSuper = true)
34   -public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements HasName, HasTenantId, HasCustomerId {
35   -
36   - private static final long serialVersionUID = 8250339805336035966L;
37   -
38   - private TenantId tenantId;
39   - private CustomerId customerId;
40   - private String email;
41   - private Authority authority;
42   - @NoXss
43   - @Length(fieldName = "first name")
44   - private String firstName;
45   - @NoXss
46   - @Length(fieldName = "last name")
47   - private String lastName;
48   -
49   - public User() {
50   - super();
51   - }
52   -
53   - public User(UserId id) {
54   - super(id);
55   - }
56   -
57   - public User(User user) {
58   - super(user);
59   - this.tenantId = user.getTenantId();
60   - this.customerId = user.getCustomerId();
61   - this.email = user.getEmail();
62   - this.authority = user.getAuthority();
63   - this.firstName = user.getFirstName();
64   - this.lastName = user.getLastName();
65   - }
66   -
67   -
68   - @ApiModelProperty(position = 1, value = "JSON object with the User Id. " +
69   - "Specify this field to update the device. " +
70   - "Referencing non-existing User Id will cause error. " +
71   - "Omit this field to create new customer." )
72   - @Override
73   - public UserId getId() {
74   - return super.getId();
75   - }
76   -
77   - @ApiModelProperty(position = 2, value = "Timestamp of the user creation, in milliseconds", example = "1609459200000", readOnly = true)
78   - @Override
79   - public long getCreatedTime() {
80   - return super.getCreatedTime();
81   - }
82   -
83   - @ApiModelProperty(position = 3, value = "JSON object with the Tenant Id.", readOnly = true)
84   - public TenantId getTenantId() {
85   - return tenantId;
86   - }
87   -
88   - public void setTenantId(TenantId tenantId) {
89   - this.tenantId = tenantId;
90   - }
91   -
92   - @ApiModelProperty(position = 4, value = "JSON object with the Customer Id.", readOnly = true)
93   - public CustomerId getCustomerId() {
94   - return customerId;
95   - }
96   -
97   - public void setCustomerId(CustomerId customerId) {
98   - this.customerId = customerId;
99   - }
100   -
101   - @ApiModelProperty(position = 5, required = true, value = "Email of the user", example = "user@example.com")
102   - public String getEmail() {
103   - return email;
104   - }
105   -
106   - public void setEmail(String email) {
107   - this.email = email;
108   - }
109   -
110   - @ApiModelProperty(position = 6, readOnly = true, value = "Duplicates the email of the user, readonly", example = "user@example.com")
111   - @Override
112   - @JsonProperty(access = JsonProperty.Access.READ_ONLY)
113   - public String getName() {
114   - return email;
115   - }
116   -
117   - @ApiModelProperty(position = 7, required = true, value = "Authority", example = "SYS_ADMIN, TENANT_ADMIN or CUSTOMER_USER")
118   - public Authority getAuthority() {
119   - return authority;
120   - }
121   -
122   - public void setAuthority(Authority authority) {
123   - this.authority = authority;
124   - }
125   -
126   - @ApiModelProperty(position = 8, required = true, value = "First name of the user", example = "John")
127   - public String getFirstName() {
128   - return firstName;
129   - }
130   -
131   - public void setFirstName(String firstName) {
132   - this.firstName = firstName;
133   - }
134   -
135   - @ApiModelProperty(position = 9, required = true, value = "Last name of the user", example = "Doe")
136   - public String getLastName() {
137   - return lastName;
138   - }
139   -
140   - public void setLastName(String lastName) {
141   - this.lastName = lastName;
142   - }
143   -
144   - @ApiModelProperty(position = 10, value = "Additional parameters of the user", dataType = "com.fasterxml.jackson.databind.JsonNode")
145   - @Override
146   - public JsonNode getAdditionalInfo() {
147   - return super.getAdditionalInfo();
148   - }
149   -
150   - @Override
151   - public String getSearchText() {
152   - return getEmail();
153   - }
154   -
155   - @Override
156   - public String toString() {
157   - StringBuilder builder = new StringBuilder();
158   - builder.append("User [tenantId=");
159   - builder.append(tenantId);
160   - builder.append(", customerId=");
161   - builder.append(customerId);
162   - builder.append(", email=");
163   - builder.append(email);
164   - builder.append(", authority=");
165   - builder.append(authority);
166   - builder.append(", firstName=");
167   - builder.append(firstName);
168   - builder.append(", lastName=");
169   - builder.append(lastName);
170   - builder.append(", additionalInfo=");
171   - builder.append(getAdditionalInfo());
172   - builder.append(", createdTime=");
173   - builder.append(createdTime);
174   - builder.append(", id=");
175   - builder.append(id);
176   - builder.append("]");
177   - return builder.toString();
178   - }
179   -
180   - @JsonIgnore
181   - public boolean isSystemAdmin() {
182   - return tenantId == null || EntityId.NULL_UUID.equals(tenantId.getId());
183   - }
184   -
185   - @JsonIgnore
186   - public boolean isTenantAdmin() {
187   - return !isSystemAdmin() && (customerId == null || EntityId.NULL_UUID.equals(customerId.getId()));
188   - }
189   -
190   - @JsonIgnore
191   - public boolean isCustomerUser() {
192   - return !isSystemAdmin() && !isTenantAdmin();
193   - }
  38 +public class User extends SearchTextBasedWithAdditionalInfo<UserId>
  39 + implements HasName, HasTenantId, HasCustomerId {
  40 +
  41 + private static final long serialVersionUID = 8250339805336035966L;
  42 +
  43 + private TenantId tenantId;
  44 + private CustomerId customerId;
  45 + private String email;
  46 + private Authority authority;
  47 +
  48 + @NoXss
  49 + @Length(fieldName = "first name")
  50 + private String firstName;
  51 +
  52 + @NoXss
  53 + @Length(fieldName = "last name")
  54 + private String lastName;
  55 + /** 平台的用户详情 */
  56 + @Getter @Setter private UserDetailsDTO userDetailsDTO;
  57 +
  58 + public User() {
  59 + super();
  60 + }
  61 +
  62 + public User(UserId id) {
  63 + super(id);
  64 + }
  65 +
  66 + public User(User user) {
  67 + super(user);
  68 + this.tenantId = user.getTenantId();
  69 + this.customerId = user.getCustomerId();
  70 + this.email = user.getEmail();
  71 + this.authority = user.getAuthority();
  72 + this.firstName = user.getFirstName();
  73 + this.lastName = user.getLastName();
  74 + }
  75 +
  76 + @ApiModelProperty(
  77 + position = 1,
  78 + value =
  79 + "JSON object with the User Id. "
  80 + + "Specify this field to update the device. "
  81 + + "Referencing non-existing User Id will cause error. "
  82 + + "Omit this field to create new customer.")
  83 + @Override
  84 + public UserId getId() {
  85 + return super.getId();
  86 + }
  87 +
  88 + @ApiModelProperty(
  89 + position = 2,
  90 + value = "Timestamp of the user creation, in milliseconds",
  91 + example = "1609459200000",
  92 + readOnly = true)
  93 + @Override
  94 + public long getCreatedTime() {
  95 + return super.getCreatedTime();
  96 + }
  97 +
  98 + @ApiModelProperty(position = 3, value = "JSON object with the Tenant Id.", readOnly = true)
  99 + public TenantId getTenantId() {
  100 + return tenantId;
  101 + }
  102 +
  103 + public void setTenantId(TenantId tenantId) {
  104 + this.tenantId = tenantId;
  105 + }
  106 +
  107 + @ApiModelProperty(position = 4, value = "JSON object with the Customer Id.", readOnly = true)
  108 + public CustomerId getCustomerId() {
  109 + return customerId;
  110 + }
  111 +
  112 + public void setCustomerId(CustomerId customerId) {
  113 + this.customerId = customerId;
  114 + }
  115 +
  116 + @ApiModelProperty(
  117 + position = 5,
  118 + required = true,
  119 + value = "Email of the user",
  120 + example = "user@example.com")
  121 + public String getEmail() {
  122 + return email;
  123 + }
  124 +
  125 + public void setEmail(String email) {
  126 + this.email = email;
  127 + }
  128 +
  129 + @ApiModelProperty(
  130 + position = 6,
  131 + readOnly = true,
  132 + value = "Duplicates the email of the user, readonly",
  133 + example = "user@example.com")
  134 + @Override
  135 + @JsonProperty(access = JsonProperty.Access.READ_ONLY)
  136 + public String getName() {
  137 + return email;
  138 + }
  139 +
  140 + @ApiModelProperty(
  141 + position = 7,
  142 + required = true,
  143 + value = "Authority",
  144 + example = "SYS_ADMIN, TENANT_ADMIN or CUSTOMER_USER")
  145 + public Authority getAuthority() {
  146 + return authority;
  147 + }
  148 +
  149 + public void setAuthority(Authority authority) {
  150 + this.authority = authority;
  151 + }
  152 +
  153 + @ApiModelProperty(
  154 + position = 8,
  155 + required = true,
  156 + value = "First name of the user",
  157 + example = "John")
  158 + public String getFirstName() {
  159 + return firstName;
  160 + }
  161 +
  162 + public void setFirstName(String firstName) {
  163 + this.firstName = firstName;
  164 + }
  165 +
  166 + @ApiModelProperty(position = 9, required = true, value = "Last name of the user", example = "Doe")
  167 + public String getLastName() {
  168 + return lastName;
  169 + }
  170 +
  171 + public void setLastName(String lastName) {
  172 + this.lastName = lastName;
  173 + }
  174 +
  175 + @ApiModelProperty(
  176 + position = 10,
  177 + value = "Additional parameters of the user",
  178 + dataType = "com.fasterxml.jackson.databind.JsonNode")
  179 + @Override
  180 + public JsonNode getAdditionalInfo() {
  181 + return super.getAdditionalInfo();
  182 + }
  183 +
  184 + @Override
  185 + public String getSearchText() {
  186 + return getEmail();
  187 + }
  188 +
  189 + @Override
  190 + public String toString() {
  191 + StringBuilder builder = new StringBuilder();
  192 + builder.append("User [tenantId=");
  193 + builder.append(tenantId);
  194 + builder.append(", customerId=");
  195 + builder.append(customerId);
  196 + builder.append(", email=");
  197 + builder.append(email);
  198 + builder.append(", authority=");
  199 + builder.append(authority);
  200 + builder.append(", firstName=");
  201 + builder.append(firstName);
  202 + builder.append(", lastName=");
  203 + builder.append(lastName);
  204 + builder.append(", additionalInfo=");
  205 + builder.append(getAdditionalInfo());
  206 + builder.append(", createdTime=");
  207 + builder.append(createdTime);
  208 + builder.append(", id=");
  209 + builder.append(id);
  210 + builder.append("]");
  211 + return builder.toString();
  212 + }
  213 +
  214 + @JsonIgnore
  215 + public boolean isSystemAdmin() {
  216 + return tenantId == null || EntityId.NULL_UUID.equals(tenantId.getId());
  217 + }
  218 +
  219 + @JsonIgnore
  220 + public boolean isTenantAdmin() {
  221 + return !isSystemAdmin()
  222 + && (customerId == null || EntityId.NULL_UUID.equals(customerId.getId()));
  223 + }
  224 +
  225 + @JsonIgnore
  226 + public boolean isCustomerUser() {
  227 + return !isSystemAdmin() && !isTenantAdmin();
  228 + }
194 229 }
... ...
  1 +package org.thingsboard.server.common.data.yunteng.common;
  2 +
  3 +public interface AddGroup {
  4 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.common;
  2 +
  3 +import org.thingsboard.server.common.data.yunteng.dto.SysDictItemDTO;
  4 +
  5 +public interface CommonService {
  6 + /**
  7 + * 通过dict表的Code和dictItem的codeText查询字典表的值
  8 + *
  9 + * @param dictCode 字典表Code
  10 + * @param codeValue 字典Item表文本值
  11 + * @return 返回字典Item表
  12 + */
  13 + SysDictItemDTO getDictValueByCodeAndText(String dictCode, String codeValue);
  14 +
  15 + /**
  16 + * 生成DeviceToken
  17 + * @return 返回DeviceToken
  18 + */
  19 + String generateDeviceToken(String tenantId);
  20 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.common;
  2 +
  3 +public interface DeleteGroup {
  4 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.common;
  2 +
  3 +public interface UpdateGroup {
  4 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.common.aspect;
  2 +
  3 +
  4 +import com.fasterxml.jackson.databind.JsonNode;
  5 +import com.fasterxml.jackson.databind.node.ObjectNode;
  6 +import lombok.RequiredArgsConstructor;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.apache.commons.lang3.StringUtils;
  9 +import org.aspectj.lang.ProceedingJoinPoint;
  10 +import org.aspectj.lang.annotation.Around;
  11 +import org.aspectj.lang.annotation.Aspect;
  12 +import org.aspectj.lang.annotation.Pointcut;
  13 +import org.springframework.stereotype.Component;
  14 +import org.thingsboard.common.util.JacksonUtil;
  15 +import org.thingsboard.server.common.data.yunteng.common.CommonService;
  16 +import org.thingsboard.server.common.data.yunteng.common.aspect.annotation.AutoDict;
  17 +import org.thingsboard.server.common.data.yunteng.dto.SysDictItemDTO;
  18 +import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
  19 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  20 +import org.thingsboard.server.common.data.yunteng.utils.tools.ResponseResult;
  21 +
  22 +import java.lang.reflect.Field;
  23 +import java.time.LocalDateTime;
  24 +import java.time.format.DateTimeFormatter;
  25 +import java.util.ArrayList;
  26 +import java.util.List;
  27 +
  28 +@Aspect
  29 +@Component
  30 +@Slf4j
  31 +@RequiredArgsConstructor
  32 +public class SysDictAspect {
  33 +
  34 + private final CommonService commonService;
  35 +
  36 + /** 表对应字段加上_dictText即可显示出文本 */
  37 + private static final String DICT_TEXT_SUFFIX = "DictText";
  38 +
  39 + /** 定义切入点 */
  40 + @Pointcut("execution(* com.codeez..*.*Controller.*(..))")
  41 + public void exudeService() {}
  42 +
  43 + /**
  44 + * 执行环绕通知
  45 + *
  46 + * @param joinPoint 切面
  47 + * @return 返回类型: Object
  48 + */
  49 + @Around("exudeService()")
  50 + public Object aroundAdvise(ProceedingJoinPoint joinPoint) throws Throwable {
  51 + // 执行切点环绕通知,获取执行方法的返回值
  52 + Object returnObject = joinPoint.proceed();
  53 + return parseDictValue(returnObject);
  54 + }
  55 +
  56 + /**
  57 + * 解析数据字典值
  58 + *
  59 + * @param returnObject 数据字典Code对应的值
  60 + */
  61 + private Object parseDictValue(Object returnObject) throws IllegalAccessException {
  62 + if (returnObject instanceof ResponseResult) {
  63 + Object object = ((ResponseResult<?>) returnObject).getData();
  64 + if(null != object){
  65 + ObjectNode objectNode = getObjectNode(object, ((ResponseResult) returnObject).getData());
  66 + if(null == objectNode){
  67 + return returnObject;
  68 + }
  69 + returnObject = ResponseResult.success(objectNode);
  70 + }
  71 + }
  72 + if (returnObject instanceof PageData) {
  73 + Object object = returnObject;
  74 + List<ObjectNode> list = new ArrayList<>();
  75 + for (Object obj : ((PageData<?>) object).getItems()) {
  76 + ObjectNode objectNode = getObjectNode(obj, obj);
  77 + if(null == objectNode){
  78 + return returnObject;
  79 + }
  80 + list.add(objectNode);
  81 + }
  82 + returnObject =new PageData<>(list, ((PageData<?>) object).getTotal());
  83 + }
  84 + return returnObject;
  85 + }
  86 +
  87 + /**
  88 + * 通过dict表的Code和dictItem的codeText查询字典表的值
  89 + *
  90 + * @param code dict表的Code
  91 + * @param codeText dictItem的codeText
  92 + * @return 返回Item的值
  93 + */
  94 + private String getDictText(String code, Object codeText) {
  95 + SysDictItemDTO sysDictItemDTO =
  96 + commonService.getDictValueByCodeAndText(code, codeText.toString());
  97 + return sysDictItemDTO != null ? sysDictItemDTO.getItemText() : null;
  98 + }
  99 +
  100 + /**
  101 + * 获取添加字段后的ObjectNode
  102 + *
  103 + * @param object 对象
  104 + * @param sourceObject 源对象
  105 + * @return 添加字段后的ObjectNode
  106 + */
  107 + private ObjectNode getObjectNode(Object object, Object sourceObject)
  108 + throws IllegalAccessException {
  109 + ObjectNode objectNode = null;
  110 + for (Field field : ReflectUtils.getAllDeclaredFields(object.getClass())) {
  111 + // 忽略修饰符访问检查
  112 + field.setAccessible(true);
  113 + if (field.getAnnotation(AutoDict.class) != null) {
  114 + String dictCode = field.getAnnotation(AutoDict.class).dictCode();
  115 + // 如果dictCode为空字符串,则循环下一个
  116 + if (StringUtils.isEmpty(dictCode)) {
  117 + log.debug("dictCode为空字符串的字段为{}", field.getName());
  118 + continue;
  119 + }
  120 + Object codeText = field.get(object);
  121 + if (null != codeText) {
  122 + String textValue = getDictText(dictCode, codeText);
  123 + JsonNode jsonNode = JacksonUtil.toJsonNode(JacksonUtil.toString(sourceObject));
  124 + if(null == objectNode){
  125 + objectNode = (ObjectNode) jsonNode;
  126 + }
  127 + objectNode.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
  128 + }
  129 + }
  130 + if(field.getType().getName().equals("java.time.LocalDateTime")){
  131 + Object content = field.get(object);
  132 + if(null != content && null !=objectNode){
  133 + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  134 + objectNode.put(field.getName(),fmt.format((LocalDateTime)content));
  135 + }
  136 + }
  137 + }
  138 + return objectNode;
  139 + }
  140 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.common.aspect.annotation;
  2 +
  3 +import java.lang.annotation.*;
  4 +
  5 +/**
  6 + * 字典注解
  7 + */
  8 +@Target(ElementType.FIELD)
  9 +@Retention(RetentionPolicy.RUNTIME)
  10 +@Documented
  11 +public @interface AutoDict {
  12 + /**
  13 + * 字典Code
  14 + * @return 返回类型 String
  15 + */
  16 + String dictCode();
  17 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.email;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class EmailConfiguration {
  7 +
  8 + /** 配置服务器 */
  9 + private String host;
  10 +
  11 + /** 配置端口 */
  12 + private Integer port;
  13 +
  14 + /** 配置用户名 */
  15 + private String username;
  16 +
  17 + /** 配置密码 */
  18 + private String password;
  19 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  5 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  6 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  7 +
  8 +@Slf4j
  9 +public abstract class AbstractSmsSender implements SmsSender {
  10 +
  11 + protected void validatePhoneNumber(String phoneNumber) {
  12 + phoneNumber = phoneNumber.trim();
  13 + if (!FastIotConstants.CHINA_MOBILE_PATTERN.matcher(phoneNumber).matches()) {
  14 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  15 + }
  16 + }
  17 +}
\ No newline at end of file
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms;
  2 +import com.fasterxml.jackson.annotation.JsonIgnore;
  3 +import com.fasterxml.jackson.annotation.JsonSubTypes;
  4 +import com.fasterxml.jackson.annotation.JsonTypeInfo;
  5 +import org.thingsboard.server.common.data.yunteng.config.sms.ali.AliSmsProviderConfiguration;
  6 +import org.thingsboard.server.common.data.yunteng.config.sms.tencent.TencentSmsProviderConfiguration;
  7 +import org.thingsboard.server.common.data.yunteng.enums.SmsProviderTypeEnum;
  8 +
  9 +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
  10 +@JsonSubTypes({
  11 + @JsonSubTypes.Type(value = AliSmsProviderConfiguration.class, name = "ALI_CLOUD"),
  12 + @JsonSubTypes.Type(value = TencentSmsProviderConfiguration.class, name = "TENCENT_CLOUD")
  13 +})
  14 +public interface SmsProviderConfiguration {
  15 +
  16 + @JsonIgnore
  17 + SmsProviderTypeEnum getType();
  18 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms;
  2 +
  3 +import java.util.LinkedHashMap;
  4 +
  5 +public interface SmsSender {
  6 + String sendSms(String phone, String templateCode, LinkedHashMap<String,String> param,String signName);
  7 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms;
  2 +
  3 +public interface SmsSenderFactory {
  4 + SmsSender createSmsSender(SmsProviderConfiguration config);
  5 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms;
  2 +
  3 +import org.springframework.stereotype.Component;
  4 +import org.thingsboard.server.common.data.yunteng.config.sms.ali.AliSmsProviderConfiguration;
  5 +import org.thingsboard.server.common.data.yunteng.config.sms.ali.AliSmsSender;
  6 +import org.thingsboard.server.common.data.yunteng.config.sms.tencent.TencentSmsProviderConfiguration;
  7 +import org.thingsboard.server.common.data.yunteng.config.sms.tencent.TencentSmsSender;
  8 +
  9 +@Component
  10 +public class YtDefaultSmsSenderFactory implements SmsSenderFactory {
  11 + @Override
  12 + public SmsSender createSmsSender(
  13 + SmsProviderConfiguration config) {
  14 + switch (config.getType()) {
  15 + case ALI_CLOUD:
  16 + return new AliSmsSender(
  17 + (AliSmsProviderConfiguration) config);
  18 + case TENCENT_CLOUD:
  19 + return new TencentSmsSender(
  20 + (TencentSmsProviderConfiguration) config);
  21 + default:
  22 + throw new RuntimeException("Unknown SMS provider type " + config.getType());
  23 + }
  24 + }
  25 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms.ali;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.config.sms.SmsProviderConfiguration;
  5 +import org.thingsboard.server.common.data.yunteng.enums.SmsProviderTypeEnum;
  6 +
  7 +@Data
  8 +public class AliSmsProviderConfiguration implements SmsProviderConfiguration {
  9 +
  10 + /** 阿里云AccessKeyId */
  11 + private String accessKeyId;
  12 +
  13 + /** 阿里云AccessKeySecret */
  14 + private String accessKeySecret;
  15 +
  16 + @Override
  17 + public SmsProviderTypeEnum getType() {
  18 + return SmsProviderTypeEnum.ALI_CLOUD;
  19 + }
  20 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms.ali;
  2 +
  3 +import com.aliyuncs.DefaultAcsClient;
  4 +import com.aliyuncs.IAcsClient;
  5 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
  6 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
  7 +import com.aliyuncs.exceptions.ClientException;
  8 +import com.aliyuncs.http.MethodType;
  9 +import com.aliyuncs.profile.DefaultProfile;
  10 +import com.aliyuncs.profile.IClientProfile;
  11 +import lombok.Data;
  12 +import lombok.extern.slf4j.Slf4j;
  13 +import org.apache.commons.lang3.StringUtils;
  14 +import org.thingsboard.common.util.JacksonUtil;
  15 +import org.thingsboard.server.common.data.yunteng.config.sms.AbstractSmsSender;
  16 +import org.thingsboard.server.common.data.yunteng.core.exception.FastIotException;
  17 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  18 +import org.thingsboard.server.common.data.yunteng.enums.ResponseCodeEnum;
  19 +
  20 +import java.util.LinkedHashMap;
  21 +
  22 +@Slf4j
  23 +public class AliSmsSender extends AbstractSmsSender {
  24 +
  25 + /** 阿里云短信参数配置 */
  26 + private final AliSmsProviderConfiguration config;
  27 +
  28 + private IClientProfile profile;
  29 +
  30 + public AliSmsSender(AliSmsProviderConfiguration config) {
  31 + if (StringUtils.isEmpty(config.getAccessKeyId())
  32 + || StringUtils.isEmpty(config.getAccessKeyId())) {
  33 + throw new FastIotException(ErrorMessage.INVALID_PARAMETER);
  34 + }
  35 + this.config = config;
  36 + initProfile();
  37 + }
  38 +
  39 + /** 使用AK&SK初始化账号Client */
  40 + private void initProfile() {
  41 + String endpoint = "dysmsapi.aliyuncs.com";
  42 + String product = "Dysmsapi";
  43 + String regionId = "cn-shanghai";
  44 + profile =
  45 + DefaultProfile.getProfile(regionId, config.getAccessKeyId(), config.getAccessKeySecret());
  46 + DefaultProfile.addEndpoint(regionId, product, endpoint);
  47 + }
  48 +
  49 + @Override
  50 + public String sendSms(
  51 + String phone, String templateCode, LinkedHashMap<String, String> param, String signName) {
  52 + validatePhoneNumber(phone);
  53 + IAcsClient client = new DefaultAcsClient(profile);
  54 + SendSmsRequest request = new SendSmsRequest();
  55 + request.setSysMethod(MethodType.POST);
  56 + request.setPhoneNumbers(phone);
  57 + request.setSignName(signName);
  58 + request.setTemplateCode(templateCode);
  59 + // 有参数的时候才处理
  60 + if (!param.isEmpty()) {
  61 + request.setTemplateParam(JacksonUtil.toString(param));
  62 + }
  63 + try {
  64 + SendSmsResponse response = client.getAcsResponse(request);
  65 + return response.getCode().equalsIgnoreCase(ResponseCodeEnum.OK.name())
  66 + ? ResponseCodeEnum.SUCCESS.name()
  67 + : response.getMessage();
  68 + } catch (ClientException e) {
  69 + e.printStackTrace();
  70 + return e.getMessage();
  71 + }
  72 + }
  73 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms.tencent;
  2 +
  3 +
  4 +import lombok.Data;
  5 +import org.thingsboard.server.common.data.yunteng.config.sms.SmsProviderConfiguration;
  6 +import org.thingsboard.server.common.data.yunteng.enums.SmsProviderTypeEnum;
  7 +
  8 +@Data
  9 +public class TencentSmsProviderConfiguration implements SmsProviderConfiguration {
  10 +
  11 + /** 腾讯云AppId */
  12 + private String appId;
  13 +
  14 + /** 腾讯云appKey */
  15 + private String appKey;
  16 +
  17 + @Override
  18 + public SmsProviderTypeEnum getType() {
  19 + return SmsProviderTypeEnum.TENCENT_CLOUD;
  20 + }
  21 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.config.sms.tencent;
  2 +
  3 +
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.thingsboard.server.common.data.yunteng.config.sms.AbstractSmsSender;
  6 +
  7 +import java.util.LinkedHashMap;
  8 +
  9 +@Slf4j
  10 +public class TencentSmsSender extends AbstractSmsSender {
  11 +
  12 + public TencentSmsSender(TencentSmsProviderConfiguration config) {}
  13 +
  14 + @Override
  15 + public String sendSms(
  16 + String phone, String templateCode, LinkedHashMap<String, String> param, String signName) {
  17 + return "";
  18 + }
  19 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.constant;
  2 +
  3 +import java.util.regex.Pattern;
  4 +
  5 +public interface FastIotConstants {
  6 +
  7 + class DefaultOrder {
  8 + public static final String CREATE_TIME="create_time";
  9 + }
  10 +
  11 + String MOBILE =
  12 + "^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$";
  13 + String EMAIL = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$";
  14 + Pattern EMAIL_PATTERN = Pattern.compile(EMAIL, Pattern.CASE_INSENSITIVE);
  15 + Pattern CHINA_MOBILE_PATTERN = Pattern.compile(MOBILE);
  16 +
  17 + class ConfigJSONKey {
  18 + public static final String BASE_URL = "baseUrl";
  19 + }
  20 +
  21 + String DEFAULT_DELIMITER = "#";
  22 +
  23 + class StateValue {
  24 + /** 禁用 */
  25 + public static final int DISABLE = 0;
  26 + /** 启用 */
  27 + public static final int ENABLE = 1;
  28 +
  29 + /** 删除成功 */
  30 + public static final String DELETE_SUCCESS = "删除成功";
  31 +
  32 + /** 删除失败 */
  33 + public static final String DELETE_FAILED = "删除成功";
  34 + }
  35 +
  36 + class LevelValue {
  37 + /** 超级管理员 */
  38 + public static final int IS_ADMIN=0;
  39 +
  40 + /** 系统平台其他管理员 */
  41 + public static final int IS_OTHER_ADMIN = 1;
  42 +
  43 + /** 租户管理员 */
  44 + public static final int IS_TENANT_ADMIN = 2;
  45 +
  46 + /** 普通用户 */
  47 + public static final int IS_NORMAL = 3;
  48 + }
  49 +
  50 + interface CacheConfigKey {
  51 + String CACHE_CONFIG_KEY = "FAST_IOT_CACHE";
  52 + String USER_PERMISSION_PREFIX = "user_permission_for_";
  53 + String MOBILE_LOGIN_SMS_CODE = "mobile_login_sms_code";
  54 + String DEFAULT_RULE_CHAIN = "default_rule_chain";
  55 + }
  56 +
  57 + String DEFAULT_EMAIL_SUFFIX_FOR_TB ="@yunteng.com";
  58 +
  59 + interface TBCacheConfig {
  60 + String TB_CACHE_CONFIG_KEY = "TB_CONNECT_CACHE";
  61 + String EXISTING_TENANT = "EXISTING_TENANT";
  62 + }
  63 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.constant;
  2 +
  3 +public final class ModelConstants {
  4 + public static class Table {
  5 + /** 系统用户表 */
  6 + public static final String USER_TABLE_NAME = "sys_user";
  7 + /** 租户表 */
  8 + public static final String TENANT_TABLE_NAME = "sys_tenant";
  9 + /** 租户菜单表 */
  10 + public static final String TENANT_MENU_TABLE_NAME = "sys_tenant_menu";
  11 + /** 租户角色表 */
  12 + public static final String TENANT_ROLE_TABLE_NAME = "sys_tenant_role";
  13 + /** 菜单表 */
  14 + public static final String MENU_TABLE_NAME = "sys_menu";
  15 + /** 角色表 */
  16 + public static final String ROLE_TABLE_NAME = "sys_role";
  17 + /** 用户角色关系表 */
  18 + public static final String USER_ROLE_TABLE_NAME = "sys_user_role";
  19 + /** 系统用户设置表 */
  20 + public static final String ADMIN_SETTING_TABLE_NAME = "sys_admin_setting";
  21 + /** 字典表 */
  22 + public static final String DICT_TABLE_NAME = "sys_dict";
  23 + /** 字典值表 */
  24 + public static final String DICT_ITEM_TABLE_NAME = "sys_dict_item";
  25 + /** 消息字典表 */
  26 + public static final String MESSAGE_CONFIG_TABLE_NAME = "message_config";
  27 + /** 消息模板表 */
  28 + public static final String MESSAGE_TEMPLATE_TABLE_NAME = "message_template";
  29 + /** 短信发送记录表 */
  30 + public static final String SMS_LOG_TABLE_NAME = "sms_log";
  31 + /** 邮件发送记录表 */
  32 + public static final String MAIL_LOG_TABLE_NAME = "mail_log";
  33 + /** 限流表 */
  34 + public static final String RATE_LIMIT_TABLE_NAME = "sys_rate_limit";
  35 + /** 系统部门表 */
  36 + public static final String DEPT_TABLE_NAME = "sys_dept";
  37 + /** 组织表 */
  38 + public static final String IOTFS_ORGANIZATION_TABLE_NAME = "iotfs_organization";
  39 + /** 用户与组织映射表 */
  40 + public static final String IOTFS_USER_ORGANIZATION_MAPPING_TABLE_NAME = "iotfs_user_organization_mapping";
  41 + /** 设备表 */
  42 + public static final String IOTFS_DEVICE_TABLE_NAME = "iotfs_device";
  43 + /** 设备配置表 */
  44 + public static final String IOTFS_DEVICE_PROFILE_TABLE_NAME = "iotfs_device_profile";
  45 + /** 设备类型表 */
  46 + public static final String IOTFS_DEVICE_TYPE_TABLE_NAME = "iotfs_device_type";
  47 + /** 告警配置表 */
  48 + public static final String IOTFS_ALARM_PROFILE_TABLE_NAME = "iotfs_alarm_profile";
  49 + /** 告警联系人 */
  50 + public static final String IOTFS_ALARM_CONTACT_TABLE_NAME = "iotfs_alarm_contact";
  51 + }
  52 +
  53 + public static class TableFields {
  54 + public static final String TENANT_ID = "tenant_id";
  55 + }
  56 +
  57 + public static class TablePropertyMapping {
  58 + public static final String ID = "id";
  59 + public static final String CREATE_TIME = "createTime";
  60 + public static final String UPDATE_TIME = "updateTime";
  61 + public static final String CREATOR = "creator";
  62 + public static final String UPDATER = "updater";
  63 + public static final String UPDATE = "update";
  64 + public static final String TENANT_CODE = "tenantCode";
  65 + public static final String PASSWORD = "password";
  66 + public static final String ACTIVATE_TOKEN = "activateToken";
  67 + public static final String TB_DEVICE_ID = "tbDeviceId";
  68 + public static final String DEVICE_STATE = "deviceState";
  69 + public static final String ACTIVE_TIME = "activeTime";
  70 + }
  71 +
  72 + public static class AdminSettingConfigKey {
  73 + public static final String GENERAL_SETTING = "general";
  74 + }
  75 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.constant;
  2 +
  3 +public class QueryConstant {
  4 + public static final String PAGE_SIZE = "pageSize";
  5 + public static final String PAGE = "page";
  6 + public static final String ORDER_FILED = "orderFiled";
  7 + public static final String ORDER_TYPE = "orderType";
  8 + public static final String CREATE_TIME="createTime";
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.constant;
  2 +
  3 +public final class SecurityConstant {
  4 + public static final String ROLE="role";
  5 + public static final String USER_ID="userId";
  6 + public static final String USER_NAME="username";
  7 + public static final String DISPLAY_NAME="displayName";
  8 + public static final String TENANT_CODE ="tenantCode";
  9 + public static final String TENANT_NAME="tenantName";
  10 + public static final String JWT_TOKEN_HEADER_PARAM="X-Authorization";
  11 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core;
  2 +
  3 +public enum RequestMethod {
  4 + GET,
  5 + HEAD,
  6 + POST,
  7 + PUT,
  8 + PATCH,
  9 + DELETE,
  10 + OPTIONS,
  11 + TRACE
  12 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +import org.springframework.util.Assert;
  7 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  8 +
  9 +import java.io.Serializable;
  10 +
  11 +@Data
  12 +@AllArgsConstructor
  13 +@NoArgsConstructor
  14 +public class Result implements Serializable {
  15 + private static final long serialVersionUID = -7460365055472356522L;
  16 + private String msg = "success";
  17 + private int code = -1;
  18 + private Object data;
  19 +
  20 + public static Result ok(Object data) {
  21 + return new Result("success", 0, data);
  22 + }
  23 +
  24 + public static Result error() {
  25 + return error(ErrorMessage.OPERATION_FAILED.getCode(), ErrorMessage.OPERATION_FAILED);
  26 + }
  27 +
  28 + public static Result error(ErrorMessage ntlErrorMessage) {
  29 + return error(ntlErrorMessage.getCode(), ntlErrorMessage);
  30 + }
  31 +
  32 + public static Result error(int code, ErrorMessage ntlErrorMessage) {
  33 + Assert.isTrue(code != 0, "error code should not be zero in error response!");
  34 + return new Result(ntlErrorMessage.getMessage(), code, null);
  35 + }
  36 +
  37 + public static Result error(String msg) {
  38 + return new Result(msg, -1, null);
  39 + }
  40 +
  41 + public static Result error(int code, String msg) {
  42 + Assert.isTrue(code != 0, "error code should not be zero in error response!");
  43 + return new Result(msg, code, null);
  44 + }
  45 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.cache;
  2 +
  3 +import org.springframework.cache.CacheManager;
  4 +import org.springframework.stereotype.Component;
  5 +
  6 +import java.util.Objects;
  7 +import java.util.Optional;
  8 +
  9 +@Component
  10 +public class CacheUtils {
  11 +
  12 + private final String COMMON_STORE_AREA = "yun-teng-iot-common";
  13 +
  14 + private final CacheManager cacheManager;
  15 +
  16 + public CacheUtils(CacheManager cacheManager) {
  17 + this.cacheManager = cacheManager;
  18 + }
  19 +
  20 + public void put(String key, Object value) {
  21 + Objects.requireNonNull(cacheManager.getCache(COMMON_STORE_AREA)).put(key, value);
  22 + }
  23 +
  24 + public void put(String cacheName, String key, Object value) {
  25 + Objects.requireNonNull(cacheManager.getCache(cacheName)).put(key, value);
  26 + }
  27 +
  28 + public void invalidateCacheName(String cacheName) {
  29 + Objects.requireNonNull(cacheManager.getCache(cacheName)).invalidate();
  30 + }
  31 + public void invalidate(String key) {
  32 + Objects.requireNonNull(cacheManager.getCache(COMMON_STORE_AREA)).evictIfPresent(key);
  33 + }
  34 +
  35 + public void invalidate(String cacheName, String key) {
  36 + Objects.requireNonNull(cacheManager.getCache(cacheName)).evictIfPresent(key);
  37 + }
  38 +
  39 + @SuppressWarnings("unchecked")
  40 + public <T> Optional<T> get(String key) {
  41 + return Optional.ofNullable(
  42 + Objects.requireNonNull(cacheManager.getCache(COMMON_STORE_AREA)).get(key))
  43 + .map(v -> (T) v.get());
  44 + }
  45 +
  46 + @SuppressWarnings("unchecked")
  47 + public <T> Optional<T> get(String cacheName, String key) {
  48 + return Optional.ofNullable(Objects.requireNonNull(cacheManager.getCache(cacheName)).get(key))
  49 + .map(v -> (T) v.get());
  50 + }
  51 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.event;
  2 +
  3 +import org.springframework.context.ApplicationContext;
  4 +import org.springframework.context.ApplicationEvent;
  5 +
  6 +public class RateLimitChangeEvent extends ApplicationEvent {
  7 + private static final long serialVersionUID = 5948179374091197232L;
  8 +
  9 + /**
  10 + * Create a new ContextStartedEvent.
  11 + *
  12 + * @param source the {@code ApplicationContext} that the event is raised for (must not be {@code
  13 + * null})
  14 + */
  15 + public RateLimitChangeEvent(ApplicationContext source) {
  16 + super(source);
  17 + }
  18 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +public class DTOCreationException extends RuntimeException {
  4 +
  5 + private static final long serialVersionUID = 5255597864949518781L;
  6 +
  7 + public DTOCreationException(String message) {
  8 + super(message);
  9 + }
  10 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +import lombok.Getter;
  4 +
  5 +public class DataValidationException extends RuntimeException {
  6 + private static final long serialVersionUID = 3556952261254572635L;
  7 +
  8 + @Getter public boolean log = false;
  9 +
  10 + public DataValidationException(String message) {
  11 + super(message);
  12 + }
  13 +
  14 + public DataValidationException(String message, boolean log) {
  15 + super(message);
  16 + this.log = log;
  17 + }
  18 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +public class EntityCreationException extends RuntimeException {
  4 +
  5 + private static final long serialVersionUID = 5255597864949518781L;
  6 +
  7 + public EntityCreationException(String message) {
  8 + super(message);
  9 + }
  10 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +import lombok.Getter;
  4 +import org.springframework.http.HttpStatus;
  5 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  6 +
  7 +public class FastIotException extends RuntimeException {
  8 + private static final long serialVersionUID = 4036257507478854844L;
  9 +
  10 + @Getter private final HttpStatus httpStatus;
  11 +
  12 + @Getter private final ErrorMessage error;
  13 +
  14 + public FastIotException(ErrorMessage errorMessage) {
  15 + super(errorMessage.getMessage());
  16 + this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
  17 + this.error = errorMessage;
  18 + }
  19 +
  20 + public FastIotException(ErrorMessage errorMessage, HttpStatus httpStatus) {
  21 + super(errorMessage.getMessage());
  22 + this.httpStatus = httpStatus;
  23 + this.error = errorMessage;
  24 + }
  25 +
  26 + public FastIotException() {
  27 + super(ErrorMessage.INTERNAL_ERROR.getMessage());
  28 + this.error = ErrorMessage.INTERNAL_ERROR;
  29 + this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
  30 + }
  31 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +public class FileNotFoundException extends RuntimeException{
  4 + private static final long serialVersionUID = 3466865879043055822L;
  5 +
  6 + public FileNotFoundException(String message) {
  7 + super(message);
  8 + }
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +public class FileStorageException extends RuntimeException{
  4 + private static final long serialVersionUID = -8866081834891143120L;
  5 +
  6 + public FileStorageException(String message) {
  7 + super(message);
  8 + }
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +public class NoneTenantAssetException extends RuntimeException {
  4 + private static final long serialVersionUID = 9135599998185288967L;
  5 +
  6 + public NoneTenantAssetException(String message) {
  7 + super(message);
  8 + }
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.exception;
  2 +
  3 +public class TooManyRequestException extends RuntimeException {
  4 + private static final long serialVersionUID = 1055141330426574861L;
  5 +
  6 + public TooManyRequestException() {
  7 + super();
  8 + }
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.message;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +
  5 +@JsonFormat(shape = JsonFormat.Shape.OBJECT)
  6 +public enum ErrorMessage {
  7 + // ERROR STARTS FROM HERE
  8 + INTERNAL_ERROR(500000, "internal error"),
  9 + OPERATION_FAILED(500001, "operation failed"),
  10 + NO_PERMISSION(403001, "no permission"),
  11 + ACCOUNT_DISABLED(403002, "account disabled"),
  12 + ACCESS_DENIED(403003, "access denied"),
  13 + AUTHENTICATION_METHOD_NOT_SUPPORTED(403004, "authentication method not supported"),
  14 + USERNAME_PASSWORD_INCORRECT(401001, "incorrect username or password"),
  15 + TOKEN_EXPIRED(401002, "token has expired"),
  16 + NONE_TENANT_ASSET(401003, "not current tenant asset"),
  17 + AUTHENTICATION_FAILED_ACCOUNT_EXPIRED(401003, "account has expired"),
  18 + BAD_PARAMETER(400000, "query parameters not valid"),
  19 + INVALID_PARAMETER(400001, "invalid parameters"),
  20 + TOO_MANY_REQUEST(429001, "too many requests"),
  21 + EXIST_ENABLE_TEMPLATE(400002,"存在已启用相同类型及用途的模板"),
  22 + NOT_SET_PASSWORD_TEMPLATE(400003,"未设置用于密码重置的模板"),
  23 + PROVIDE_CORRECT_PHONE_NUMBER(400004,"请提供正确的电话号码"),
  24 + PROVIDE_CORRECT_EMAIL(400005,"请提供正确的邮箱"),
  25 + PHONE_NUMBER_OR_EMAIL_REQUIRED(400006,"必须提供电话或者邮箱"),
  26 + NAME_ALREADY_EXISTS(400007,"名称已存在"),
  27 + ROLE_IN_USE(400008,"该角色还存在用户使用"),
  28 + NONE_DEFAULT_RULE_CHAIN(400009,"该租户不存在默认的规则链"),
  29 + TENANT_MISMATCHING(400010,"租户不匹配"),
  30 + GET_CURRENT_USER_EXCEPTION(400011,"获取当前用户信息异常"),
  31 + CONNECT_TO_TB_ERROR(500001,"与TB联系错误"),
  32 + HAVE_NO_PERMISSION(500002,"没有修改权限");
  33 + private final int code;
  34 + private String message;
  35 +
  36 + ErrorMessage(int code, String message) {
  37 + this.code = code;
  38 + this.message = message;
  39 + }
  40 +
  41 + public ErrorMessage setMessage(String message) {
  42 + this.message = message;
  43 + return this;
  44 + }
  45 +
  46 + public int getCode() {
  47 + return code;
  48 + }
  49 +
  50 + public String getMessage() {
  51 + return message;
  52 + }
  53 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.utils;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +@ConfigurationProperties(prefix = "file.storage.local")
  8 +@Component
  9 +@Data
  10 +public class FileStorageProperties {
  11 + private String type;
  12 + private String uploadDir;
  13 + private String downloadPath;
  14 + private String uploadPath;
  15 + private boolean randomFileName;
  16 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.utils;
  2 +
  3 +
  4 +import org.springframework.http.ResponseEntity;
  5 +import org.springframework.web.multipart.MultipartFile;
  6 +import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse;
  7 +
  8 +import javax.servlet.http.HttpServletRequest;
  9 +import javax.servlet.http.HttpServletResponse;
  10 +
  11 +public interface FileStorageService {
  12 +
  13 + /**
  14 + * 上传文件
  15 + *
  16 + * @param file 待上传文件
  17 + * @return {@link FileUploadResponse} 实例对象
  18 + */
  19 + FileUploadResponse upload(MultipartFile file);
  20 +
  21 + /**
  22 + * 下载文件
  23 + *
  24 + * @param fileName 待下载文件名
  25 + * @param response {@link HttpServletResponse}
  26 + */
  27 + ResponseEntity<?> download(
  28 + String fileName, HttpServletRequest request, HttpServletResponse response);
  29 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.utils;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.apache.commons.lang3.RandomStringUtils;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.beans.factory.annotation.Value;
  7 +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  8 +import org.springframework.core.io.Resource;
  9 +import org.springframework.core.io.UrlResource;
  10 +import org.springframework.http.HttpHeaders;
  11 +import org.springframework.http.MediaType;
  12 +import org.springframework.http.ResponseEntity;
  13 +import org.springframework.stereotype.Service;
  14 +import org.springframework.util.StringUtils;
  15 +import org.springframework.web.multipart.MultipartFile;
  16 +import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
  17 +import org.thingsboard.server.common.data.yunteng.core.exception.FileNotFoundException;
  18 +import org.thingsboard.server.common.data.yunteng.core.exception.FileStorageException;
  19 +import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse;
  20 +
  21 +import javax.servlet.http.HttpServletRequest;
  22 +import javax.servlet.http.HttpServletResponse;
  23 +import java.io.IOException;
  24 +import java.net.MalformedURLException;
  25 +import java.nio.file.Files;
  26 +import java.nio.file.Path;
  27 +import java.nio.file.Paths;
  28 +import java.nio.file.StandardCopyOption;
  29 +import java.util.Objects;
  30 +
  31 +@Service
  32 +@Slf4j
  33 +@ConditionalOnExpression("'${file.storage.type}'=='local'")
  34 +public class LocalFileStorageService implements FileStorageService {
  35 +
  36 + private final FileStorageProperties fileStorageProperties;
  37 + private final Path fileStorageLocation;
  38 +
  39 + @Value("${file.storage.local.staticUrl}")
  40 + private String ossFileUrl;
  41 +
  42 + @Autowired
  43 + public LocalFileStorageService(FileStorageProperties fileStorageProperties) {
  44 + this.fileStorageProperties = fileStorageProperties;
  45 + this.fileStorageLocation =
  46 + Paths.get(fileStorageProperties.getUploadDir()).toAbsolutePath().normalize();
  47 + try {
  48 + Files.createDirectories(this.fileStorageLocation);
  49 + } catch (Exception e) {
  50 + throw new RuntimeException(
  51 + "Could not create the directory where the uploaded files will be stored.");
  52 + }
  53 + }
  54 +
  55 + public String storeFile(MultipartFile file) {
  56 + // Normalize file name
  57 + String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename()));
  58 +
  59 + try {
  60 + // random fileName if needed
  61 + if (fileStorageProperties.isRandomFileName()) {
  62 + if (fileName.contains(".")) {
  63 + fileName =
  64 + RandomStringUtils.randomAlphabetic(15)
  65 + + fileName.substring(fileName.lastIndexOf("."));
  66 + } else {
  67 + fileName = RandomStringUtils.randomAlphabetic(15);
  68 + }
  69 + }
  70 + // Check if the file's name contains invalid characters
  71 + if (fileName.contains("..")) {
  72 + throw new FileStorageException(
  73 + "Sorry! Filename contains invalid path sequence " + fileName);
  74 + }
  75 +
  76 + // Copy file to the target location (Replacing existing file with the same name)
  77 + Path targetLocation = this.fileStorageLocation.resolve(fileName);
  78 + Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
  79 +
  80 + return fileName;
  81 + } catch (IOException ex) {
  82 + throw new FileStorageException("Could not store file " + fileName + ". Please try again!");
  83 + }
  84 + }
  85 +
  86 + public Resource loadFileAsResource(String fileName) {
  87 + try {
  88 + Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
  89 + Resource resource = new UrlResource(filePath.toUri());
  90 + if (resource.exists()) {
  91 + return resource;
  92 + } else {
  93 + throw new FileNotFoundException("File not found " + fileName);
  94 + }
  95 + } catch (MalformedURLException ex) {
  96 + throw new FileNotFoundException("File not found " + fileName);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public FileUploadResponse upload(MultipartFile file) {
  102 + String fileName = this.storeFile(file);
  103 + String fileDownloadPath =
  104 + ServletUriComponentsBuilder.fromCurrentRequestUri()
  105 + .path(fileStorageProperties.getDownloadPath())
  106 + .path(fileName)
  107 + .toUriString();
  108 + String realDownloadPath = fileDownloadPath.replace(fileStorageProperties.getUploadPath(), "");
  109 + String ossStaticPath =
  110 + ServletUriComponentsBuilder.fromCurrentContextPath().toUriString() + ossFileUrl;
  111 + ossStaticPath = ossStaticPath.replace("**", fileName);
  112 + return new FileUploadResponse(
  113 + fileName, realDownloadPath, file.getContentType(), file.getSize(), ossStaticPath);
  114 + }
  115 +
  116 + @Override
  117 + public ResponseEntity<?> download(
  118 + String fileName, HttpServletRequest request, HttpServletResponse response) {
  119 + Resource resource = this.loadFileAsResource(fileName);
  120 + String contentType = null;
  121 + try {
  122 + contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
  123 + } catch (IOException ex) {
  124 + log.info("Could not determine file type.");
  125 + }
  126 +
  127 + // Fallback to the default content type if type could not be determined
  128 + if (contentType == null) {
  129 + contentType = "application/octet-stream";
  130 + }
  131 +
  132 + return ResponseEntity.ok()
  133 + .contentType(MediaType.parseMediaType(contentType))
  134 + .header(
  135 + HttpHeaders.CONTENT_DISPOSITION,
  136 + "attachment; filename=\"" + resource.getFilename() + "\"")
  137 + .body(resource);
  138 + }
  139 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.utils;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +/**
  8 + * @author 徐浩然
  9 + * @desc minio配置文件
  10 + * @date 2021/12/1-15:35
  11 + */
  12 +@ConfigurationProperties(prefix = "file.storage.minio")
  13 +@Component
  14 +@Data
  15 +public class MinioFileStorageProperties {
  16 + /** minio储存地址 */
  17 + private String minioUrl;
  18 + /** minio账户 */
  19 + private String minioName;
  20 + /** minio访问密码 */
  21 + private String minioPass;
  22 + /** minio储存桶名称 */
  23 + private String bucketName;
  24 +
  25 + private boolean randomFileName;
  26 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.core.utils;
  2 +
  3 +import io.minio.*;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.apache.commons.lang3.RandomStringUtils;
  6 +import org.jetbrains.annotations.NotNull;
  7 +import org.springframework.beans.factory.annotation.Autowired;
  8 +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  9 +import org.springframework.http.HttpHeaders;
  10 +import org.springframework.http.HttpStatus;
  11 +import org.springframework.http.ResponseEntity;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.util.StringUtils;
  14 +import org.springframework.web.context.request.RequestContextHolder;
  15 +import org.springframework.web.context.request.ServletRequestAttributes;
  16 +import org.springframework.web.multipart.MultipartFile;
  17 +import org.thingsboard.server.common.data.yunteng.core.exception.FileStorageException;
  18 +import org.thingsboard.server.common.data.yunteng.dto.FileUploadResponse;
  19 +
  20 +import javax.servlet.http.HttpServletRequest;
  21 +import javax.servlet.http.HttpServletResponse;
  22 +import java.io.InputStream;
  23 +import java.io.OutputStream;
  24 +import java.util.Objects;
  25 +
  26 +@Service
  27 +@Slf4j
  28 +@ConditionalOnExpression("'${file.storage.type}'=='minio'")
  29 +public class MinioFileStorageService implements FileStorageService {
  30 +
  31 + private final MinioFileStorageProperties fileStorageProperties;
  32 + private MinioClient minioClient;
  33 +
  34 + @Autowired
  35 + public MinioFileStorageService(MinioFileStorageProperties fileStorageProperties) {
  36 + this.fileStorageProperties = fileStorageProperties;
  37 + // 创建客户端对象
  38 + this.minioClient =
  39 + MinioClient.builder()
  40 + .endpoint(fileStorageProperties.getMinioUrl())
  41 + .credentials(fileStorageProperties.getMinioName(), fileStorageProperties.getMinioPass())
  42 + .build();
  43 + // 创建储存桶
  44 + checkBucket();
  45 + }
  46 +
  47 + // 储存文件
  48 + public String storeFile(MultipartFile file) {
  49 + // Normalize file name
  50 + String fileName = StringUtils.cleanPath(Objects.requireNonNull(file.getOriginalFilename()));
  51 + // random fileName if needed
  52 + if (fileStorageProperties.isRandomFileName()) {
  53 + if (fileName.contains(".")) {
  54 + fileName =
  55 + RandomStringUtils.randomAlphabetic(15) + fileName.substring(fileName.lastIndexOf("."));
  56 + } else {
  57 + fileName = RandomStringUtils.randomAlphabetic(15);
  58 + }
  59 + }
  60 + // Check if the file's name contains invalid characters
  61 + if (fileName.contains("..")) {
  62 + throw new FileStorageException("Sorry! Filename contains invalid path sequence " + fileName);
  63 + }
  64 +
  65 + // 储存
  66 + try {
  67 + checkBucket();
  68 + PutObjectArgs build =
  69 + PutObjectArgs.builder()
  70 + .bucket(fileStorageProperties.getBucketName())
  71 + .object(fileName)
  72 + .contentType(file.getContentType())
  73 + .stream(file.getInputStream(), file.getInputStream().available(), -1)
  74 + .build();
  75 + minioClient.putObject(build);
  76 + return fileName;
  77 + } catch (Exception ex) {
  78 + ex.printStackTrace();
  79 + throw new FileStorageException("Could not store file " + fileName + ". Please try again!");
  80 + }
  81 + }
  82 +
  83 + @Override
  84 + public FileUploadResponse upload(MultipartFile file) {
  85 + String fileName = this.storeFile(file);
  86 + String staticPath = getPath(fileName);
  87 + String realDownloadPath = null;
  88 + try {
  89 + // 获取request
  90 + HttpServletRequest request =
  91 + ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  92 + // 生成下载接口的地址
  93 + realDownloadPath =
  94 + request.getRequestURL().toString().replace("upload", "downloadFile/" + fileName);
  95 + } catch (Exception e) {
  96 + e.printStackTrace();
  97 + log.info("Could not upload file " + fileName + ". Please try again!");
  98 + }
  99 + return new FileUploadResponse(
  100 + fileName, realDownloadPath, file.getContentType(), file.getSize(), staticPath);
  101 + }
  102 +
  103 + @Override
  104 + public ResponseEntity<?> download(
  105 + String fileName, HttpServletRequest request, HttpServletResponse response) {
  106 + // get object given the bucket and object name
  107 + try (
  108 + // 获取文件流
  109 + InputStream inputStream =
  110 + minioClient.getObject(
  111 + GetObjectArgs.builder()
  112 + .bucket(fileStorageProperties.getBucketName())
  113 + .object(fileName)
  114 + .build());
  115 + // 获取输出流
  116 + OutputStream outputStream = response.getOutputStream(); ) {
  117 + // 清空
  118 + response.reset();
  119 + // 写入流
  120 + byte[] buffer = inputStream.readAllBytes();
  121 + outputStream.write(buffer);
  122 + outputStream.flush();
  123 + // 配置header
  124 + response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);
  125 + response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(buffer.length));
  126 + return ResponseEntity.status(HttpStatus.OK).body("download...");
  127 + } catch (Exception e) {
  128 + // 找不到文件时会抛出异常
  129 + String err = fileName + "file not found";
  130 + log.info(err);
  131 + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(err);
  132 + }
  133 + }
  134 +
  135 + // 检查储存桶情况
  136 + private void checkBucket() {
  137 + try {
  138 + // 桶是否存在
  139 + boolean exists =
  140 + minioClient.bucketExists(
  141 + BucketExistsArgs.builder().bucket(fileStorageProperties.getBucketName()).build());
  142 + if (!exists) {
  143 + // 不存在创建
  144 + minioClient.makeBucket(
  145 + MakeBucketArgs.builder().bucket(fileStorageProperties.getBucketName()).build());
  146 + // 设置储存桶策略
  147 + String str =
  148 + "{\"Statement\": [{\"Action\": [\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Effect\": \"Allow\",\"Principal\": \"*\",\"Resource\": \"arn:aws:s3:::%\"},{\"Action\": \"s3:GetObject\",\"Effect\": \"Allow\",\"Principal\": \"*\",\"Resource\": \"arn:aws:s3:::%/*\"}],\"Version\": \"2012-10-17\"}";
  149 + String replace = str.replace("%", fileStorageProperties.getBucketName());
  150 + minioClient.setBucketPolicy(
  151 + SetBucketPolicyArgs.builder()
  152 + .bucket(fileStorageProperties.getBucketName())
  153 + .config(replace)
  154 + .build());
  155 + }
  156 + } catch (Exception e) {
  157 + log.error(e.getMessage(), e);
  158 + }
  159 + }
  160 +
  161 + /**
  162 + * @param fileName 文件名
  163 + * @return 文件访问地址
  164 + */
  165 + @NotNull
  166 + private String getPath(String fileName) {
  167 + return fileStorageProperties
  168 + .getMinioUrl()
  169 + .concat("/")
  170 + .concat(fileStorageProperties.getBucketName())
  171 + .concat("/")
  172 + .concat(fileName);
  173 + }
  174 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class AlarmProfileDTO extends TenantDTO {
  7 + /** 告警联系人 通知多人“,”号分隔 */
  8 + private String alarmContactId;
  9 + /** 设备配置ID */
  10 + private String deviceProfileId;
  11 + /** 消息通知方式:多种方式“,”号分隔 MessageTypeEnum */
  12 + private String messageMode;
  13 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +
  4 +import com.fasterxml.jackson.annotation.JsonFormat;
  5 +import com.fasterxml.jackson.annotation.JsonIgnore;
  6 +import com.fasterxml.jackson.annotation.JsonInclude;
  7 +import lombok.Data;
  8 +import org.springframework.beans.BeanUtils;
  9 +import org.thingsboard.server.common.data.yunteng.common.UpdateGroup;
  10 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  11 +import org.thingsboard.server.common.data.yunteng.core.exception.EntityCreationException;
  12 +import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
  13 +
  14 +import javax.validation.constraints.NotEmpty;
  15 +import java.lang.reflect.Constructor;
  16 +import java.lang.reflect.InvocationTargetException;
  17 +import java.time.LocalDateTime;
  18 +
  19 +@Data
  20 +@JsonInclude(JsonInclude.Include.NON_NULL)
  21 +public class BaseDTO {
  22 + @NotEmpty(message = "ID不能为空或者空字符串",groups = {UpdateGroup.class})
  23 + private String id;
  24 + /**创建用户*/
  25 + private String creator;
  26 + /**创建时间*/
  27 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  28 + private LocalDateTime createTime;
  29 + /**更新用户*/
  30 + private String updater;
  31 + /**更新时间*/
  32 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  33 + private LocalDateTime updateTime;
  34 + @JsonIgnore
  35 + public <E> void copyToEntity(E entity, String... ignoreProperties) {
  36 + if (ignoreProperties.length == 0) {
  37 + BeanUtils.copyProperties(
  38 + this,
  39 + entity,
  40 + ModelConstants.TablePropertyMapping.CREATE_TIME,
  41 + ModelConstants.TablePropertyMapping.UPDATE_TIME,
  42 + ModelConstants.TablePropertyMapping.CREATOR,
  43 + ModelConstants.TablePropertyMapping.UPDATER);
  44 + } else {
  45 + BeanUtils.copyProperties(this, entity, ignoreProperties);
  46 + }
  47 + }
  48 +
  49 + @JsonIgnore
  50 + @SuppressWarnings("unchecked")
  51 + public <E> E getEntity(Class<E> clazz) {
  52 + Constructor<?> constructor = ReflectUtils.getEmptyParameterConstructor(clazz);
  53 + if (constructor != null) {
  54 + try {
  55 + E e = (E) constructor.newInstance();
  56 + BeanUtils.copyProperties(this, e);
  57 + return e;
  58 + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
  59 + throw new EntityCreationException(
  60 + "try to get entity from class [" + clazz.getName() + "] failed " + e.getMessage());
  61 + }
  62 + } else {
  63 + throw new EntityCreationException(
  64 + "try to get entity from class [" + clazz.getName() + "] failed");
  65 + }
  66 + }
  67 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.common.DeleteGroup;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +import javax.validation.constraints.Size;
  8 +import java.util.Set;
  9 +
  10 +@Data
  11 +public class DeleteDTO {
  12 + /** 删除主键IDS */
  13 + @NotNull(
  14 + message = "IDS不能为空",
  15 + groups = {DeleteGroup.class})
  16 + @Size(
  17 + min = 1,
  18 + message = "删除至少需要一个id",
  19 + groups = {DeleteGroup.class})
  20 + private Set<String> ids;
  21 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import com.fasterxml.jackson.annotation.JsonIgnore;
  5 +import com.fasterxml.jackson.databind.JsonNode;
  6 +import io.swagger.annotations.ApiModelProperty;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import org.thingsboard.server.common.data.security.DeviceCredentialsType;
  10 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  11 +import org.thingsboard.server.common.data.yunteng.enums.DeviceState;
  12 +import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
  13 +
  14 +import javax.validation.constraints.NotEmpty;
  15 +import javax.validation.constraints.NotNull;
  16 +import java.time.LocalDateTime;
  17 +
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@Data
  20 +public class DeviceDTO extends TenantDTO {
  21 + private String name;
  22 + /**
  23 + * 包含字段:
  24 + *
  25 + * <ul/>
  26 + * <li>gateway 网关,bool类型
  27 + * <li>description 描述字段
  28 + */
  29 + private JsonNode deviceInfo;
  30 +
  31 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  32 + private LocalDateTime activeTime;
  33 +
  34 + private DeviceState deviceState = DeviceState.INACTIVE;
  35 +
  36 + @NotEmpty(
  37 + message = "设备配置ID不能为空或者空字符串",
  38 + groups = {AddGroup.class})
  39 + @ApiModelProperty(value = "设备配置", required = true)
  40 + private String profileId;
  41 +
  42 + @NotEmpty(
  43 + message = "设备唯一编号不能为空或空字符串",
  44 + groups = {AddGroup.class})
  45 + @ApiModelProperty(value = "设备唯一编号", required = true)
  46 + private String deviceToken;
  47 + // 不用序列化给前端
  48 + @JsonIgnore private String tbDeviceId;
  49 + private String deviceTypeId;
  50 +
  51 + @NotEmpty(
  52 + message = "所属组织不能为空或者空字符串",
  53 + groups = {AddGroup.class})
  54 + @ApiModelProperty(value = "设备组织", required = true)
  55 + private String organizationId;
  56 + /** 标签 */
  57 + private String label;
  58 +
  59 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  60 + private LocalDateTime lastConnectTime;
  61 +
  62 + private DeviceProfileDTO deviceProfile;
  63 + private OrganizationDTO organizationDTO;
  64 +
  65 + @NotNull(
  66 + message = "设备类型不能为空",
  67 + groups = {AddGroup.class})
  68 + @ApiModelProperty(value = "设备类型:GATEWAY,DIRECT_CONNECTION,SENSOR", required = true)
  69 + private DeviceTypeEnum deviceType;
  70 + /** 设备凭证 */
  71 + private DeviceCredentialsType deviceCredentials;
  72 + /** 告警状态:0:正常 1:告警 */
  73 + private Integer alarmStatus;
  74 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.databind.JsonNode;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import org.thingsboard.server.common.data.DeviceTransportType;
  8 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  9 +
  10 +import javax.validation.constraints.NotEmpty;
  11 +
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@Data
  14 +public class DeviceProfileDTO extends TenantDTO {
  15 + @NotEmpty(message = "设备配置名称不能为空或者空字符串", groups = AddGroup.class)
  16 + @ApiModelProperty(value = "设备配置名称")
  17 + private String name;
  18 +
  19 + private String description;
  20 + /** 转换脚本:TCP才会使用 */
  21 + private String convertJs;
  22 +
  23 + @NotEmpty(message = "传输协议不能为空或者空字符串", groups = AddGroup.class)
  24 + @ApiModelProperty(value = "传输协议", required = true)
  25 + @NotEmpty(message = "传输协议不能为空或者二空字符串")
  26 + private DeviceTransportType transportType;
  27 + /** TB的设备配置文件 */
  28 + private String tbProfileId;
  29 +
  30 + private JsonNode alarms;
  31 + /** 告警配置 */
  32 + private AlarmProfileDTO alarmProfile;
  33 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +
  6 +@Data
  7 +@AllArgsConstructor
  8 +public class FileUploadResponse {
  9 + private String fileName;
  10 + private String fileDownloadUri;
  11 + private String fileType;
  12 + private long size;
  13 + private String fileStaticUri;
  14 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import com.fasterxml.jackson.annotation.JsonIgnore;
  5 +import com.fasterxml.jackson.annotation.JsonInclude;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import org.thingsboard.server.common.data.yunteng.enums.MenuTypeEnum;
  10 +
  11 +import java.time.LocalDateTime;
  12 +import java.util.ArrayList;
  13 +import java.util.List;
  14 +import java.util.Objects;
  15 +
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@Data
  18 +public class MenuDTO extends BaseDTO implements Comparable<MenuDTO> {
  19 + private String id;
  20 + /**
  21 + * if menu type is system default, the menu name can be null; if menu type is not system default,
  22 + * menu name is user defined
  23 + */
  24 + private String name;
  25 +
  26 + // @JsonIgnore
  27 + private String parentId;
  28 + private List<MenuDTO> children;
  29 + private String path;
  30 + // @JsonIgnore
  31 + private MenuTypeEnum type;
  32 + private String permission;
  33 + private Integer sort;
  34 + @JsonIgnore private String tenantCode;
  35 + private String component;
  36 + private JsonNode meta;
  37 + @JsonIgnore private String alias;
  38 +
  39 + @JsonInclude(JsonInclude.Include.NON_NULL)
  40 + private String redirect;
  41 +
  42 + @JsonInclude(JsonInclude.Include.NON_NULL)
  43 + private Boolean caseSensitive;
  44 +
  45 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  46 + private LocalDateTime createTime;
  47 +
  48 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  49 + private LocalDateTime updateTime;
  50 +
  51 + public MenuDTO() {
  52 + this.children = new ArrayList<>();
  53 + }
  54 +
  55 + @Override
  56 + public int compareTo(MenuDTO o) {
  57 + return Objects.requireNonNullElse(this.getSort(), 0)
  58 + - Objects.requireNonNullElse(o.getSort(), 0);
  59 + }
  60 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.databind.JsonNode;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.common.aspect.annotation.AutoDict;
  7 +
  8 +@EqualsAndHashCode(callSuper = false)
  9 +@Data
  10 +public class MessageConfigDTO extends TenantDTO {
  11 +
  12 + /** 配置名称 */
  13 + private String configName;
  14 + /** 短信平台类型 */
  15 + @AutoDict(dictCode = "platform_type")
  16 + private String platformType;
  17 +
  18 + /** 消息类型 */
  19 + @AutoDict(dictCode = "message_type")
  20 + private String messageType;
  21 +
  22 + /** json配置 */
  23 + private JsonNode config;
  24 +
  25 + /** 状态:0禁用 1启用 */
  26 + private Integer status;
  27 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +import org.thingsboard.server.common.data.yunteng.common.aspect.annotation.AutoDict;
  6 +
  7 +@EqualsAndHashCode(callSuper = false)
  8 +@Data
  9 +public class MessageTemplateDTO extends TenantDTO {
  10 + /** 模板名称 */
  11 + private String templateName;
  12 +
  13 + /** 模板签名 */
  14 + private String signName;
  15 +
  16 + /** 模板CODE */
  17 + private String templateCode;
  18 +
  19 + /** 消息配置 */
  20 + private String messageConfigId;
  21 +
  22 + /**消息配置信息*/
  23 + private MessageConfigDTO messageConfig;
  24 +
  25 + /**消息类型*/
  26 + private String messageType;
  27 +
  28 + /** 模板用途 */
  29 + @AutoDict(dictCode = "template_purpose")
  30 + private String templatePurpose;
  31 +
  32 + /** 状态:0禁用 1启用 */
  33 + private Integer status;
  34 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.utils.tree.TreeDTO;
  7 +
  8 +import java.util.ArrayList;
  9 +import java.util.List;
  10 +
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@Data
  13 +public class OrganizationDTO extends TenantDTO implements TreeDTO<OrganizationDTO> {
  14 + private String parentId;
  15 + private String name;
  16 + private int sort;
  17 + private List<OrganizationDTO> children;
  18 + private String remark;
  19 +
  20 + public OrganizationDTO() {
  21 + this.children = new ArrayList<>();
  22 + }
  23 +
  24 + @Override
  25 + public int compareTo(OrganizationDTO o) {
  26 + return this.getSort() - o.getSort();
  27 + }
  28 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +
  4 +import lombok.Data;
  5 +
  6 +@Data
  7 +public class PlainRolesDTO {
  8 + private String roleId;
  9 + private String roleName;
  10 +
  11 + @Override
  12 + public String toString() {
  13 + return "角色ID:" + roleId + " " + "角色名:" + roleName;
  14 + }
  15 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonAlias;
  4 +import com.fasterxml.jackson.annotation.JsonFormat;
  5 +import com.fasterxml.jackson.annotation.JsonProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@Data
  13 +public class RoleDTO extends TenantDTO {
  14 + private String name;
  15 + private String remark;
  16 + private LocalDateTime createTime;
  17 + private String roleType;
  18 + private String code;
  19 + @JsonFormat(shape = JsonFormat.Shape.NUMBER)
  20 + @JsonAlias({"status", "enabled"})
  21 + @JsonProperty("status")
  22 + private boolean enabled = true;
  23 + private String[] roleIds;
  24 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +
  8 +@Data
  9 +public class SysDictDTO extends TenantDTO{
  10 +
  11 + /** 字典名称 */
  12 + @NotEmpty(message = "字典名称不能为空或空字符串",groups = {AddGroup.class})
  13 + private String dictName;
  14 +
  15 + /** 字典编码 */
  16 + @NotEmpty(message = "字典编码不能为空或空字符串",groups = {AddGroup.class})
  17 + private String dictCode;
  18 +
  19 + /** 字典描述 */
  20 + private String description;
  21 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +
  8 +@Data
  9 +public class SysDictItemDTO extends BaseDTO{
  10 + /** 字典ID */
  11 + @NotEmpty(message = "字典表ID不能为空或空字符串",groups = {AddGroup.class})
  12 + private String dictId;
  13 +
  14 + /** 字典文本 */
  15 + @NotEmpty(message = "字典Item文本不能为空或空字符串",groups = {AddGroup.class})
  16 + private String itemText;
  17 +
  18 + /** 字典值 */
  19 + @NotEmpty(message = "字典Item文本值不能为空或空字符串",groups = {AddGroup.class})
  20 + private String itemValue;
  21 +
  22 + /** 字典描述 */
  23 + private String description;
  24 +
  25 + /** 字典排序 默认排序1*/
  26 + private Integer sort;
  27 +
  28 + /** 字典状态 默认状态1 启用*/
  29 + private Integer status;
  30 +
  31 + /** 租户Code */
  32 + private String tenantCode;
  33 +
  34 + /**字典*/
  35 + private SysDictDTO sysDict;
  36 +
  37 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +
  4 +import com.fasterxml.jackson.annotation.JsonFormat;
  5 +import com.fasterxml.jackson.annotation.JsonInclude;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import org.thingsboard.server.common.data.yunteng.enums.TenantStatusEnum;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +@EqualsAndHashCode(callSuper = false)
  13 +@Data
  14 +public class TenantDTO extends BaseDTO {
  15 + private String name;
  16 + private String icon;
  17 + private String tenantCode;
  18 + private boolean enabled;
  19 + private String description;
  20 + private String defaultConfig;
  21 + /** TB的租户ID */
  22 + private String tenantId;
  23 + /** 租户角色 */
  24 + private String[] roleIds;
  25 +
  26 + @JsonInclude(JsonInclude.Include.NON_NULL)
  27 + private TenantStatusEnum tenantStatus;
  28 +
  29 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  30 + private LocalDateTime tenantExpireTime;
  31 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import com.fasterxml.jackson.annotation.JsonInclude;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  8 +import org.thingsboard.server.common.data.yunteng.enums.UserStatusEnum;
  9 +
  10 +import javax.validation.constraints.NotEmpty;
  11 +import java.time.LocalDateTime;
  12 +import java.util.Set;
  13 +
  14 +@EqualsAndHashCode(callSuper = false)
  15 +@Data
  16 +public class UserDTO extends BaseDTO {
  17 +
  18 + @NotEmpty(message = "用户名不能为空或字符串", groups = AddGroup.class)
  19 + private String username;
  20 +
  21 + @NotEmpty(message = "姓名不能为空或字符串", groups = AddGroup.class)
  22 + private String realName;
  23 +
  24 + @JsonInclude(JsonInclude.Include.NON_NULL)
  25 + @NotEmpty(message = "密码不能为空或空字符串", groups = AddGroup.class)
  26 + private String password;
  27 +
  28 + @JsonInclude(JsonInclude.Include.NON_NULL)
  29 + private String activateToken;
  30 +
  31 + /** 所辖组织ids */
  32 + private String[] organizationIds;
  33 +
  34 + /** 角色ids */
  35 + private String[] roleIds;
  36 +
  37 + private String phoneNumber;
  38 + private String email;
  39 + private String avatar;
  40 + private boolean enabled;
  41 +
  42 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  43 + private LocalDateTime accountExpireTime;
  44 +
  45 + private boolean hasPassword;
  46 +
  47 + @JsonInclude(JsonInclude.Include.NON_NULL)
  48 + private String tenantCode;
  49 +
  50 + @JsonInclude(JsonInclude.Include.NON_NULL)
  51 + private String tenantName;
  52 +
  53 + @JsonInclude(JsonInclude.Include.NON_NULL)
  54 + private UserStatusEnum userStatusEnum;
  55 +
  56 + @JsonInclude(JsonInclude.Include.NON_NULL)
  57 + private Set<PlainRolesDTO> roles;
  58 +
  59 + private String deptId;
  60 +
  61 + /** 0:超级管理员;1:租户账号;2:租户下的账号 */
  62 + private Integer level;
  63 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
  5 +
  6 +@Data
  7 +public class UserDetailRoleDTO {
  8 + private RoleEnum roleType;
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +import java.time.LocalDateTime;
  7 +import java.util.Set;
  8 +
  9 +/** for authentication */
  10 +@Data
  11 +public class UserDetailsDTO implements Serializable {
  12 +
  13 + private static final long serialVersionUID = -515966143236266646L;
  14 + private String id;
  15 + private String username;
  16 + private String password;
  17 + private boolean enabled;
  18 + private LocalDateTime accountExpireTime;
  19 + private TenantDTO tenant;
  20 + private String tenantId;
  21 + private Set<UserDetailRoleDTO> roles;
  22 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnore;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import com.alibaba.excel.converters.Converter;
  6 +import com.alibaba.excel.converters.WriteConverterContext;
  7 +import com.alibaba.excel.enums.CellDataTypeEnum;
  8 +import com.alibaba.excel.metadata.data.WriteCellData;
  9 +import io.swagger.annotations.ApiModelProperty;
  10 +import lombok.Data;
  11 +import org.apache.commons.lang3.StringUtils;
  12 +
  13 +import java.util.Set;
  14 +
  15 +@Data
  16 +public class UserInfoDTO {
  17 + @ExcelProperty("用户Id")
  18 + @ApiModelProperty(value = "用户ID")
  19 + private String userId;
  20 +
  21 + @ApiModelProperty(value = "姓名")
  22 + private String realName;
  23 +
  24 + @ExcelIgnore
  25 + @ApiModelProperty(value = "头像")
  26 + private String avatar;
  27 +
  28 + @ApiModelProperty(value = "租户Code")
  29 + private String tenantCode;
  30 +
  31 + @ApiModelProperty(value = "租户名称")
  32 + private String tenantName;
  33 +
  34 + @ApiModelProperty(value = "主页地址")
  35 + private String homePath;
  36 + /** default: true */
  37 + @ApiModelProperty(value = "是否需要重置密码")
  38 + private boolean needSetPwd = true;
  39 +
  40 + /** 添加SetConverter,将Set字符串或者对象转成字符串,对象转成字符串会调用其toString方法,请重写toString方法 */
  41 + @ExcelProperty(converter = SetConverter.class)
  42 + private Set<String> roles;
  43 +
  44 + @ExcelProperty(converter = SetConverter.class)
  45 + private Set<PlainRolesDTO> plainRoles;
  46 +
  47 + public static class SetConverter implements Converter<Set<?>> {
  48 + @Override
  49 + public Class<?> supportJavaTypeKey() {
  50 + return Set.class;
  51 + }
  52 +
  53 + @Override
  54 + public WriteCellData<?> convertToExcelData(WriteConverterContext<Set<?>> context)
  55 + throws Exception {
  56 + return new WriteCellData<>(
  57 + CellDataTypeEnum.STRING, StringUtils.join(context.getValue(), ","));
  58 + }
  59 + }
  60 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonInclude;
  4 +import lombok.Data;
  5 +
  6 +import java.io.Serializable;
  7 +
  8 +@Data
  9 +@JsonInclude(JsonInclude.Include.NON_NULL)
  10 +public class UserRoleDTO implements Serializable {
  11 + private static final long serialVersionUID = -6930831157503627224L;
  12 + /** 用户ID */
  13 + private String userId;
  14 + /** 角色ID */
  15 + private String roleId;
  16 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +@ApiModel(value = "密码修改")
  9 +public class AccountReqDTO {
  10 +
  11 + @ApiModelProperty(value = "用户ID",required = true)
  12 + private String userId;
  13 + @ApiModelProperty(value = "旧密码,旧密码为空表示设置初始密码")
  14 + private String password;
  15 + @ApiModelProperty(value = "新密码",required = true)
  16 + private String resetPassword;
  17 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonCreator;
  4 +import com.fasterxml.jackson.annotation.JsonProperty;
  5 +import lombok.Getter;
  6 +
  7 +@Getter
  8 +public class CodeLoginRequest {
  9 + private final String phoneNumber;
  10 + private final String code;
  11 +
  12 + @JsonCreator
  13 + public CodeLoginRequest(
  14 + @JsonProperty("phoneNumber") String phoneNumber, @JsonProperty("code") String code) {
  15 + this.phoneNumber = phoneNumber;
  16 + this.code = code;
  17 + }
  18 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
  7 +@Data
  8 +@AllArgsConstructor
  9 +@NoArgsConstructor
  10 +public class CodeTTL {
  11 + private String code;
  12 + private long sendTs;
  13 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import lombok.Data;
  4 +import lombok.RequiredArgsConstructor;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import javax.validation.constraints.NotNull;
  8 +import java.io.File;
  9 +
  10 +@Data
  11 +@RequiredArgsConstructor
  12 +public class EmailReqDTO{
  13 +
  14 + /** 接收人 */
  15 + @NotEmpty(message = "缺少邮件接收人")
  16 + private String[] to;
  17 +
  18 + /** 抄送人 */
  19 + private String[] cc;
  20 +
  21 + /** 密送人 */
  22 + private String[] bcc;
  23 +
  24 + /** 主题 */
  25 + @NotNull(message = "主题不能为空")
  26 + private String subject;
  27 +
  28 + /** 内容 */
  29 + @NotEmpty(message ="内容不能为空")
  30 + private String body;
  31 +
  32 + /** 附件 */
  33 + private File[] files;
  34 +
  35 + /** 邮件格式:TEXT或者HTML */
  36 + @NotEmpty(message ="邮件格式不能为空")
  37 + private String emailFormatEnum;
  38 +
  39 + /** 模板ID */
  40 + @NotEmpty(message ="模板ID不能为空")
  41 + private String id;
  42 +
  43 + /**备注*/
  44 + private String remark;
  45 +
  46 + /**用途*/
  47 + private String templatePurpose;
  48 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonCreator;
  4 +import com.fasterxml.jackson.annotation.JsonProperty;
  5 +
  6 +public class LoginRequest {
  7 + private final String username;
  8 + private final String password;
  9 +
  10 + @JsonCreator
  11 + public LoginRequest(
  12 + @JsonProperty("username") String username, @JsonProperty("password") String password) {
  13 + this.username = username;
  14 + this.password = password;
  15 + }
  16 +
  17 + public String getUsername() {
  18 + return username;
  19 + }
  20 +
  21 + public String getPassword() {
  22 + return password;
  23 + }
  24 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import javax.validation.constraints.NotEmpty;
  6 +import java.io.Serializable;
  7 +
  8 +@Data
  9 +public class RoleOrOrganizationReqDTO implements Serializable {
  10 +
  11 + private static final long serialVersionUID = -5917331728153319765L;
  12 + /** 是否查询关联角色 */
  13 + private boolean queryRole;
  14 +
  15 + /** 是否查询关联组织 */
  16 + private boolean queryOrganization;
  17 +
  18 + /** 用户ID */
  19 + @NotEmpty(message = "用户ID不能为空或者空字符串")
  20 + private String userId;
  21 +
  22 + /** 角色或组织的ID */
  23 + private String id;
  24 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +
  4 +import lombok.Data;
  5 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
  6 +
  7 +import java.util.List;
  8 +
  9 +@Data
  10 +public class RoleReqDTO {
  11 + private String id;
  12 + private String name;
  13 + private String remark;
  14 + private RoleEnum roleType;
  15 + private int status;
  16 + private List<String> menu;
  17 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Data
  10 +public class SendResetPasswordEmailMsg {
  11 + @NotNull(message = "用户ID不能为空")
  12 + private String userId;
  13 +
  14 + @NotEmpty(message = "消息类型不能为空字符串")
  15 + private MessageTypeEnum messageTypeEnum;
  16 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import lombok.Data;
  4 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +import javax.validation.constraints.Pattern;
  8 +import java.util.LinkedHashMap;
  9 +
  10 +@Data
  11 +public class SmsReqDTO {
  12 +
  13 + /** 模板参数 */
  14 + private LinkedHashMap<String, String> params;
  15 +
  16 + /** 手机号码 */
  17 + @Pattern(regexp = FastIotConstants.MOBILE, message = "请输入正确的手机号")
  18 + private String phoneNumbers;
  19 +
  20 + /** 模板ID */
  21 + @NotNull(message = "模板ID不能为空")
  22 + private String id;
  23 +
  24 + /** 备注 */
  25 + private String remark;
  26 +
  27 + /** 用途 */
  28 + private String templatePurpose;
  29 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.dto.request;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonFormat;
  4 +import com.fasterxml.jackson.annotation.JsonInclude;
  5 +import lombok.Data;
  6 +import org.thingsboard.server.common.data.yunteng.common.AddGroup;
  7 +import org.thingsboard.server.common.data.yunteng.enums.TenantStatusEnum;
  8 +
  9 +import javax.validation.constraints.NotEmpty;
  10 +import javax.validation.constraints.NotNull;
  11 +import java.time.LocalDateTime;
  12 +
  13 +@Data
  14 +public class TenantReqDTO {
  15 + private String id;
  16 + private String icon;
  17 +
  18 + @NotEmpty(message = "租户名称不能为空或空字符串", groups = AddGroup.class)
  19 + private String name;
  20 +
  21 + private boolean enabled;
  22 + private String description;
  23 +
  24 + @NotNull(message = "角色不能为空", groups = AddGroup.class)
  25 + private String[] roleIds;
  26 +
  27 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  28 + private LocalDateTime tenantExpireTime;
  29 +
  30 + private String tenantCode;
  31 + private String defaultConfig;
  32 +
  33 + @JsonInclude(JsonInclude.Include.NON_NULL)
  34 + private TenantStatusEnum tenantStatus;
  35 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +/**
  4 + * 设备凭证
  5 + */
  6 +public enum DeviceCredentialsEnum {
  7 + ACCESS_TOKEN,
  8 + X509_CERTIFICATE,
  9 + MQTT_BASIC,
  10 + LWM2M_CREDENTIALS
  11 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum DeviceState {
  4 + INACTIVE,
  5 + ONLINE,
  6 + OFFLINE
  7 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum DeviceTypeEnum {
  4 + GATEWAY,
  5 + DIRECT_CONNECTION,
  6 + SENSOR
  7 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum MenuTypeEnum {
  4 + SYSADMIN,
  5 + CUSTOM
  6 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +/** 消息类型枚举值 */
  4 +public enum MessageTypeEnum {
  5 + EMAIL_MESSAGE,
  6 + PHONE_MESSAGE,
  7 + DING_TALK_MESSAGE,
  8 + WECHAT_MESSAGE
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum MsgTemplatePurposeEnum {
  4 + FOR_LOGIN,
  5 + FOR_FORGET_PASSWORD,
  6 + FOR_SET_PASSWORD,
  7 + FOR_ALARM_NOTICE,
  8 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum OrderTypeEnum {
  4 + ASC,
  5 + DESC
  6 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum RateLimitType {
  4 + /**
  5 + * 对所有请求进行限制
  6 + */
  7 + ALL,
  8 + /**
  9 + * 根据登录的用户限制
  10 + */
  11 + USER,
  12 + /**
  13 + * 根据IP限制
  14 + */
  15 + IP
  16 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +/** 请求响应枚举值 */
  4 +public enum ResponseCodeEnum {
  5 + SUCCESS,
  6 + FAILED,
  7 + SENDING,
  8 + OK
  9 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +public enum RoleEnum {
  4 + /**
  5 + * 超级管理员
  6 + */
  7 + ROLE_SYS_ADMIN,
  8 + /**
  9 + * 租户管理员
  10 + */
  11 + ROLE_TENANT_ADMIN,
  12 + /**
  13 + * 租户下普通用户
  14 + */
  15 + ROLE_NORMAL_USER,
  16 + /**
  17 + * 平台系统管理员
  18 + */
  19 + ROLE_PLATFORM_ADMIN;
  20 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +/** 短信平台枚举值 */
  4 +public enum SmsProviderTypeEnum {
  5 + ALI_CLOUD,
  6 + TENCENT_CLOUD
  7 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +/** 租户状态 */
  4 +public enum TenantStatusEnum {
  5 + NORMAL,
  6 + DISABLED,
  7 + EXPIRED
  8 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.enums;
  2 +
  3 +/** 用户状态 */
  4 +public enum UserStatusEnum {
  5 + NORMAL,
  6 + DISABLED,
  7 + EXPIRED
  8 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils;
  2 +
  3 +import org.springframework.core.annotation.AliasFor;
  4 +
  5 +import java.lang.annotation.*;
  6 +
  7 +/** 表示这个是一个<em>演示</em>,这不是一个正式方法,参照写法完成以后,请删掉demo的方法或者字段演示 */
  8 +@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
  9 +@Retention(RetentionPolicy.SOURCE)
  10 +@Documented
  11 +public @interface Demo {
  12 + String value() default "";
  13 +
  14 + @AliasFor(attribute = "value")
  15 + String description() default "";
  16 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils;
  2 +
  3 +import com.alibaba.excel.EasyExcel;
  4 +import org.apache.commons.lang3.StringUtils;
  5 +import org.springframework.beans.BeanUtils;
  6 +
  7 +import javax.servlet.http.HttpServletResponse;
  8 +import java.io.IOException;
  9 +import java.net.URLEncoder;
  10 +import java.nio.charset.StandardCharsets;
  11 +import java.time.LocalDateTime;
  12 +import java.time.format.DateTimeFormatter;
  13 +import java.util.ArrayList;
  14 +import java.util.List;
  15 +
  16 +public class ExcelUtil {
  17 + private ExcelUtil() {}
  18 +
  19 + public static void exportExcel(
  20 + HttpServletResponse response,
  21 + String fileName,
  22 + String sheetName,
  23 + List<?> list,
  24 + Class<?> pojoClass)
  25 + throws IOException {
  26 + if (StringUtils.isBlank(fileName)) {
  27 + fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
  28 + }
  29 +
  30 + response.setContentType("application/vnd.ms-excel");
  31 + response.setCharacterEncoding("UTF-8");
  32 + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
  33 + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
  34 + EasyExcel.write(response.getOutputStream(), pojoClass).sheet(sheetName).doWrite(list);
  35 + }
  36 +
  37 + @SuppressWarnings("all")
  38 + public static void exportExcelToTarget(
  39 + HttpServletResponse response,
  40 + String fileName,
  41 + String sheetName,
  42 + List<?> sourceList,
  43 + Class<?> targetClass)
  44 + throws Exception {
  45 + List<Object> targetList = new ArrayList<>(sourceList.size());
  46 +
  47 + for (Object source : sourceList) {
  48 + Object target = targetClass.newInstance();
  49 + BeanUtils.copyProperties(source, target);
  50 + targetList.add(target);
  51 + }
  52 +
  53 + exportExcel(response, fileName, sheetName, targetList, targetClass);
  54 + }
  55 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5 + * except in compliance with the License. You may obtain a copy of the License at
  6 + *
  7 + * <p>http://www.apache.org/licenses/LICENSE-2.0
  8 + *
  9 + * <p>Unless required by applicable law or agreed to in writing, software distributed under the
  10 + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  11 + * express or implied. See the License for the specific language governing permissions and
  12 + * limitations under the License.
  13 + */
  14 +package org.thingsboard.server.common.data.yunteng.utils;
  15 +
  16 +import com.fasterxml.jackson.core.JsonProcessingException;
  17 +import com.fasterxml.jackson.core.type.TypeReference;
  18 +import com.fasterxml.jackson.databind.DeserializationFeature;
  19 +import com.fasterxml.jackson.databind.JsonNode;
  20 +import com.fasterxml.jackson.databind.ObjectMapper;
  21 +import com.fasterxml.jackson.databind.node.ObjectNode;
  22 +
  23 +import java.io.IOException;
  24 +import java.util.Arrays;
  25 +
  26 +public class JacksonUtil {
  27 +
  28 + public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  29 +
  30 + static {
  31 + OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
  32 + }
  33 +
  34 + public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
  35 + try {
  36 + return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueType) : null;
  37 + } catch (IllegalArgumentException e) {
  38 + throw new IllegalArgumentException(
  39 + "The given object value: " + fromValue + " cannot be converted to " + toValueType, e);
  40 + }
  41 + }
  42 +
  43 + public static <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef) {
  44 + try {
  45 + return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueTypeRef) : null;
  46 + } catch (IllegalArgumentException e) {
  47 + throw new IllegalArgumentException(
  48 + "The given object value: " + fromValue + " cannot be converted to " + toValueTypeRef, e);
  49 + }
  50 + }
  51 +
  52 + public static <T> T fromString(String string, Class<T> clazz) {
  53 + try {
  54 + return string != null ? OBJECT_MAPPER.readValue(string, clazz) : null;
  55 + } catch (IOException e) {
  56 + throw new IllegalArgumentException(
  57 + "The given string value: " + string + " cannot be transformed to Json object", e);
  58 + }
  59 + }
  60 +
  61 + public static <T> T fromString(String string, TypeReference<T> valueTypeRef) {
  62 + try {
  63 + return string != null ? OBJECT_MAPPER.readValue(string, valueTypeRef) : null;
  64 + } catch (IOException e) {
  65 + throw new IllegalArgumentException(
  66 + "The given string value: " + string + " cannot be transformed to Json object", e);
  67 + }
  68 + }
  69 +
  70 + public static <T> T fromBytes(byte[] bytes, Class<T> clazz) {
  71 + try {
  72 + return bytes != null ? OBJECT_MAPPER.readValue(bytes, clazz) : null;
  73 + } catch (IOException e) {
  74 + throw new IllegalArgumentException(
  75 + "The given string value: "
  76 + + Arrays.toString(bytes)
  77 + + " cannot be transformed to Json object",
  78 + e);
  79 + }
  80 + }
  81 +
  82 + public static JsonNode fromBytes(byte[] bytes) {
  83 + try {
  84 + return OBJECT_MAPPER.readTree(bytes);
  85 + } catch (IOException e) {
  86 + throw new IllegalArgumentException(
  87 + "The given byte[] value: "
  88 + + Arrays.toString(bytes)
  89 + + " cannot be transformed to Json object",
  90 + e);
  91 + }
  92 + }
  93 +
  94 + public static String toString(Object value) {
  95 + try {
  96 + return value != null ? OBJECT_MAPPER.writeValueAsString(value) : null;
  97 + } catch (JsonProcessingException e) {
  98 + throw new IllegalArgumentException(
  99 + "The given Json object value: " + value + " cannot be transformed to a String", e);
  100 + }
  101 + }
  102 +
  103 + public static JsonNode toJsonNode(String value) {
  104 + if (value == null || value.isEmpty()) {
  105 + return null;
  106 + }
  107 + try {
  108 + return OBJECT_MAPPER.readTree(value);
  109 + } catch (IOException e) {
  110 + throw new IllegalArgumentException(e);
  111 + }
  112 + }
  113 +
  114 + public static ObjectNode newObjectNode() {
  115 + return OBJECT_MAPPER.createObjectNode();
  116 + }
  117 +
  118 + public static <T> T clone(T value) {
  119 + @SuppressWarnings("unchecked")
  120 + Class<T> valueClass = (Class<T>) value.getClass();
  121 + return fromString(toString(value), valueClass);
  122 + }
  123 +
  124 + public static <T> JsonNode valueToTree(T value) {
  125 + return OBJECT_MAPPER.valueToTree(value);
  126 + }
  127 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.springframework.beans.BeanUtils;
  5 +
  6 +import java.lang.reflect.Constructor;
  7 +import java.lang.reflect.Field;
  8 +import java.util.ArrayList;
  9 +import java.util.Arrays;
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +
  13 +@Slf4j
  14 +public class ReflectUtils {
  15 +
  16 + public static <T> Constructor<?> getEmptyParameterConstructor(Class<T> clazz) {
  17 + Constructor<?> constructor = null;
  18 + Constructor<?>[] constructors = clazz.getConstructors();
  19 + for (Constructor<?> con : constructors) {
  20 + if (con.getParameterCount() == 0) {
  21 + constructor = con;
  22 + break;
  23 + }
  24 + }
  25 + return constructor;
  26 + }
  27 +
  28 + @SuppressWarnings("unchecked")
  29 + public static <T> List<T> sourceToTarget(
  30 + Collection<?> sourceList, Class<T> target, String... ignoreProperties) {
  31 + if (sourceList == null) {
  32 + return null;
  33 + }
  34 +
  35 + List<T> targetList = new ArrayList<>(sourceList.size());
  36 + Constructor<?> constructor = getEmptyParameterConstructor(target);
  37 + if (constructor != null) {
  38 + try {
  39 + for (Object source : sourceList) {
  40 + T targetObject = (T) constructor.newInstance();
  41 + BeanUtils.copyProperties(source, targetObject, ignoreProperties);
  42 + targetList.add(targetObject);
  43 + }
  44 + } catch (Exception e) {
  45 + log.error("convert error ", e);
  46 + }
  47 + }
  48 + return targetList;
  49 + }
  50 +
  51 +
  52 + /**
  53 + * 获取类的所有属性,包含父类的【public private protected】
  54 + * @param clazz 不确定类型
  55 + * @return 返回List<Field>
  56 + */
  57 + public static List<Field> getAllDeclaredFields(Class<?> clazz){
  58 + List<Field> fieldList = new ArrayList<>();
  59 + for (;clazz !=null;clazz=clazz.getSuperclass()){
  60 + fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
  61 + }
  62 + return fieldList;
  63 + }
  64 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils;
  2 +
  3 +import javax.servlet.http.HttpServletRequest;
  4 +
  5 +public class RequestUtils {
  6 + public static String getClientIpAddr(HttpServletRequest request) {
  7 + String ip = request.getHeader("X-Forwarded-For");
  8 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  9 + ip = request.getHeader("Proxy-Client-IP");
  10 + }
  11 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  12 + ip = request.getHeader("WL-Proxy-Client-IP");
  13 + }
  14 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  15 + ip = request.getHeader("HTTP_CLIENT_IP");
  16 + }
  17 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  18 + ip = request.getHeader("HTTP_X_FORWARDED_FOR");
  19 + }
  20 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  21 + ip = request.getRemoteAddr();
  22 + }
  23 + return ip;
  24 + }
  25 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils.tools;
  2 +
  3 +import lombok.Data;
  4 +import lombok.NoArgsConstructor;
  5 +
  6 +import java.io.Serializable;
  7 +import java.util.Collection;
  8 +
  9 +@Data
  10 +@NoArgsConstructor
  11 +public class PageData<T> implements Serializable {
  12 + private static final long serialVersionUID = -5385636733740491124L;
  13 + private int total;
  14 + private Collection<T> items;
  15 +
  16 + public PageData(Collection<T> list, long total) {
  17 + this.items = list;
  18 + this.total = (int) total;
  19 + }
  20 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils.tools;
  2 +
  3 +import lombok.Data;
  4 +import lombok.NoArgsConstructor;
  5 +import org.springframework.http.HttpStatus;
  6 +
  7 +import java.io.Serializable;
  8 +
  9 +@Data
  10 +@NoArgsConstructor
  11 +public class ResponseResult<T> implements Serializable {
  12 +
  13 + private static final long serialVersionUID = -8043533414600873987L;
  14 +
  15 + /**
  16 + * 状态码
  17 + */
  18 + private Integer code;
  19 +
  20 + /**
  21 + * 消息
  22 + */
  23 + private String message;
  24 +
  25 + /**
  26 + * 数据
  27 + */
  28 + private T data;
  29 +
  30 + /**
  31 + * 成功返回数据
  32 + * @param message 消息
  33 + * @return Result<T>
  34 + */
  35 + public static <T> ResponseResult<T> success(String message){
  36 + ResponseResult<T> responseResult = new ResponseResult<>();
  37 + responseResult.setMessage(message);
  38 + responseResult.setCode(HttpStatus.OK.value());
  39 + return responseResult;
  40 + }
  41 +
  42 + /**
  43 + * 成功返回数据
  44 + * @param data 数据
  45 + * @return Result<T>
  46 + */
  47 + public static <T> ResponseResult<T> success(T data){
  48 + ResponseResult<T> responseResult = new ResponseResult<>();
  49 + responseResult.setCode(HttpStatus.OK.value());
  50 + responseResult.setMessage(HttpStatus.OK.getReasonPhrase());
  51 + responseResult.setData(data);
  52 + return responseResult;
  53 + }
  54 +
  55 + /**
  56 + * 失败返回数据
  57 + * @param message 消息
  58 + * @return Result<T>
  59 + */
  60 + public static <T> ResponseResult<T> failed(String message){
  61 + ResponseResult<T> responseResult = new ResponseResult<>();
  62 + responseResult.setMessage(message);
  63 + responseResult.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
  64 + return responseResult;
  65 + }
  66 +
  67 + /**
  68 + * 失败返回数据
  69 + * @param code 状态码
  70 + * @param message 消息
  71 + * @return Result<T>
  72 + */
  73 + public static <T> ResponseResult<T> failed(int code, String message){
  74 + ResponseResult<T> responseResult = new ResponseResult<>();
  75 + responseResult.setMessage(message);
  76 + responseResult.setCode(code);
  77 + return responseResult;
  78 + }
  79 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils.tools;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonProperty;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +import org.thingsboard.common.util.JacksonUtil;
  7 +
  8 +import java.io.Serializable;
  9 +import java.util.ArrayList;
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +
  13 +@Data
  14 +@NoArgsConstructor
  15 +public class TBPageData<T> implements Serializable {
  16 +
  17 + private static final long serialVersionUID = -914237744254466700L;
  18 +
  19 + private Collection<T> data;
  20 + private int totalPages;
  21 + private long totalElements;
  22 +
  23 + @JsonProperty("hasNext")
  24 + private boolean hasNext;
  25 +
  26 + public TBPageData(Collection<T> data, int totalPages, long totalElements, boolean hasNext) {
  27 + this.data = data;
  28 + this.totalPages = totalPages;
  29 + this.totalElements = totalElements;
  30 + this.hasNext = hasNext;
  31 + }
  32 +
  33 + public <D> TBPageData<D> getPageData(TBPageData<T> data, Class<D> target){
  34 + List<D> targetList = new ArrayList<>();
  35 + for(T t:data.getData()){
  36 + targetList.add(JacksonUtil.convertValue(t,target));
  37 + }
  38 + return new TBPageData<>(targetList,data.totalPages,data.totalElements,data.hasNext);
  39 + }
  40 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils.tree;
  2 +
  3 +import java.util.List;
  4 +
  5 +public interface TreeDTO<T> extends Comparable<T> {
  6 + String getParentId();
  7 +
  8 + String getId();
  9 +
  10 + List<T> getChildren();
  11 +}
... ...
  1 +package org.thingsboard.server.common.data.yunteng.utils.tree;
  2 +
  3 +import com.google.common.collect.Lists;
  4 +import com.google.common.collect.Sets;
  5 +
  6 +import java.util.*;
  7 +
  8 +public class TreeUtils {
  9 + public static <T extends TreeDTO<T>> List<T> buildTree(List<T> treeList) {
  10 + Map<String, T> dtoMap = new LinkedHashMap<>(treeList.size());
  11 + HashSet<T> dtoSet = Sets.newHashSet(treeList);
  12 + dtoSet.forEach(dto -> dtoMap.put(dto.getId(), dto));
  13 + List<T> result = Lists.newArrayList();
  14 + for (T node : dtoMap.values()) {
  15 + T parent = dtoMap.get(node.getParentId());
  16 + if (parent != null && !(node.getId().equals(parent.getId()))) {
  17 + parent.getChildren().add(node);
  18 + continue;
  19 + }
  20 + result.add(node);
  21 + }
  22 + Collections.sort(result);
  23 + result.forEach(node -> Collections.sort(node.getChildren()));
  24 + return result;
  25 + }
  26 +}
... ...
... ... @@ -246,6 +246,13 @@
246 246 <groupId>org.eclipse.leshan</groupId>
247 247 <artifactId>leshan-core</artifactId>
248 248 </dependency>
  249 +
  250 + <!--mybatis-->
  251 + <dependency>
  252 + <groupId>com.baomidou</groupId>
  253 + <artifactId>mybatis-plus-boot-starter</artifactId>
  254 + <version>${mybatis-plus.version}</version>
  255 + </dependency>
249 256 </dependencies>
250 257 <build>
251 258 <plugins>
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = false)
  12 +@TableName(ModelConstants.Table.ADMIN_SETTING_TABLE_NAME)
  13 +public class AdminSetting extends BaseEntity {
  14 +
  15 + private static final long serialVersionUID = -881433375246560135L;
  16 +
  17 + private String configJson;
  18 + private String key;
  19 + private LocalDateTime createTime;
  20 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.FieldFill;
  4 +import com.baomidou.mybatisplus.annotation.TableField;
  5 +import com.baomidou.mybatisplus.annotation.TableName;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +/**
  13 + * @Description
  14 + * @Author cxy 告警联系人实体表
  15 + * @Date 2021/11/2 11:17
  16 + */
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@TableName(ModelConstants.Table.IOTFS_ALARM_CONTACT_TABLE_NAME)
  20 +public class AlarmContact extends TenantBaseEntity{
  21 +
  22 + private static final long serialVersionUID= -3982884827995610164L;
  23 +
  24 + private String username;
  25 +
  26 + private String organizationId;
  27 +
  28 +
  29 + private String phone;
  30 +
  31 + private String email;
  32 +
  33 + private String wechat;
  34 + private String dingtalk;
  35 +
  36 + private String remark;
  37 +
  38 + private String addPeople;
  39 +
  40 + private String tenantCode;
  41 +
  42 + @TableField(fill = FieldFill.INSERT)
  43 + private LocalDateTime createTime;
  44 +
  45 + private String creator;
  46 +
  47 + private String updater;
  48 +
  49 + @TableField(fill = FieldFill.UPDATE)
  50 + private LocalDateTime updateTime;
  51 +
  52 +
  53 +
  54 +
  55 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@TableName(ModelConstants.Table.IOTFS_ALARM_PROFILE_TABLE_NAME)
  11 +public class AlarmProfile extends TenantBaseEntity {
  12 +
  13 + private static final long serialVersionUID = -4922707705163155569L;
  14 + private String alarmContactId;
  15 + private String deviceProfileId;
  16 + private String messageMode;
  17 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.FieldFill;
  4 +import com.baomidou.mybatisplus.annotation.TableField;
  5 +import lombok.Getter;
  6 +import lombok.Setter;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Getter
  11 +@Setter
  12 +public class AuditRelatedEntity extends BaseEntity {
  13 +
  14 + private static final long serialVersionUID = -5865650870569216315L;
  15 +
  16 + @TableField(fill = FieldFill.INSERT)
  17 + private String creator;
  18 +
  19 + @TableField(fill = FieldFill.INSERT)
  20 + private LocalDateTime createTime;
  21 +
  22 + @TableField(fill = FieldFill.INSERT_UPDATE)
  23 + private String updater;
  24 +
  25 + @TableField(fill = FieldFill.INSERT_UPDATE)
  26 + private LocalDateTime updateTime;
  27 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.IdType;
  4 +import com.baomidou.mybatisplus.annotation.TableId;
  5 +import com.fasterxml.jackson.annotation.JsonIgnore;
  6 +import lombok.Getter;
  7 +import lombok.Setter;
  8 +import org.springframework.beans.BeanUtils;
  9 +import org.thingsboard.server.common.data.yunteng.core.exception.DTOCreationException;
  10 +import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
  11 +
  12 +import java.io.Serializable;
  13 +import java.lang.reflect.Constructor;
  14 +import java.lang.reflect.InvocationTargetException;
  15 +
  16 +@Getter
  17 +@Setter
  18 +public class BaseEntity implements Serializable {
  19 + private static final long serialVersionUID = 8948437944054606982L;
  20 +
  21 + @TableId(type = IdType.ASSIGN_UUID)
  22 + private String id;
  23 +
  24 + @JsonIgnore
  25 + public <T> void copyToDTO(T dto, String... ignoreProperties) {
  26 + BeanUtils.copyProperties(this, dto, ignoreProperties);
  27 + }
  28 +
  29 + @JsonIgnore
  30 + @SuppressWarnings("unchecked")
  31 + public <T> T getDTO(Class<T> clazz) {
  32 + Constructor<?> constructor = ReflectUtils.getEmptyParameterConstructor(clazz);
  33 + if (constructor != null) {
  34 + try {
  35 + T t = (T) constructor.newInstance();
  36 + BeanUtils.copyProperties(this, t);
  37 + return t;
  38 + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
  39 + throw new DTOCreationException(
  40 + "try to get dto from class [" + clazz.getName() + "] failed " + e.getMessage());
  41 + }
  42 + } else {
  43 + throw new DTOCreationException("try to get dto from class [" + clazz.getName() + "] failed");
  44 + }
  45 + }
  46 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@TableName(ModelConstants.Table.IOTFS_DEVICE_TYPE_TABLE_NAME)
  11 +public class DeviceType extends TenantBaseEntity {
  12 +
  13 + private static final long serialVersionUID = -3777232331298040322L;
  14 +
  15 + private String name;
  16 +
  17 + private String parentId;
  18 +
  19 + private String path;
  20 +
  21 + private Integer sort;
  22 +
  23 + private String description;
  24 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableField;
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  10 +
  11 +import java.time.LocalDateTime;
  12 +
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = false)
  15 +@TableName(value = ModelConstants.Table.MAIL_LOG_TABLE_NAME,autoResultMap = true)
  16 +public class MailLog extends BaseEntity {
  17 + private static final long serialVersionUID = -8847842025838559296L;
  18 +
  19 + /** 发件人 */
  20 + private String emailFrom;
  21 +
  22 + /** 收件人 */
  23 + @TableField(typeHandler = JacksonTypeHandler.class)
  24 + private JsonNode emailTo;
  25 +
  26 + /** 抄送人 */
  27 + @TableField(typeHandler = JacksonTypeHandler.class)
  28 + private JsonNode emailCc;
  29 +
  30 + /** 密送人 */
  31 + @TableField(typeHandler = JacksonTypeHandler.class)
  32 + private JsonNode emailBcc;
  33 +
  34 + /** 邮件主题 */
  35 + private String emailSubject;
  36 +
  37 + /** 邮件内容 */
  38 + private String emailBody;
  39 +
  40 + /** 状态:ResponseCodeEnum枚举值 */
  41 + private String status;
  42 +
  43 + /** 发送时间 */
  44 + private LocalDateTime sendTime;
  45 +
  46 + /** 租户Code */
  47 + private String tenantCode;
  48 +
  49 + /** 模板ID */
  50 + private String messageTemplateId;
  51 +
  52 + /**备注*/
  53 + private String remark;
  54 +
  55 + /**用途*/
  56 + private String templatePurpose;
  57 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableField;
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  10 +import org.thingsboard.server.common.data.yunteng.enums.MenuTypeEnum;
  11 +
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@TableName(ModelConstants.Table.MENU_TABLE_NAME)
  15 +public class Menu extends TenantBaseEntity {
  16 +
  17 + private static final long serialVersionUID = 6319718763792214142L;
  18 + private String name;
  19 +
  20 + private String parentId;
  21 +
  22 + private String path;
  23 +
  24 + private MenuTypeEnum type;
  25 +
  26 + private String permission;
  27 +
  28 + private Integer sort;
  29 +
  30 + @TableField(typeHandler = JacksonTypeHandler.class)
  31 + private JsonNode meta;
  32 +
  33 + private String alias;
  34 +
  35 + private String redirect;
  36 +
  37 + private Boolean caseSensitive;
  38 +
  39 + private String component;
  40 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableField;
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  10 +
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@TableName(value = ModelConstants.Table.MESSAGE_CONFIG_TABLE_NAME,autoResultMap = true)
  14 +public class MessageConfig extends TenantBaseEntity {
  15 +
  16 + private static final long serialVersionUID = -3624943194108704138L;
  17 +
  18 + /** 配置名称 */
  19 + private String configName;
  20 +
  21 + /** 平台类型 */
  22 + private String platformType;
  23 +
  24 + /** 消息类型 */
  25 + private String messageType;
  26 +
  27 + /** json配置 */
  28 + @TableField(typeHandler = JacksonTypeHandler.class)
  29 + private JsonNode config;
  30 +
  31 + /** 状态:0禁用 1启用 */
  32 + private Integer status;
  33 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@TableName(ModelConstants.Table.MESSAGE_TEMPLATE_TABLE_NAME)
  11 +public class MessageTemplate extends TenantBaseEntity {
  12 +
  13 + private static final long serialVersionUID = 6347635507829273091L;
  14 +
  15 + /** 模板名称 */
  16 + private String templateName;
  17 +
  18 + /** 模板签名 */
  19 + private String signName;
  20 +
  21 + /** 模板CODE */
  22 + private String templateCode;
  23 +
  24 + /** 消息配置 */
  25 + private String messageConfigId;
  26 +
  27 + /** 模板用途 */
  28 + private String templatePurpose;
  29 +
  30 + /** 消息类型 */
  31 + private String messageType;
  32 +
  33 + /** 状态:0禁用 1启用 */
  34 + private Integer status;
  35 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@TableName(ModelConstants.Table.IOTFS_ORGANIZATION_TABLE_NAME)
  11 +public class Organization extends TenantBaseEntity {
  12 + private String parentId;
  13 + private String name;
  14 + private int sort;
  15 + private String remark;
  16 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  6 +import org.thingsboard.server.common.data.yunteng.core.RequestMethod;
  7 +import org.thingsboard.server.common.data.yunteng.enums.RateLimitType;
  8 +
  9 +import java.time.LocalTime;
  10 +
  11 +@Data
  12 +@TableName(ModelConstants.Table.RATE_LIMIT_TABLE_NAME)
  13 +public class RateLimiterEntity {
  14 + private String id;
  15 + private String path;
  16 + private double qps;
  17 + private RateLimitType rateLimitType;
  18 + private boolean enabled;
  19 + private LocalTime enableTime;
  20 + private LocalTime endTime;
  21 + private RequestMethod requestMethod;
  22 + private Integer sort;
  23 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = false)
  10 +@TableName(ModelConstants.Table.ROLE_TABLE_NAME)
  11 +public class Role extends TenantBaseEntity {
  12 +
  13 + private static final long serialVersionUID = 3915852360063998830L;
  14 + private String name;
  15 +
  16 + private String remark;
  17 +
  18 + private String roleType;
  19 +
  20 + private String code;
  21 +
  22 + private boolean enabled = true;
  23 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.FieldFill;
  4 +import com.baomidou.mybatisplus.annotation.TableField;
  5 +import com.baomidou.mybatisplus.annotation.TableName;
  6 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  7 +import com.fasterxml.jackson.databind.JsonNode;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  11 +
  12 +import java.time.LocalDateTime;
  13 +
  14 +@Data
  15 +@EqualsAndHashCode(callSuper = false)
  16 +@TableName(value = ModelConstants.Table.SMS_LOG_TABLE_NAME,autoResultMap = true)
  17 +public class SmsLog extends BaseEntity {
  18 +
  19 + private static final long serialVersionUID = 2778820322396894328L;
  20 +
  21 + /** 短信平台类型 */
  22 + private String type;
  23 +
  24 + /** 发送状态:ResponseCodeEnum枚举值 */
  25 + private String status;
  26 +
  27 + /** 发送时间 */
  28 + @TableField(fill = FieldFill.INSERT)
  29 + private LocalDateTime sendTime;
  30 +
  31 + /** 发送手机号 */
  32 + private String toPhone;
  33 +
  34 + /** 发送模板参数 */
  35 + @TableField(typeHandler = JacksonTypeHandler.class)
  36 + private JsonNode templateParam;
  37 +
  38 + /** 租户Code */
  39 + private String tenantCode;
  40 +
  41 + /** 模板ID */
  42 + private String messageTemplateId;
  43 +
  44 + /**用途*/
  45 + private String templatePurpose;
  46 +
  47 + /**备注*/
  48 + private String remark;
  49 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@TableName(ModelConstants.Table.DEPT_TABLE_NAME)
  11 +public class SysDept extends TenantBaseEntity {
  12 +
  13 +
  14 + private static final long serialVersionUID = -7160697827758883893L;
  15 + private String deptName;
  16 +
  17 + private String parentId;
  18 +
  19 + private Integer orderNo;
  20 +
  21 +
  22 + private String remark;
  23 + private Integer status;
  24 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = false)
  10 +@TableName(ModelConstants.Table.DICT_TABLE_NAME)
  11 +public class SysDict extends TenantBaseEntity {
  12 +
  13 + private static final long serialVersionUID = -5381101569947327544L;
  14 +
  15 + /** 字典名称 */
  16 + private String dictName;
  17 +
  18 + /** 字典编码 */
  19 + private String dictCode;
  20 +
  21 + /** 字典描述 */
  22 + private String description;
  23 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.RequiredArgsConstructor;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +@Data
  9 +@RequiredArgsConstructor
  10 +@TableName(ModelConstants.Table.DICT_ITEM_TABLE_NAME)
  11 +public class SysDictItem extends TenantBaseEntity {
  12 +
  13 + private static final long serialVersionUID = 9177617160310722864L;
  14 + /** 字典id */
  15 + private String dictId;
  16 +
  17 + /** 字典项文本 */
  18 + private String itemText;
  19 +
  20 + /** 字典值 */
  21 + private String itemValue;
  22 +
  23 + /** 描述 */
  24 + private String description;
  25 +
  26 + /** 排序 */
  27 + private Integer sort;
  28 +
  29 + /** 状态 */
  30 + private Integer status;
  31 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = false)
  12 +@TableName(ModelConstants.Table.TENANT_TABLE_NAME)
  13 +public class Tenant extends AuditRelatedEntity {
  14 +
  15 + private static final long serialVersionUID = 4848421848961008112L;
  16 + private String name;
  17 +
  18 + private String tenantCode;
  19 +
  20 + private String icon;
  21 +
  22 + private boolean enabled = true;
  23 +
  24 + private String description;
  25 +
  26 + private String defaultConfig;
  27 +
  28 + private LocalDateTime tenantExpireTime;
  29 +
  30 + /** TB的租户ID */
  31 + private String tenantId;
  32 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.FieldFill;
  4 +import com.baomidou.mybatisplus.annotation.TableField;
  5 +import lombok.Getter;
  6 +import lombok.Setter;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Getter
  11 +@Setter
  12 +public class TenantBaseEntity extends BaseEntity {
  13 +
  14 + private static final long serialVersionUID = -4315734960161684909L;
  15 +
  16 + private String tenantCode;
  17 +
  18 + @TableField(fill = FieldFill.INSERT)
  19 + private String creator;
  20 +
  21 + @TableField(fill = FieldFill.UPDATE)
  22 + private String updater;
  23 +
  24 + @TableField(fill = FieldFill.INSERT)
  25 + private LocalDateTime createTime;
  26 +
  27 + @TableField(fill = FieldFill.UPDATE)
  28 + private LocalDateTime updateTime;
  29 +
  30 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +import java.io.Serializable;
  9 +
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = false)
  12 +@TableName(ModelConstants.Table.TENANT_MENU_TABLE_NAME)
  13 +public class TenantMenu implements Serializable {
  14 + private static final long serialVersionUID = -8775371485677702427L;
  15 + /** 菜单ID */
  16 + private String menuId;
  17 + /** 租户ID */
  18 + private String tenantCode;
  19 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +import java.io.Serializable;
  9 +
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = false)
  12 +@TableName(ModelConstants.Table.TENANT_ROLE_TABLE_NAME)
  13 +public class TenantRole implements Serializable {
  14 +
  15 + private static final long serialVersionUID = 7332631758506821892L;
  16 + /** 角色ID */
  17 + private String roleId;
  18 + /** 租户ID */
  19 + private String tenantCode;
  20 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.FieldStrategy;
  4 +import com.baomidou.mybatisplus.annotation.TableField;
  5 +import com.baomidou.mybatisplus.annotation.TableName;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +/** user是所有可登录系统用户 */
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = false)
  15 +@TableName(ModelConstants.Table.USER_TABLE_NAME)
  16 +public class User extends TenantBaseEntity {
  17 + private static final long serialVersionUID = 834982016421849497L;
  18 + private String username;
  19 +
  20 + private String realName;
  21 +
  22 + private String password;
  23 +
  24 + @TableField(updateStrategy = FieldStrategy.IGNORED)
  25 + private String activateToken;
  26 +
  27 + private String phoneNumber;
  28 +
  29 + private String email;
  30 +
  31 + private String avatar;
  32 +
  33 + private boolean enabled = true;
  34 +
  35 + private LocalDateTime accountExpireTime;
  36 +
  37 + private String deptId;
  38 +
  39 + /** 0:超级管理员;1:租户账号;2:租户下的账号 */
  40 + private Integer level;
  41 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  8 +
  9 +@Data
  10 +@AllArgsConstructor
  11 +@NoArgsConstructor
  12 +@TableName(ModelConstants.Table.IOTFS_USER_ORGANIZATION_MAPPING_TABLE_NAME)
  13 +public class UserOrganizationMapping {
  14 + private String userId;
  15 + private String organizationId;
  16 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  7 +
  8 +import java.io.Serializable;
  9 +
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = false)
  12 +@TableName(ModelConstants.Table.USER_ROLE_TABLE_NAME)
  13 +public class UserRole implements Serializable {
  14 +
  15 + private static final long serialVersionUID = -1018514294019250455L;
  16 +
  17 + /** 用户ID */
  18 + private String userId;
  19 + /** 角色ID */
  20 + private String roleId;
  21 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.entities;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableField;
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  10 +import org.thingsboard.server.common.data.yunteng.enums.DeviceCredentialsEnum;
  11 +import org.thingsboard.server.common.data.yunteng.enums.DeviceState;
  12 +import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
  13 +
  14 +import java.time.LocalDateTime;
  15 +
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@TableName(value = ModelConstants.Table.IOTFS_DEVICE_TABLE_NAME)
  19 +public class YtDevice extends TenantBaseEntity {
  20 + private String name;
  21 +
  22 + @TableField(typeHandler = JacksonTypeHandler.class)
  23 + private JsonNode deviceInfo;
  24 +
  25 + private LocalDateTime activeTime;
  26 + private DeviceState deviceState;
  27 + private String profileId;
  28 + private String deviceToken;
  29 + private String tbDeviceId;
  30 + private String deviceTypeId;
  31 + private LocalDateTime lastConnectTime;
  32 + private String label;
  33 + private DeviceTypeEnum deviceType;
  34 + private DeviceCredentialsEnum deviceCredentials;
  35 + private String organizationId;
  36 + /** 告警状态:0:正常 1:告警 */
  37 + private Integer alarmStatus;
  38 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import lombok.RequiredArgsConstructor;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.apache.commons.lang3.RandomStringUtils;
  6 +import org.springframework.stereotype.Service;
  7 +import org.thingsboard.server.common.data.yunteng.common.CommonService;
  8 +import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
  9 +import org.thingsboard.server.common.data.yunteng.dto.SysDictItemDTO;
  10 +import org.thingsboard.server.dao.yunteng.mapper.SysDictItemMapper;
  11 +import org.thingsboard.server.dao.yunteng.service.YtDeviceService;
  12 +
  13 +@Slf4j
  14 +@Service
  15 +@RequiredArgsConstructor
  16 +public class CommonServiceImpl implements CommonService {
  17 +
  18 + private final SysDictItemMapper sysDictItemMapper;
  19 + private final YtDeviceService deviceService;
  20 + @Override
  21 + public SysDictItemDTO getDictValueByCodeAndText(String dictCode, String codeValue) {
  22 + return sysDictItemMapper.getDictValueByCodeAndText(dictCode, codeValue);
  23 + }
  24 +
  25 + @Override
  26 + public String generateDeviceToken(String tenantId) {
  27 + String deviceToken = RandomStringUtils.randomAlphabetic(20);
  28 + DeviceDTO deviceDTO = new DeviceDTO();
  29 + deviceDTO.setDeviceToken(deviceToken);
  30 + //检查数据库是否已存在对应的DeviceToken
  31 + if(deviceService.findDeviceInfo(tenantId,deviceDTO).size()>0){
  32 + generateDeviceToken(tenantId);
  33 + }
  34 + return deviceToken;
  35 + }
  36 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4 +import com.google.common.collect.Lists;
  5 +import com.google.common.collect.Sets;
  6 +import lombok.RequiredArgsConstructor;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.apache.commons.lang3.StringUtils;
  9 +import org.springframework.http.HttpStatus;
  10 +import org.springframework.security.access.AccessDeniedException;
  11 +import org.springframework.stereotype.Service;
  12 +import org.springframework.transaction.annotation.Transactional;
  13 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  14 +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils;
  15 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  16 +import org.thingsboard.server.common.data.yunteng.core.exception.FastIotException;
  17 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  18 +import org.thingsboard.server.common.data.yunteng.dto.MenuDTO;
  19 +import org.thingsboard.server.common.data.yunteng.enums.MenuTypeEnum;
  20 +import org.thingsboard.server.dao.yunteng.entities.Menu;
  21 +import org.thingsboard.server.dao.yunteng.mapper.MenuMapper;
  22 +import org.thingsboard.server.dao.yunteng.mapper.RoleMapper;
  23 +import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
  24 +import org.thingsboard.server.dao.yunteng.service.MenuService;
  25 +
  26 +import java.util.*;
  27 +
  28 +@Service
  29 +@Slf4j
  30 +@RequiredArgsConstructor
  31 +public class MenuServiceImpl extends AbstractBaseService<MenuMapper, Menu> implements MenuService {
  32 +
  33 + private final RoleMapper roleMapper;
  34 + private final CacheUtils cacheUtils;
  35 +
  36 + @Override
  37 + public List<MenuDTO> getAllMenus(String tenantId) {
  38 +
  39 + List<Menu> menus =
  40 + baseMapper.selectList(
  41 + new QueryWrapper<Menu>().lambda().eq(Menu::getTenantCode, tenantId));
  42 + Map<String, MenuDTO> menuDTOMap = new LinkedHashMap<>(menus.size());
  43 + menus.forEach(menu -> menuDTOMap.put(menu.getId(), menu.getDTO(MenuDTO.class)));
  44 + return buildMenuDTOTree(menuDTOMap);
  45 + }
  46 +
  47 + @Override
  48 + public List<MenuDTO> getMyMenus(String tenantId,String userId,boolean isSysAdmin,boolean isTenantAdmin) {
  49 + List<MenuDTO> menuDTOs;
  50 + if (isSysAdmin) {
  51 + menuDTOs = baseMapper.selectSysAdminMenu();
  52 + }
  53 + else if (isTenantAdmin) {
  54 + menuDTOs = baseMapper.selectTenantMenu(tenantId);
  55 + }
  56 + else {
  57 + menuDTOs = baseMapper.selectMyMenu(userId);
  58 + }
  59 + Map<String, MenuDTO> menuDTOMap = new LinkedHashMap<>(menuDTOs.size());
  60 + menuDTOs.forEach(menuDTO -> menuDTOMap.put(menuDTO.getId(), menuDTO));
  61 + return buildMenuDTOTree(menuDTOMap);
  62 + }
  63 +
  64 + private List<MenuDTO> buildMenuDTOTree(Map<String, MenuDTO> menuDTOMap) {
  65 + List<MenuDTO> result = Lists.newArrayList();
  66 + for (MenuDTO node : menuDTOMap.values()) {
  67 + MenuDTO parent = menuDTOMap.get(node.getParentId());
  68 + if (parent != null && !(node.getId().equals(parent.getId()))) {
  69 + parent.getChildren().add(node);
  70 + continue;
  71 + }
  72 + result.add(node);
  73 + }
  74 + Collections.sort(result);
  75 + result.forEach(node -> Collections.sort(node.getChildren()));
  76 + return result;
  77 + }
  78 +
  79 + @Override
  80 + @Transactional
  81 + public MenuDTO saveMenu(String tenantId,boolean isSysAdmin,MenuDTO menuDTO) {
  82 + if (menuDTO.getType() == null) {
  83 + menuDTO.setType(MenuTypeEnum.CUSTOM);
  84 + }
  85 + if (!isSysAdmin
  86 + && menuDTO.getType().equals(MenuTypeEnum.SYSADMIN)) {
  87 + throw new FastIotException(
  88 + ErrorMessage.ACCESS_DENIED.setMessage("Non-system admin cannot save system menu"),
  89 + HttpStatus.FORBIDDEN);
  90 + }
  91 + if (menuDTO.getType().equals(MenuTypeEnum.CUSTOM)
  92 + && StringUtils.isAllBlank(menuDTO.getName())) {
  93 + throw new DataValidationException("menu name is required when save custom menu");
  94 + }
  95 + int count =
  96 + baseMapper.selectCount(
  97 + new QueryWrapper<Menu>().lambda().eq(Menu::getPath, menuDTO.getPath()));
  98 + if (count > 0) {
  99 + throw new DataValidationException("menu with path " + menuDTO + " already exist");
  100 + }
  101 + menuDTO.setTenantCode(tenantId);
  102 + Menu menu = menuDTO.getEntity(Menu.class);
  103 + int insertCount = baseMapper.insert(menu);
  104 + if (insertCount > 0) {
  105 + menu.copyToDTO(menuDTO);
  106 + return menuDTO;
  107 + }
  108 + return null;
  109 + }
  110 +
  111 + @Override
  112 + public Optional<MenuDTO> getMenu(String id) {
  113 + return Optional.ofNullable(baseMapper.selectById(id)).map(menu -> menu.getDTO(MenuDTO.class));
  114 + }
  115 +
  116 + @Override
  117 + @Transactional
  118 + public MenuDTO updateMenu(String tenantId,boolean isSysAdmin,MenuDTO menuDTO) {
  119 + Menu menu = baseMapper.selectById(menuDTO.getId());
  120 + if (menu == null) {
  121 + throw new DataValidationException("cannot find menu to update");
  122 + } else {
  123 + if (!isSysAdmin) {
  124 + if (!tenantId.equals(menuDTO.getTenantCode())) {
  125 + throw new AccessDeniedException("You don't have permission to update this menu");
  126 + }
  127 + }
  128 + menuDTO.copyToEntity(menu);
  129 + baseMapper.updateById(menu);
  130 + if (!Objects.equals(menuDTO.getPermission(), menu.getPermission())) {
  131 + cacheUtils.invalidateCacheName(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY);
  132 + }
  133 + menu.copyToDTO(menuDTO);
  134 + }
  135 + return menuDTO;
  136 + }
  137 +
  138 + @Override
  139 + @Transactional
  140 + public boolean deleteMenus(String tenantId,String[] menuIds) {
  141 + Set<String> ids = Set.of(menuIds);
  142 + // 1. 判断是否所有的id都属于此人,admin也不可删除租户的menu
  143 + int notTenantMenuCount =
  144 + baseMapper.selectCount(
  145 + new QueryWrapper<Menu>()
  146 + .lambda()
  147 + .ne(Menu::getTenantCode, tenantId)
  148 + .in(Menu::getId, ids));
  149 + if (notTenantMenuCount > 0) {
  150 + throw new AccessDeniedException("cannot delete menu that not create by you");
  151 + }
  152 + // 2. 删除角色对应的menu
  153 + roleMapper.deleteRoleMenuMappingByMenuIds(ids);
  154 + // 3. 删除租户对应menu
  155 + baseMapper.deleteTenantMenuMappingByMenuIds(ids);
  156 + // 4. 删除menu
  157 + baseMapper.deleteBatchIds(ids);
  158 + cacheUtils.invalidateCacheName(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY);
  159 + return true;
  160 + }
  161 +
  162 + @Override
  163 + @Transactional
  164 + public boolean assignMenuToTenant(String tenantId,String[] menuId) {
  165 + Set<String> ids = Set.of(menuId);
  166 + int menuCountInDB =
  167 + baseMapper.selectCount(new QueryWrapper<Menu>().lambda().in(Menu::getId, ids));
  168 + if (menuCountInDB != menuId.length) {
  169 + throw new DataValidationException("please ensure all menu id are valid");
  170 + }
  171 + Set<String> existMenus = baseMapper.selectTenantMenuIds(tenantId);
  172 + Set<String> toDel = Sets.difference(existMenus, ids);
  173 + Set<String> toAdd = Sets.difference(ids, existMenus);
  174 + if (!toDel.isEmpty()) {
  175 + baseMapper.removeMenuFromTenant(tenantId, toDel);
  176 + }
  177 + if (!toAdd.isEmpty()) {
  178 + baseMapper.addMenuToTenant(tenantId, toAdd);
  179 + }
  180 + if (!toDel.isEmpty() && !toAdd.isEmpty()) {
  181 + cacheUtils.invalidate(
  182 + FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY,
  183 + FastIotConstants.CacheConfigKey.USER_PERMISSION_PREFIX + tenantId);
  184 + }
  185 + return true;
  186 + }
  187 +
  188 + @Override
  189 + @Transactional
  190 + public boolean assignMenuToRole(String[] menuId, String roleId) {
  191 + Set<String> ids = Set.of(menuId);
  192 + if (!ids.isEmpty()) {
  193 + int menuCountInDB =
  194 + baseMapper.selectCount(new QueryWrapper<Menu>().lambda().in(Menu::getId, ids));
  195 + if (menuCountInDB != menuId.length) {
  196 + throw new DataValidationException("please ensure all menu id are valid");
  197 + }
  198 + }
  199 + Set<String> existMenus = baseMapper.selectRoleMenuIds(roleId);
  200 + Set<String> toDel = Sets.difference(existMenus, ids);
  201 + Set<String> toAdd = Sets.difference(ids, existMenus);
  202 + if (!toDel.isEmpty()) {
  203 + baseMapper.removeMenuFromRole(roleId, toDel);
  204 + }
  205 + if (!toAdd.isEmpty()) {
  206 + baseMapper.addMenuToRole(roleId, toAdd);
  207 + }
  208 + if (!toAdd.isEmpty() && !toDel.isEmpty()) {
  209 + cacheUtils.invalidateCacheName(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY);
  210 + }
  211 + return true;
  212 + }
  213 +
  214 + @Override
  215 + public Set<String> getMenuIdsByRoleId(String roleId) {
  216 + return roleMapper.getMenuIdsByRoleId(roleId);
  217 + }
  218 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +import com.baomidou.mybatisplus.core.metadata.IPage;
  3 +import lombok.RequiredArgsConstructor;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.apache.commons.lang3.StringUtils;
  6 +import org.springframework.stereotype.Service;
  7 +import org.springframework.transaction.annotation.Transactional;
  8 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  9 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  10 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  11 +import org.thingsboard.server.common.data.yunteng.dto.MessageTemplateDTO;
  12 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  13 +import org.thingsboard.server.dao.yunteng.entities.MessageTemplate;
  14 +import org.thingsboard.server.dao.yunteng.mapper.MessageTemplateMapper;
  15 +import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
  16 +import org.thingsboard.server.dao.yunteng.service.MessageTemplateService;
  17 +
  18 +import java.util.List;
  19 +import java.util.Map;
  20 +import java.util.Set;
  21 +
  22 +@Service
  23 +@Slf4j
  24 +@RequiredArgsConstructor
  25 +public class MessageTemplateServiceImpl
  26 + extends AbstractBaseService<MessageTemplateMapper, MessageTemplate>
  27 + implements MessageTemplateService {
  28 + @Override
  29 + public PageData<MessageTemplateDTO> page(Map<String, Object> queryMap) {
  30 +// queryMap.put("tenantCode",SecurityContext.getCurrentUser().getTenantCode());
  31 + IPage<MessageTemplate> configIPage = getPage(queryMap, FastIotConstants.DefaultOrder.CREATE_TIME,false);
  32 + IPage<MessageTemplateDTO> iPage = baseMapper.getTemplatePage(configIPage,queryMap);
  33 + return getPageData(iPage, MessageTemplateDTO.class);
  34 + }
  35 +
  36 + @Override
  37 + @Transactional
  38 + public MessageTemplateDTO saveMessageTemplate(MessageTemplateDTO templateDTO) {
  39 + MessageTemplate messageTemplate = new MessageTemplate();
  40 + templateDTO.copyToEntity(messageTemplate);
  41 +// messageTemplate.setTenantCode(SecurityContext.getCurrentUser().getTenantCode());
  42 + baseMapper.insert(messageTemplate);
  43 + messageTemplate.copyToDTO(templateDTO);
  44 + return templateDTO;
  45 + }
  46 +
  47 + @Override
  48 + @Transactional
  49 + public boolean deleteMessageTemplate(Set<String> ids) {
  50 + return baseMapper.deleteBatchIds(ids) > 0;
  51 + }
  52 +
  53 + @Override
  54 + @Transactional
  55 + public MessageTemplateDTO updateMessageTemplate(MessageTemplateDTO templateDTO) {
  56 +
  57 +// String tenantCode = SecurityContext.getCurrentUser().getTenantCode();
  58 + //查询该租户下 是否已经启用相同消息类型、相同用途的模板
  59 + MessageTemplateDTO queryTemplate = new MessageTemplateDTO();
  60 + queryTemplate.setTemplatePurpose(templateDTO.getTemplatePurpose());
  61 + queryTemplate.setMessageType(templateDTO.getMessageType());
  62 +// queryTemplate.setTemplateCode(tenantCode);
  63 + if(StringUtils.isEmpty(templateDTO.getTemplatePurpose()) || StringUtils.isEmpty(templateDTO.getMessageType())){
  64 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  65 + }
  66 + List<MessageTemplateDTO> messageTemplateDTOList = baseMapper.findMessageTemplate(queryTemplate);
  67 + if(null!=messageTemplateDTOList && messageTemplateDTOList.size()>0){
  68 + throw new DataValidationException(ErrorMessage.NOT_SET_PASSWORD_TEMPLATE.getMessage());
  69 + }
  70 + MessageTemplate messageTemplate = baseMapper.selectById(templateDTO.getId());
  71 + templateDTO.copyToEntity(messageTemplate);
  72 +// messageTemplate.setTenantCode(tenantCode);
  73 + baseMapper.updateById(messageTemplate);
  74 + messageTemplate.copyToDTO(templateDTO);
  75 + return templateDTO;
  76 + }
  77 +
  78 + @Override
  79 + public List<MessageTemplateDTO> findMessageTemplate(MessageTemplateDTO templateDTO) {
  80 +// templateDTO.setTenantCode(SecurityContext.getCurrentUser().getTenantCode());
  81 + return baseMapper.findMessageTemplate(templateDTO);
  82 + }
  83 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4 +import com.google.common.collect.Lists;
  5 +import com.google.common.collect.Sets;
  6 +import lombok.RequiredArgsConstructor;
  7 +import org.apache.commons.lang3.StringUtils;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.transaction.annotation.Transactional;
  10 +import org.springframework.util.Assert;
  11 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  12 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  13 +import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
  14 +import org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO;
  15 +import org.thingsboard.server.dao.yunteng.entities.UserOrganizationMapping;
  16 +import org.thingsboard.server.dao.yunteng.entities.Organization;
  17 +import org.thingsboard.server.dao.yunteng.entities.User;
  18 +import org.thingsboard.server.dao.yunteng.mapper.DeviceMapper;
  19 +import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper;
  20 +import org.thingsboard.server.dao.yunteng.mapper.UserMapper;
  21 +import org.thingsboard.server.dao.yunteng.mapper.UserOrganizationMappingMapper;
  22 +import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
  23 +import org.thingsboard.server.dao.yunteng.service.OrganizationService;
  24 +
  25 +import java.util.*;
  26 +import java.util.stream.Collectors;
  27 +
  28 +@Service
  29 +@RequiredArgsConstructor
  30 +public class OrganizationServiceImpl extends AbstractBaseService<OrganizationMapper, Organization>
  31 + implements OrganizationService {
  32 +
  33 + private final UserOrganizationMappingMapper userOrganizationMappingMapper;
  34 + private final UserMapper userMapper;
  35 + private final DeviceMapper deviceMapper;
  36 +
  37 + @Override
  38 + @Transactional
  39 + public OrganizationDTO saveOrganization(OrganizationDTO organizationDTO) {
  40 + Assert.notNull(organizationDTO.getName(), "organization name cannot be null");
  41 + if (StringUtils.isNotBlank(organizationDTO.getParentId())) {
  42 + Organization organization = baseMapper.selectById(organizationDTO.getParentId());
  43 + if (organization == null) {
  44 + throw new DataValidationException("parent organization not exist!");
  45 + } else {
  46 + if (!organization
  47 + .getTenantCode()
  48 + .equals(null)) {//TODO getCurrentUser().getTenantCode()
  49 + throw new DataValidationException("parent organization not exist.");
  50 + }
  51 + }
  52 + }
  53 + Organization organization = new Organization();
  54 + //organizationDTO.setTenantCode(getCurrentUser().getTenantCode());
  55 + organizationDTO.copyToEntity(organization, "id");
  56 + baseMapper.insert(organization);
  57 + organization.copyToDTO(organizationDTO);
  58 + return organizationDTO;
  59 + }
  60 +
  61 + @Override
  62 + @Transactional
  63 + public boolean deleteOrganizations(DeleteDTO deleteDTO) {
  64 + if(null == deleteDTO || deleteDTO.getIds().isEmpty()){
  65 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  66 + }
  67 + String[] ids = deleteDTO.getIds().toArray(new String[deleteDTO.getIds().size()]);
  68 + Set<String> idToDelete =
  69 + baseMapper
  70 + .findOrganizationTreeList(
  71 + null, Arrays.asList(ids))//TODO getCurrentUser().getTenantCode()
  72 + .stream()
  73 + .map(OrganizationDTO::getId)
  74 + .collect(Collectors.toSet());
  75 + if (idToDelete.size() != ids.length) {
  76 + throw new DataValidationException("待删除数据存在子项,不能删除!");
  77 + }
  78 + List<UserOrganizationMapping> userOrganizationMappingList =
  79 + userOrganizationMappingMapper.selectList(
  80 + new QueryWrapper<UserOrganizationMapping>()
  81 + .lambda()
  82 + .in(UserOrganizationMapping::getOrganizationId, idToDelete));
  83 + if (!userOrganizationMappingList.isEmpty()) {
  84 + throw new DataValidationException("待删除数据存在关联用户,不能删除!");
  85 + }
  86 + // 查询是否有设备使用该组织
  87 +// List<Device> deviceList = deviceMapper.selectList(
  88 +// new QueryWrapper<Device>()
  89 +// .lambda()
  90 +// .eq(Device::getTenantCode, getCurrentUser().getTenantCode())
  91 +// .eq(Device::getOrganizationId,ids));
  92 +// if (!deviceList.isEmpty()) {
  93 +// throw new DataValidationException("待删除数据存在关联设备,不能删除!");
  94 +// }
  95 +// doDeleteUserOrganizationMapping(idToDelete);
  96 + return baseMapper.deleteBatchIds(idToDelete)>0;
  97 + }
  98 +
  99 + private void doDeleteUserOrganizationMapping(Collection<String> organizationIds) {
  100 + userOrganizationMappingMapper.delete(
  101 + new QueryWrapper<UserOrganizationMapping>()
  102 + .lambda()
  103 + .in(UserOrganizationMapping::getOrganizationId, organizationIds));
  104 + }
  105 +
  106 + @Override
  107 + @Transactional
  108 + public OrganizationDTO updateOrganization(OrganizationDTO organizationDTO) {
  109 +// Organization organization = baseMapper.selectById(organizationDTO.getId());
  110 +// Organization parent = null;
  111 +// if (StringUtils.isNotBlank(organizationDTO.getParentId())) {
  112 +// Organization parentOrganization = baseMapper.selectById(organizationDTO.getParentId());
  113 +// if (parentOrganization
  114 +// .getTenantCode()
  115 +// .equals(getCurrentUser().getTenantCode())) {
  116 +// parent = parentOrganization;
  117 +// }
  118 +// }
  119 +// if (organization == null) {
  120 +// return null;
  121 +// }
  122 +// if (organization.getName().equals(organizationDTO.getName())
  123 +// && organization.getSort() == organizationDTO.getSort()
  124 +// && organization.getRemark().equals(organizationDTO.getRemark())
  125 +// && Objects.equals(organization.getParentId(), organizationDTO.getParentId())) {
  126 +// return organizationDTO;
  127 +// }
  128 +// organization.setName(organizationDTO.getName());
  129 +// organization.setRemark(organizationDTO.getRemark());
  130 +// organization.setSort(organizationDTO.getSort());
  131 +// if (parent != null) {
  132 +// organization.setParentId(parent.getId());
  133 +// }
  134 +// baseMapper.updateById(organization);
  135 +// organization.copyToDTO(organizationDTO);
  136 +// return organizationDTO;
  137 + return null;
  138 + }
  139 +
  140 + @Override
  141 + public List<OrganizationDTO> getMyOrganizations() {
  142 +// if (getCurrentUser().isTenantAdmin()) {
  143 +// return findOrganizationTree(getCurrentUser().getTenantCode());
  144 +// } else {
  145 +// Set<String> organizationIds =
  146 +// userOrganizationMappingMapper
  147 +// .selectList(
  148 +// new QueryWrapper<UserOrganizationMapping>()
  149 +// .lambda()
  150 +// .in(
  151 +// UserOrganizationMapping::getUserId,
  152 +// getCurrentUser().getUserId()))
  153 +// .stream()
  154 +// .map(UserOrganizationMapping::getOrganizationId)
  155 +// .collect(Collectors.toSet());
  156 +// List<Organization> organizations =
  157 +// baseMapper.selectList(
  158 +// new QueryWrapper<Organization>()
  159 +// .lambda()
  160 +// .eq(Organization::getTenantCode, getCurrentUser().getTenantCode())
  161 +// .in(organizationIds.size() > 0, Organization::getId, organizationIds));
  162 +// return TreeUtils.buildTree(ReflectUtils.sourceToTarget(organizations, OrganizationDTO.class));
  163 +// }
  164 + return null;
  165 + }
  166 +
  167 + private List<OrganizationDTO> findOrganizationTree(String tenantCode) {
  168 + List<OrganizationDTO> organizationTreeList =
  169 + baseMapper.findOrganizationTreeList(tenantCode, null);
  170 + return buildOrganizationDTOTree(organizationTreeList);
  171 + }
  172 +
  173 + private List<OrganizationDTO> buildOrganizationDTOTree(
  174 + List<OrganizationDTO> organizationTreeList) {
  175 + Map<String, OrganizationDTO> organizationDTOMap =
  176 + new LinkedHashMap<>(organizationTreeList.size());
  177 + HashSet<OrganizationDTO> organizationDTOSet = Sets.newHashSet(organizationTreeList);
  178 + organizationDTOSet.forEach(
  179 + organizationDTO -> organizationDTOMap.put(organizationDTO.getId(), organizationDTO));
  180 + List<OrganizationDTO> result = Lists.newArrayList();
  181 + for (OrganizationDTO node : organizationDTOMap.values()) {
  182 + OrganizationDTO parent = organizationDTOMap.get(node.getParentId());
  183 + if (parent != null && !(node.getId().equals(parent.getId()))) {
  184 + parent.getChildren().add(node);
  185 + continue;
  186 + }
  187 + result.add(node);
  188 + }
  189 + Collections.sort(result);
  190 + result.forEach(node -> Collections.sort(node.getChildren()));
  191 + return result;
  192 + }
  193 +
  194 + @Override
  195 + @Transactional
  196 + public void bindUserToOrganization(String userId, String[] organizationIds) {
  197 +// User user = userMapper.selectById(userId);
  198 +// if (user == null) {
  199 +// throw new DataValidationException("所选用户不存在");
  200 +// }
  201 +// if (!user.getTenantCode().equals(getCurrentUser().getTenantCode())) {
  202 +// throw new DataValidationException("所选用户不可用");
  203 +// }
  204 +// if (null != organizationIds && organizationIds.length > 0) {
  205 +// Set<String> newBinding =
  206 +// baseMapper
  207 +// .findOrganizationTreeList(
  208 +// getCurrentUser().getTenantCode(), Arrays.asList(organizationIds))
  209 +// .stream()
  210 +// .map(OrganizationDTO::getId)
  211 +// .collect(Collectors.toSet());
  212 +// Set<String> existBinding =
  213 +// userOrganizationMappingMapper
  214 +// .selectList(
  215 +// new QueryWrapper<UserOrganizationMapping>()
  216 +// .lambda()
  217 +// .eq(UserOrganizationMapping::getUserId, userId))
  218 +// .stream()
  219 +// .map(UserOrganizationMapping::getOrganizationId)
  220 +// .collect(Collectors.toSet());
  221 +// Set<String> toDel = Sets.difference(existBinding, newBinding);
  222 +// Set<String> toAdd = Sets.difference(newBinding, existBinding);
  223 +// if (!toDel.isEmpty()) {
  224 +// userOrganizationMappingMapper.delete(
  225 +// new QueryWrapper<UserOrganizationMapping>()
  226 +// .lambda()
  227 +// .in(UserOrganizationMapping::getUserId, userId)
  228 +// .in(UserOrganizationMapping::getOrganizationId, toDel));
  229 +// }
  230 +// if (!toAdd.isEmpty()) {
  231 +// toAdd.stream()
  232 +// .map(organizationId -> new UserOrganizationMapping(userId, organizationId))
  233 +// .forEach(userOrganizationMappingMapper::insert);
  234 +// }
  235 +// }
  236 + }
  237 +
  238 + @Override
  239 + @Transactional
  240 + public void unBindUserToOrganization(Set<String> userIds) {
  241 + for (String userId : userIds) {
  242 + User user = userMapper.selectById(userId);
  243 + if (user == null) {
  244 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  245 + }
  246 + userOrganizationMappingMapper.delete(
  247 + new QueryWrapper<UserOrganizationMapping>()
  248 + .lambda()
  249 + .eq(UserOrganizationMapping::getUserId, userId));
  250 + }
  251 + }
  252 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import com.google.common.collect.Sets;
  6 +import lombok.RequiredArgsConstructor;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.apache.commons.lang3.RandomStringUtils;
  9 +import org.apache.commons.lang3.StringUtils;
  10 +import org.springframework.boot.actuate.endpoint.SecurityContext;
  11 +import org.springframework.security.access.AccessDeniedException;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.transaction.annotation.Transactional;
  14 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  15 +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils;
  16 +import org.thingsboard.server.common.data.yunteng.core.exception.FastIotException;
  17 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  18 +import org.thingsboard.server.common.data.yunteng.dto.RoleDTO;
  19 +import org.thingsboard.server.common.data.yunteng.dto.request.RoleReqDTO;
  20 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
  21 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  22 +import org.thingsboard.server.dao.yunteng.entities.Role;
  23 +import org.thingsboard.server.dao.yunteng.entities.TenantMenu;
  24 +import org.thingsboard.server.dao.yunteng.entities.TenantRole;
  25 +import org.thingsboard.server.dao.yunteng.entities.UserRole;
  26 +import org.thingsboard.server.dao.yunteng.mapper.*;
  27 +import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
  28 +import org.thingsboard.server.dao.yunteng.service.MenuService;
  29 +import org.thingsboard.server.dao.yunteng.service.RoleService;
  30 +
  31 +import java.util.List;
  32 +import java.util.Map;
  33 +import java.util.Optional;
  34 +import java.util.Set;
  35 +import java.util.stream.Collectors;
  36 +
  37 +@Service
  38 +@Slf4j
  39 +@RequiredArgsConstructor
  40 +public class RoleServiceImpl extends AbstractBaseService<RoleMapper, Role> implements RoleService {
  41 +
  42 + private final MenuMapper menuMapper;
  43 + private final CacheUtils cacheUtils;
  44 + private final MenuService menuService;
  45 + private final TenantMenuMapper tenantMenuMapper;
  46 + private final TenantRoleMapper tenantRoleMapper;
  47 + private final UserRoleMapper userRoleMapper;
  48 +
  49 + @Override
  50 + public PageData<RoleDTO> page(boolean isSysadmin,boolean isPlatformAdmin, String tenantId,Map<String, Object> queryMap) {
  51 + IPage<Role> roleIPage =
  52 + baseMapper.selectPage(
  53 + getPage(queryMap, "create_time", false),
  54 + new QueryWrapper<Role>()
  55 + .lambda()
  56 + .eq(queryMap.get("status") != null, Role::isEnabled, queryMap.get("status"))
  57 + .eq(queryMap.get("roleType") != null, Role::getRoleType, queryMap.get("roleType"))
  58 + .ne(queryMap.get("roleType") == null, Role::getRoleType, RoleEnum.ROLE_TENANT_ADMIN)
  59 + .ne(
  60 + queryMap.get("roleType") == null
  61 + && isPlatformAdmin,
  62 + Role::getRoleType,
  63 + RoleEnum.ROLE_SYS_ADMIN)
  64 + .eq(
  65 + !isSysadmin,
  66 + Role::getTenantCode,
  67 + tenantId)
  68 + .like(
  69 + queryMap.get("roleName") != null,
  70 + Role::getName,
  71 + String.valueOf(queryMap.get("roleName"))));
  72 + return getPageData(roleIPage, RoleDTO.class);
  73 + }
  74 +
  75 + @Override
  76 + @Transactional
  77 + public boolean deleteRole(String[] roleIds,String tenantId) {
  78 + Set<String> ids = Set.of(roleIds);
  79 + int notTenantMenuCount =
  80 + baseMapper.selectCount(
  81 + new QueryWrapper<Role>()
  82 + .lambda()
  83 + .ne(Role::getTenantCode, tenantId)
  84 + .in(Role::getId, ids));
  85 + if (notTenantMenuCount > 0) {
  86 + throw new AccessDeniedException("cannot delete role that not create by you");
  87 + }
  88 + // 判断该角色下面是否有用户
  89 + Set<String> userIds = baseMapper.checkRoleUserMappingByRoleIds(ids);
  90 + if (null != userIds && userIds.size() > 0) {
  91 + throw new FastIotException(ErrorMessage.ROLE_IN_USE);
  92 + }
  93 + // delete sys_role_menu mapping
  94 + baseMapper.deleteRoleMenuMappingByRoleIds(ids);
  95 + // delete role
  96 + baseMapper.deleteBatchIds(ids);
  97 + // FIXME 频繁删除role造成缓存效果不大
  98 + cacheUtils.invalidateCacheName(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY);
  99 + return true;
  100 + }
  101 +
  102 + @Override
  103 + public Set<String> getPermissions(boolean isSysadmin,boolean isTenantAdmin,String tenantId,String useerId) {
  104 + Set<String> permissions = Sets.newHashSet();
  105 + Set<String> allPermission;
  106 + String cacheKey;
  107 + boolean cachePresent;
  108 + if (isSysadmin) {
  109 + cacheKey =
  110 + FastIotConstants.CacheConfigKey.USER_PERMISSION_PREFIX + RoleEnum.ROLE_SYS_ADMIN.name();
  111 + Optional<Set<String>> optionalPermission =
  112 + cacheUtils.get(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY, cacheKey);
  113 + cachePresent = optionalPermission.isPresent();
  114 + allPermission = optionalPermission.orElseGet(menuMapper::getAllPermission);
  115 + } else if (isTenantAdmin) {
  116 + cacheKey =
  117 + FastIotConstants.CacheConfigKey.USER_PERMISSION_PREFIX
  118 + + tenantId;
  119 + Optional<Set<String>> optionalPermission =
  120 + cacheUtils.get(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY, cacheKey);
  121 + cachePresent = optionalPermission.isPresent();
  122 + allPermission =
  123 + optionalPermission.orElseGet(
  124 + () ->
  125 + menuMapper.getAllPermissionsByTenantCode(tenantId));
  126 + } else {
  127 + cacheKey =
  128 + FastIotConstants.CacheConfigKey.USER_PERMISSION_PREFIX
  129 + + useerId;
  130 + Optional<Set<String>> optionalPermission =
  131 + cacheUtils.get(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY, cacheKey);
  132 + cachePresent = optionalPermission.isPresent();
  133 + allPermission =
  134 + optionalPermission.orElseGet(
  135 + () ->
  136 + menuMapper.getAllPermissionsByUserId(useerId));
  137 + }
  138 + if (cachePresent) {
  139 + return allPermission;
  140 + } else {
  141 + allPermission.forEach(
  142 + permission -> permissions.addAll(Sets.newHashSet(permission.split(","))));
  143 + cacheUtils.put(FastIotConstants.CacheConfigKey.CACHE_CONFIG_KEY, cacheKey, permissions);
  144 + }
  145 + return permissions;
  146 + }
  147 +
  148 + @Override
  149 + @Transactional
  150 + public void updateRoleStatus(String roleId, int status,boolean isSysadmin,String tenantId) {
  151 + Optional.ofNullable(
  152 + baseMapper.selectOne(
  153 + new QueryWrapper<Role>()
  154 + .lambda()
  155 + .eq(Role::getId, roleId)
  156 + .eq(
  157 + !isSysadmin,
  158 + Role::getTenantCode,
  159 + tenantId)))
  160 + .ifPresent(
  161 + role -> {
  162 + role.setEnabled(status == 1);
  163 + baseMapper.updateById(role);
  164 + });
  165 + }
  166 +
  167 + @Override
  168 + @Transactional
  169 + public RoleDTO saveOrUpdateRoleInfoWithMenu(RoleReqDTO roleReqDTO,boolean isSysadmin,boolean isPlatformAdmin,String tenantId) {
  170 + Role role;
  171 + // 默认普通管理员角色,即租户管理员添加的角色
  172 + var roleType = RoleEnum.ROLE_NORMAL_USER.name();
  173 + if (null != roleReqDTO.getRoleType()) {
  174 + roleType = roleReqDTO.getRoleType().name();
  175 + } else {
  176 + if (isSysadmin
  177 + || isPlatformAdmin) {
  178 + roleType = RoleEnum.ROLE_PLATFORM_ADMIN.name();
  179 + }
  180 + }
  181 + boolean update = StringUtils.isNotBlank(roleReqDTO.getId());
  182 + if (update) {
  183 + // do update
  184 + role =
  185 + baseMapper.selectOne(
  186 + new QueryWrapper<Role>()
  187 + .lambda()
  188 + .eq(Role::getId, roleReqDTO.getId())
  189 + .eq(
  190 + !isSysadmin,
  191 + Role::getTenantCode,
  192 + tenantId));
  193 + if (role == null) {
  194 + return null;
  195 + } else {
  196 + role.setRemark(roleReqDTO.getRemark());
  197 + role.setName(roleReqDTO.getName());
  198 + role.setEnabled(roleReqDTO.getStatus() == 1);
  199 + baseMapper.updateById(role);
  200 + }
  201 + } else {
  202 + // do save
  203 + role = new Role();
  204 + role.setRoleType(roleType);
  205 + role.setCode(RandomStringUtils.randomAlphabetic(10));
  206 + role.setRemark(roleReqDTO.getRemark());
  207 + role.setName(roleReqDTO.getName());
  208 + role.setEnabled(roleReqDTO.getStatus() == 1);
  209 + role.setTenantCode(tenantId);
  210 + baseMapper.insert(role);
  211 + }
  212 + // do update or save menu associate with this roleId
  213 + menuService.assignMenuToRole(
  214 + roleReqDTO.getMenu().toArray(new String[roleReqDTO.getMenu().size()]), role.getId());
  215 + // 如果是租户管理员角色并且是更新,则需要更新租户菜单表
  216 + if (role.getRoleType().equals(RoleEnum.ROLE_TENANT_ADMIN.name()) && update) {
  217 + List<String> menus = roleReqDTO.getMenu();
  218 + // 先删除以前的租户菜单,再更新新的租户菜单
  219 + // 1、查询这个角色有几个租户用户
  220 + // 2、删除并更新对应租户的信息
  221 + List<TenantRole> tenantRoles =
  222 + tenantRoleMapper.selectList(
  223 + new QueryWrapper<TenantRole>().lambda().eq(TenantRole::getRoleId, role.getId()));
  224 + tenantRoles.forEach(
  225 + tenantRole -> {
  226 + String updateTenantCode = tenantRole.getTenantCode();
  227 + int deleteCount =
  228 + tenantMenuMapper.delete(
  229 + new QueryWrapper<TenantMenu>()
  230 + .lambda()
  231 + .eq(TenantMenu::getTenantCode, updateTenantCode));
  232 + if (deleteCount > 0) {
  233 + menus.forEach(
  234 + menu -> {
  235 + TenantMenu tenantMenu = new TenantMenu();
  236 + tenantMenu.setMenuId(menu);
  237 + tenantMenu.setTenantCode(updateTenantCode);
  238 + tenantMenuMapper.insert(tenantMenu);
  239 + });
  240 + }
  241 + });
  242 + }
  243 + return role.getDTO(RoleDTO.class);
  244 + }
  245 +
  246 + @Override
  247 + public List<RoleDTO> findRoleInfo(boolean isTenantAdmin,String tenantId,String userId,RoleDTO roleDTO) {
  248 + if (StringUtils.isEmpty(roleDTO.getTenantCode())) {
  249 + roleDTO.setTenantCode(tenantId);
  250 + }
  251 + if (isTenantAdmin) {
  252 + // 租户管理员既要查询自己拥有的角色,也要查询自己创建的角色
  253 + List<String> roleIds =
  254 + userRoleMapper
  255 + .selectList(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, userId))
  256 + .stream()
  257 + .map(UserRole::getRoleId)
  258 + .collect(Collectors.toList());
  259 + roleDTO.setRoleIds(roleIds.toArray(new String[roleIds.size()]));
  260 + }
  261 + return baseMapper.findRoleInfo(roleDTO);
  262 + }
  263 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  5 +import com.baomidou.mybatisplus.core.metadata.IPage;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import lombok.RequiredArgsConstructor;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.apache.commons.lang3.StringUtils;
  10 +import org.springframework.stereotype.Service;
  11 +import org.springframework.transaction.annotation.Transactional;
  12 +import org.thingsboard.server.common.data.DeviceProfile;
  13 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  14 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  15 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  16 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  17 +import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
  18 +import org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO;
  19 +import org.thingsboard.server.common.data.yunteng.enums.DeviceState;
  20 +import org.thingsboard.server.common.data.yunteng.enums.DeviceTypeEnum;
  21 +import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
  22 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  23 +import org.thingsboard.server.dao.yunteng.entities.Organization;
  24 +import org.thingsboard.server.dao.yunteng.entities.YtDevice;
  25 +import org.thingsboard.server.dao.yunteng.mapper.DeviceMapper;
  26 +import org.thingsboard.server.dao.yunteng.mapper.DeviceProfileMapper;
  27 +import org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper;
  28 +import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
  29 +import org.thingsboard.server.dao.yunteng.service.YtDeviceService;
  30 +
  31 +import java.util.*;
  32 +import java.util.stream.Collectors;
  33 +
  34 +@Service
  35 +@RequiredArgsConstructor
  36 +@Slf4j
  37 +public class YtDeviceServiceImpl extends AbstractBaseService<DeviceMapper, YtDevice>
  38 + implements YtDeviceService {
  39 +
  40 +// private final TBConfig tbConfig;
  41 +// private final TBConnectService tbConnectService;
  42 +// private final TbDBService tbDBService;
  43 + private final DeviceProfileMapper deviceProfileMapper;
  44 + private final OrganizationMapper organizationMapper;
  45 +
  46 + @Override
  47 + // @Transactional
  48 + // 事务会导致 tbDBService 多数据源失效
  49 + public DeviceDTO insertOrUpdate(String tenantId,DeviceDTO deviceDTO) {
  50 + if (StringUtils.isBlank(deviceDTO.getId())) {
  51 + return insert(tenantId,deviceDTO);
  52 + } else {
  53 + return update(tenantId,deviceDTO);
  54 + }
  55 + }
  56 +
  57 + private DeviceDTO update(String tenantId,DeviceDTO deviceDTO) {
  58 + YtDevice device = baseMapper.selectById(deviceDTO.getId());
  59 + if (!device.getTenantCode().equals(tenantId)) {
  60 + return null;
  61 + }
  62 + validateDeviceDTO(tenantId,deviceDTO, false);
  63 + List<YtDevice> devices =
  64 + baseMapper.selectList(
  65 + new QueryWrapper<YtDevice>()
  66 + .lambda()
  67 +// .eq(YtDevice::getDeviceToken, deviceDTO.getDeviceToken())
  68 + );
  69 + if (!devices.isEmpty()) {
  70 + // 如果device token已经存在,那么必定只有一个,不会有多个
  71 + YtDevice deviceExistWithSameToken = devices.get(0);
  72 + if (!deviceExistWithSameToken.getId().equals(deviceDTO.getId())) {
  73 + throw new DataValidationException("设备Device Token已经存在!");
  74 + }
  75 + }
  76 + // 首先update tb, 需要更新的字段有
  77 + // name, tbDeviceProfileId, label, isGateway, deviceToken
  78 + /*if (tbConfig.isEnabled()) {
  79 + validateUpdate(deviceDTO);
  80 + deviceDTO.setTbDeviceId(device.getTbDeviceId());
  81 + // 判断name, tbDeviceProfileId, label, isGateway是否有更新
  82 + boolean changed = detectDeviceChange(deviceDTO, device);
  83 + if (changed) {
  84 + Device tbDevice = buildTbDeviceFromDeviceDTO(deviceDTO);
  85 + try {
  86 + tbConnectService.saveDevice(tbDevice, deviceDTO.getDeviceToken()).get();
  87 + } catch (InterruptedException | ExecutionException e) {
  88 + log.error("update device to tb error:{}", e.getMessage());
  89 + throw new FastIotException(ErrorMessage.CONNECT_TO_TB_ERROR);
  90 + }
  91 + }
  92 + // update deviceToken
  93 + if (!deviceDTO.getDeviceToken().equals(device.getDeviceToken())) {
  94 + CredentialEntity credentialEntity =
  95 + tbDBService.findDeviceCredentialsByDeviceId(deviceDTO.getTbDeviceId());
  96 + if (credentialEntity == null) {
  97 + log.error("tb 无此设备信息->tbDeviceId[{}]", deviceDTO.getTbDeviceId());
  98 + throw new FastIotException(ErrorMessage.CONNECT_TO_TB_ERROR.setMessage("tb 无此设备信息"));
  99 + }
  100 + credentialEntity.setCredentialsId(deviceDTO.getDeviceToken());
  101 + TBCredential tbCredential = buildTBCredential(credentialEntity);
  102 + try {
  103 + TBCredential newTbCredentials = tbConnectService.saveDeviceCredential(tbCredential).get();
  104 + if (newTbCredentials == null) {
  105 + throw new FastIotException(
  106 + ErrorMessage.CONNECT_TO_TB_ERROR.setMessage("update tb credentials error"));
  107 + }
  108 + } catch (InterruptedException | ExecutionException e) {
  109 + log.error("update device to tb error:{}", e.getMessage());
  110 + throw new FastIotException(ErrorMessage.CONNECT_TO_TB_ERROR);
  111 + }
  112 + }
  113 + }*/
  114 + deviceDTO.copyToEntity(
  115 + device,
  116 + ModelConstants.TablePropertyMapping.ACTIVE_TIME,
  117 + ModelConstants.TablePropertyMapping.DEVICE_STATE,
  118 + ModelConstants.TablePropertyMapping.TB_DEVICE_ID,
  119 + ModelConstants.TablePropertyMapping.TENANT_CODE,
  120 + ModelConstants.TablePropertyMapping.CREATOR,
  121 + ModelConstants.TablePropertyMapping.UPDATER,
  122 + ModelConstants.TablePropertyMapping.CREATE_TIME,
  123 + ModelConstants.TablePropertyMapping.UPDATE,
  124 + ModelConstants.TablePropertyMapping.UPDATE_TIME);
  125 + baseMapper.updateById(device);
  126 + return device.getDTO(DeviceDTO.class);
  127 + }
  128 +
  129 +// private TBCredential buildTBCredential(CredentialEntity credentialEntity) {
  130 +// Assert.notNull(credentialEntity, "credentialEntity cannot be null");
  131 +// TBCredential tbCredential = new TBCredential();
  132 +// tbCredential.setCredentialsId(credentialEntity.getCredentialsId());
  133 +// tbCredential.setCredentialsType(credentialEntity.getCredentialsType());
  134 +// tbCredential.setCreateTime(credentialEntity.getCreatedTime());
  135 +// tbCredential.setCredentialsValue(credentialEntity.getCredentialsValue());
  136 +// Id deviceId = new Id();
  137 +// deviceId.setEntityType(EntityType.DEVICE);
  138 +// deviceId.setId(credentialEntity.getDeviceId());
  139 +// tbCredential.setDeviceId(deviceId);
  140 +// Id id = new Id();
  141 +// id.setId(credentialEntity.getId());
  142 +// tbCredential.setId(id);
  143 +// return tbCredential;
  144 +// }
  145 +
  146 + private void validateUpdate(DeviceDTO deviceDTO) {
  147 + if (StringUtils.isAllBlank(deviceDTO.getName())) {
  148 + throw new DataValidationException("device name must be specific");
  149 + }
  150 + }
  151 +
  152 + private boolean detectDeviceChange(DeviceDTO deviceDTO, YtDevice device) {
  153 + boolean changed =
  154 + !deviceDTO.getName().equalsIgnoreCase(device.getName())
  155 + || !deviceDTO.getProfileId().equalsIgnoreCase(device.getProfileId());
  156 + if (changed) {
  157 + return true;
  158 + }
  159 + boolean dtoGateway =
  160 + Optional.ofNullable(deviceDTO.getDeviceType())
  161 + .map(deviceType -> deviceType.equals(DeviceTypeEnum.GATEWAY))
  162 + .orElse(false);
  163 + boolean entityGateway =
  164 + Optional.ofNullable(device.getDeviceType())
  165 + .map(deviceType -> deviceType.equals(DeviceTypeEnum.GATEWAY))
  166 + .orElse(false);
  167 + if (entityGateway != dtoGateway) {
  168 + changed = true;
  169 + }
  170 + if (changed) {
  171 + return true;
  172 + }
  173 + String dtoDesc =
  174 + Optional.ofNullable(deviceDTO.getDeviceInfo())
  175 + .map(deviceInfo -> deviceInfo.get("description"))
  176 + .map(JsonNode::asText)
  177 + .orElse("");
  178 + String dtoLabel = deviceDTO.getLabel() == null ? "" : deviceDTO.getLabel();
  179 + String entityDesc =
  180 + Optional.ofNullable(device.getDeviceInfo())
  181 + .map(deviceInfo -> deviceInfo.get("description"))
  182 + .map(JsonNode::asText)
  183 + .orElse("");
  184 + String entityLabel = device.getLabel() == null ? "" : device.getLabel();
  185 + if (!dtoDesc.equals(entityDesc) || !dtoLabel.equals(entityLabel)) {
  186 + changed = true;
  187 + }
  188 + return changed;
  189 + }
  190 +
  191 + private void validateDeviceDTO(String tenantId,DeviceDTO deviceDTO, boolean insert) {
  192 + if (StringUtils.isBlank(deviceDTO.getName())) {
  193 + throw new DataValidationException("device name cannot be black");
  194 + }
  195 + // validate IOT DB
  196 + if (StringUtils.isBlank(deviceDTO.getProfileId())) {
  197 + throw new DataValidationException("device profile cannot be black");
  198 + }
  199 + if (StringUtils.isBlank(deviceDTO.getDeviceToken()) && !insert) {
  200 + throw new DataValidationException("device token cannot be black");
  201 + }
  202 + // 验证设备名称是否已经存在 如果此处直接使用deviceDTO 将有误
  203 + if (insert) {
  204 + DeviceDTO check = new DeviceDTO();
  205 + check.setName(deviceDTO.getName());
  206 + if (findDeviceInfo(tenantId,check).size() > 0) {
  207 + throw new DataValidationException(ErrorMessage.NAME_ALREADY_EXISTS.getMessage());
  208 + }
  209 + }
  210 + // 验证数据profileId的正确性
  211 + DeviceProfile deviceProfile = deviceProfileMapper.selectById(deviceDTO.getProfileId());
  212 + Organization organization = organizationMapper.selectById(deviceDTO.getOrganizationId());
  213 + if (null == deviceProfile || null == organization) {
  214 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  215 +// } else if (StringUtils.isEmpty(deviceProfile.getTbProfileId())) {
  216 +// throw new DataValidationException("tb_device profile is nonexistent");
  217 + } else if (!deviceProfile
  218 + .getTenantId()
  219 + .equals(tenantId)
  220 + || !organization.getTenantCode().equals(tenantId)) {
  221 + throw new DataValidationException(ErrorMessage.TENANT_MISMATCHING.getMessage());
  222 + }
  223 + }
  224 +
  225 + private DeviceDTO insert(String tenantId,DeviceDTO deviceDTO) {
  226 + validateDeviceDTO(tenantId,deviceDTO, true);
  227 + if (StringUtils.isNotBlank(deviceDTO.getDeviceToken())) {
  228 + List<YtDevice> devices =
  229 + baseMapper.selectList(
  230 + new QueryWrapper<YtDevice>()
  231 + .lambda()
  232 + .eq(YtDevice::getDeviceToken, deviceDTO.getDeviceToken()));
  233 + if (!devices.isEmpty()) {
  234 + throw new DataValidationException("设备Device Token已经存在!");
  235 + }
  236 + }
  237 + YtDevice device = new YtDevice();
  238 + deviceDTO.copyToEntity(
  239 + device,
  240 + ModelConstants.TablePropertyMapping.ACTIVE_TIME,
  241 + ModelConstants.TablePropertyMapping.DEVICE_STATE,
  242 + ModelConstants.TablePropertyMapping.TB_DEVICE_ID,
  243 + ModelConstants.TablePropertyMapping.TENANT_CODE,
  244 + ModelConstants.TablePropertyMapping.CREATOR,
  245 + ModelConstants.TablePropertyMapping.UPDATER,
  246 + ModelConstants.TablePropertyMapping.CREATE_TIME,
  247 + ModelConstants.TablePropertyMapping.UPDATE,
  248 + ModelConstants.TablePropertyMapping.UPDATE_TIME);
  249 + device.setTenantCode(tenantId);
  250 + // First insert into TB
  251 +// if (tbConfig.isEnabled()) {
  252 +// Device tbDevice = buildTbDeviceFromDeviceDTO(deviceDTO);
  253 +// try {
  254 +// Device insertedTbDevice =
  255 +// tbConnectService.saveDevice(tbDevice, deviceDTO.getDeviceToken()).get();
  256 +// if (insertedTbDevice == null) {
  257 +// throw new FastIotException(ErrorMessage.CONNECT_TO_TB_ERROR);
  258 +// }
  259 +// // 判断插入的DTO是否设置了deviceToken,如果不存在,获取Tb的deviceToken存入DB
  260 +// if (StringUtils.isAllBlank(device.getDeviceToken())) {
  261 +// String deviceTokenFromDB =
  262 +// tbDBService.getDeviceTokenFromDB(insertedTbDevice.getId().getId());
  263 +// device.setDeviceToken(deviceTokenFromDB);
  264 +// }
  265 +// device.setTbDeviceId(insertedTbDevice.getId().getId());
  266 +// } catch (InterruptedException | ExecutionException e) {
  267 +// log.error("insert device into tb error:{}", e.getMessage());
  268 +// throw new FastIotException(ErrorMessage.CONNECT_TO_TB_ERROR);
  269 +// }
  270 +// }
  271 + device.setAlarmStatus(0);
  272 + /** 默认待激活状态 */
  273 + device.setDeviceState(DeviceState.INACTIVE);
  274 + baseMapper.insert(device);
  275 + return device.getDTO(DeviceDTO.class);
  276 + }
  277 +
  278 +// private Device buildTbDeviceFromDeviceDTO(DeviceDTO deviceDTO) {
  279 +// Device tbDevice = new Device();
  280 +// if (StringUtils.isNotBlank(deviceDTO.getTbDeviceId())) {
  281 +// Id id = new Id();
  282 +// id.setId(deviceDTO.getTbDeviceId());
  283 +// id.setEntityType(EntityType.DEVICE);
  284 +// tbDevice.setId(id);
  285 +// }
  286 +// Device.AdditionalInfo additionalInfo = new Device.AdditionalInfo();
  287 +// additionalInfo.setGateway(
  288 +// Optional.ofNullable(deviceDTO.getDeviceType())
  289 +// .map(deviceType -> deviceType.equals(DeviceTypeEnum.GATEWAY))
  290 +// .orElse(false));
  291 +//
  292 +// additionalInfo.setDescription(
  293 +// Optional.ofNullable(deviceDTO.getDeviceInfo())
  294 +// .map(deviceInfo -> deviceInfo.get("description"))
  295 +// .map(JsonNode::asText)
  296 +// .orElse(""));
  297 +// additionalInfo.setOverwriteActivityTime(false);
  298 +//
  299 +// Id deviceProfileId = new Id();
  300 +// deviceProfileId.setEntityType(EntityType.DEVICE_PROFILE);
  301 +// DeviceProfile deviceProfile = deviceProfileMapper.selectById(deviceDTO.getProfileId());
  302 +// deviceProfileId.setId(deviceProfile != null ? deviceProfile.getTbProfileId() : null);
  303 +//
  304 +// tbDevice.setAdditionalInfo(additionalInfo);
  305 +// tbDevice.setCustomerId(null);
  306 +// tbDevice.setDeviceProfileId(deviceProfileId);
  307 +// tbDevice.setLabel(deviceDTO.getLabel());
  308 +// tbDevice.setName(deviceDTO.getName());
  309 +// tbDevice.setCreatedTime(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
  310 +// return tbDevice;
  311 +// }
  312 +
  313 + @Override
  314 + @Transactional
  315 + public void deleteDevices(String tenantId,Set<String> ids) {
  316 + LambdaQueryWrapper<YtDevice> queryWrapper =
  317 + new QueryWrapper<YtDevice>()
  318 + .lambda()
  319 + .eq(YtDevice::getTenantCode, tenantId)
  320 + .in(YtDevice::getId, ids);
  321 +
  322 + List<String> tbDeviceIds =
  323 + baseMapper.selectList(queryWrapper).stream()
  324 + .map(YtDevice::getTbDeviceId)
  325 + .collect(Collectors.toList());
  326 + baseMapper.delete(queryWrapper);
  327 + // 忽略删除进度,也不管是否删除了
  328 +/* if (tbConfig.isEnabled()) {
  329 + tbDeviceIds.forEach(tbConnectService::deleteDevice);
  330 + }*/
  331 + }
  332 +
  333 + @Override
  334 + public Optional<DeviceDTO> getDevice(String tenantId,String id) {
  335 + return Optional.ofNullable(
  336 + baseMapper.selectOne(
  337 + new QueryWrapper<YtDevice>()
  338 + .lambda()
  339 + .eq(YtDevice::getTenantCode, tenantId)
  340 + .eq(YtDevice::getId, id)))
  341 + .map(device -> device.getDTO(DeviceDTO.class));
  342 + }
  343 +
  344 + @Override
  345 + public PageData<DeviceDTO> page(String tenantId,Map<String, Object> queryMap) {
  346 + queryMap.put("tenantCode", tenantId);
  347 + String organizationId = (String) queryMap.get("organizationId");
  348 + if (!StringUtils.isEmpty(organizationId)) {
  349 + List<String> organizationIds = new ArrayList<>();
  350 + organizationIds.add(organizationId);
  351 + // 查询该组织的所有子类
  352 + List<OrganizationDTO> organizationDTOS =
  353 + organizationMapper.findOrganizationTreeList(
  354 + tenantId, organizationIds);
  355 + List<String> queryOrganizationIds = new ArrayList<>();
  356 + organizationDTOS.forEach(
  357 + item -> {
  358 + queryOrganizationIds.add(item.getId());
  359 + });
  360 + queryMap.put("organizationIds", queryOrganizationIds);
  361 + }
  362 + IPage<YtDevice> page = getPage(queryMap, FastIotConstants.DefaultOrder.CREATE_TIME, false);
  363 + IPage<DeviceDTO> deviceIPage = baseMapper.getDevicePage(page, queryMap);
  364 + return getPageData(deviceIPage, DeviceDTO.class);
  365 + }
  366 +
  367 + @Override
  368 + public List<DeviceDTO> findDeviceInfo(String tenantId,DeviceDTO deviceDTO) {
  369 + List<YtDevice> deviceList =
  370 + baseMapper.selectList(
  371 + new QueryWrapper<YtDevice>()
  372 + .lambda()
  373 + .eq(
  374 + StringUtils.isNotBlank(deviceDTO.getDeviceToken()),
  375 + YtDevice::getDeviceToken,
  376 + deviceDTO.getDeviceToken())
  377 + .eq(true, YtDevice::getTenantCode, tenantId)
  378 + .like(
  379 + StringUtils.isNotBlank(deviceDTO.getName()),
  380 + YtDevice::getName,
  381 + deviceDTO.getName()));
  382 + return ReflectUtils.sourceToTarget(deviceList, DeviceDTO.class);
  383 + }
  384 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  5 +import com.fasterxml.jackson.databind.JsonNode;
  6 +import com.fasterxml.jackson.databind.node.ObjectNode;
  7 +import lombok.RequiredArgsConstructor;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.apache.commons.lang3.RandomStringUtils;
  10 +import org.apache.commons.lang3.StringUtils;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.transaction.annotation.Transactional;
  14 +import org.thingsboard.common.util.JacksonUtil;
  15 +import org.thingsboard.server.common.data.yunteng.config.sms.YtDefaultSmsSenderFactory;
  16 +import org.thingsboard.server.common.data.yunteng.config.sms.SmsProviderConfiguration;
  17 +import org.thingsboard.server.common.data.yunteng.config.sms.SmsSender;
  18 +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils;
  19 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  20 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  21 +import org.thingsboard.server.common.data.yunteng.dto.request.CodeTTL;
  22 +import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO;
  23 +import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum;
  24 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
  25 +import org.thingsboard.server.common.data.yunteng.enums.ResponseCodeEnum;
  26 +import org.thingsboard.server.dao.yunteng.entities.MessageConfig;
  27 +import org.thingsboard.server.dao.yunteng.entities.MessageTemplate;
  28 +import org.thingsboard.server.dao.yunteng.entities.SmsLog;
  29 +import org.thingsboard.server.dao.yunteng.entities.User;
  30 +import org.thingsboard.server.dao.yunteng.mapper.MessageConfigMapper;
  31 +import org.thingsboard.server.dao.yunteng.mapper.MessageTemplateMapper;
  32 +import org.thingsboard.server.dao.yunteng.mapper.SmsLogMapper;
  33 +import org.thingsboard.server.dao.yunteng.mapper.UserMapper;
  34 +import org.thingsboard.server.dao.yunteng.service.YtSmsService;
  35 +
  36 +import java.time.LocalDateTime;
  37 +import java.util.LinkedHashMap;
  38 +import java.util.List;
  39 +
  40 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CacheConfigKey.MOBILE_LOGIN_SMS_CODE;
  41 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.DEFAULT_DELIMITER;
  42 +
  43 +@Slf4j
  44 +@Service
  45 +@RequiredArgsConstructor
  46 +public class YtSmsServiceImpl implements YtSmsService {
  47 +
  48 + private final MessageTemplateMapper messageTemplateMapper;
  49 +
  50 + private final MessageConfigMapper messageConfigMapper;
  51 +
  52 + private YtDefaultSmsSenderFactory ytDefaultSmsSenderFactory;
  53 +
  54 + private final SmsLogMapper smsLogMapper;
  55 +
  56 + private CacheUtils cacheUtils;
  57 +
  58 + private final UserMapper userMapper;
  59 +
  60 + @Override
  61 + @Transactional
  62 + public boolean sendSms(SmsReqDTO smsReqDTO) {
  63 + String phoneNumbers = smsReqDTO.getPhoneNumbers();
  64 + LinkedHashMap<String, String> templateParam = smsReqDTO.getParams();
  65 + String templateId = smsReqDTO.getId();
  66 + if (StringUtils.isEmpty(phoneNumbers) || StringUtils.isEmpty(templateId)) {
  67 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  68 + }
  69 + MessageTemplate messageTemplate = messageTemplateMapper.selectById(templateId);
  70 + if (null != messageTemplate) {
  71 + MessageConfig messageConfig =
  72 + messageConfigMapper.selectById(messageTemplate.getMessageConfigId());
  73 + JsonNode configJsonNode = messageConfig.getConfig();
  74 + ObjectNode configObjectNode = (ObjectNode) configJsonNode;
  75 + configObjectNode.put("type", messageConfig.getPlatformType());
  76 + SmsProviderConfiguration smsProviderConfiguration =
  77 + JacksonUtil.convertValue(configObjectNode, SmsProviderConfiguration.class);
  78 + if (null != smsProviderConfiguration) {
  79 + SmsSender smsSender = ytDefaultSmsSenderFactory.createSmsSender(smsProviderConfiguration);
  80 + String result =
  81 + smsSender.sendSms(
  82 + phoneNumbers,
  83 + messageTemplate.getTemplateCode(),
  84 + templateParam,
  85 + messageTemplate.getSignName());
  86 + // 记录短信日志
  87 + String status = ResponseCodeEnum.SUCCESS.name();
  88 + String remark = smsReqDTO.getRemark()==null?"":smsReqDTO.getRemark();
  89 + if(!ResponseCodeEnum.SUCCESS.name().equals(result)){
  90 + status = ResponseCodeEnum.FAILED.name();
  91 + remark += result;
  92 + }
  93 + SmsLog smsLog = new SmsLog();
  94 + smsLog.setToPhone(phoneNumbers);
  95 + smsLog.setType(messageConfig.getPlatformType());
  96 + smsLog.setStatus(status);
  97 + smsLog.setRemark(remark);
  98 + smsLog.setMessageTemplateId(messageTemplate.getId());
  99 + smsLog.setTemplateParam(JacksonUtil.toJsonNode(JacksonUtil.toString(templateParam)));
  100 + smsLog.setSendTime(LocalDateTime.now());
  101 + smsLog.setTenantCode(messageTemplate.getTenantCode());
  102 + smsLog.setTemplatePurpose(smsReqDTO.getTemplatePurpose());
  103 + smsLogMapper.insert(smsLog);
  104 + return ResponseCodeEnum.SUCCESS.name().equals(result);
  105 + }
  106 + }
  107 + return false;
  108 + }
  109 +
  110 + @Override
  111 + @Transactional
  112 + public boolean sendLoginSmsCode(String phoneNumber) {
  113 + // 检查手机号码是否存在系统,以免乱发消息
  114 + if (userMapper
  115 + .selectList(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber))
  116 + .isEmpty()) {
  117 + throw new DataValidationException("电话号码未在系统注册,请联系你的管理员");
  118 + }
  119 + // 获取是否有验证码存在,防止发送数量过多
  120 + String key =
  121 + MsgTemplatePurposeEnum.FOR_LOGIN.name()
  122 + + DEFAULT_DELIMITER
  123 + + MessageTypeEnum.PHONE_MESSAGE.name()
  124 + + DEFAULT_DELIMITER
  125 + + phoneNumber;
  126 + boolean canSend =
  127 + cacheUtils
  128 + .get(MOBILE_LOGIN_SMS_CODE, key)
  129 + .map(
  130 + o -> {
  131 + CodeTTL codeTTL = (CodeTTL) o;
  132 + return System.currentTimeMillis() - codeTTL.getSendTs()
  133 + >= 60 * 1000; // 大于1分钟才允许下次再发送短信
  134 + })
  135 + .orElse(true);
  136 + if (!canSend) {
  137 + return false;
  138 + }
  139 + List<MessageTemplate> messageTemplates =
  140 + messageTemplateMapper.selectList(
  141 + new QueryWrapper<MessageTemplate>()
  142 + .lambda()
  143 + .eq(MessageTemplate::getTemplatePurpose, MsgTemplatePurposeEnum.FOR_LOGIN.name())
  144 + .eq(MessageTemplate::getMessageType, MessageTypeEnum.PHONE_MESSAGE.name()));
  145 + if (messageTemplates.isEmpty()) {
  146 + throw new DataValidationException("no sms provider config");
  147 + }
  148 + String code = RandomStringUtils.randomNumeric(6);
  149 + LinkedHashMap<String, String> params = new LinkedHashMap<>();
  150 + params.put("code", code);
  151 + MessageTemplate messageTemplate = messageTemplates.get(0);
  152 + SmsReqDTO smsReqDTO = new SmsReqDTO();
  153 + smsReqDTO.setParams(params);
  154 + smsReqDTO.setPhoneNumbers(phoneNumber);
  155 + smsReqDTO.setId(messageTemplate.getId());
  156 + smsReqDTO.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_LOGIN.name());
  157 + if (this.sendSms(smsReqDTO)) {
  158 + cacheUtils.put(MOBILE_LOGIN_SMS_CODE, key, new CodeTTL(code, System.currentTimeMillis()));
  159 + return true;
  160 + } else {
  161 + cacheUtils.invalidate(MOBILE_LOGIN_SMS_CODE, key);
  162 + return false;
  163 + }
  164 + }
  165 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import lombok.RequiredArgsConstructor;
  6 +import org.apache.commons.lang3.RandomStringUtils;
  7 +import org.apache.commons.lang3.StringUtils;
  8 +import org.springframework.beans.BeanUtils;
  9 +import org.springframework.stereotype.Service;
  10 +import org.springframework.transaction.annotation.Transactional;
  11 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  12 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  13 +import org.thingsboard.server.common.data.yunteng.dto.TenantDTO;
  14 +import org.thingsboard.server.common.data.yunteng.dto.request.TenantReqDTO;
  15 +import org.thingsboard.server.common.data.yunteng.enums.TenantStatusEnum;
  16 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  17 +import org.thingsboard.server.dao.yunteng.entities.Tenant;
  18 +import org.thingsboard.server.dao.yunteng.entities.TenantMenu;
  19 +import org.thingsboard.server.dao.yunteng.entities.TenantRole;
  20 +import org.thingsboard.server.dao.yunteng.entities.User;
  21 +import org.thingsboard.server.dao.yunteng.mapper.*;
  22 +import org.thingsboard.server.dao.yunteng.service.AbstractBaseService;
  23 +import org.thingsboard.server.dao.yunteng.service.YtTenantService;
  24 +
  25 +import java.time.LocalDateTime;
  26 +import java.util.*;
  27 +
  28 +@Service
  29 +@RequiredArgsConstructor
  30 +public class YtTenantServiceImpl extends AbstractBaseService<TenantMapper, Tenant>
  31 + implements YtTenantService {
  32 +
  33 + private final MenuMapper menuMapper;
  34 + private final RoleMapper roleMapper;
  35 + private final UserMapper userMapper;
  36 + private final TenantMenuMapper tenantMenuMapper;
  37 + private final TenantRoleMapper tenantRoleMapper;
  38 +
  39 + @Override
  40 + @Transactional
  41 + public TenantDTO createNewTenant(TenantReqDTO tenantReqDTO) {
  42 + TenantDTO tenantDTO = new TenantDTO();
  43 + BeanUtils.copyProperties(tenantReqDTO, tenantDTO);
  44 + processTenantCode(tenantDTO);
  45 + Tenant tenant = tenantDTO.getEntity(Tenant.class);
  46 + baseMapper.insert(tenant);
  47 + // 调用TB API
  48 + tenant.copyToDTO(tenantDTO);
  49 + saveTenantMapping(tenantDTO.getTenantCode(), tenantReqDTO.getRoleIds());
  50 + return tenantDTO;
  51 + }
  52 +
  53 + @Override
  54 + public PageData<TenantDTO> page(Map<String, Object> queryMap) {
  55 + IPage<Tenant> tenantIPage = getPage(queryMap, "create_time", true);
  56 + IPage<TenantDTO> userPage =
  57 + baseMapper.getTenantPage(tenantIPage, (String) queryMap.get("tenantName"));
  58 + PageData<TenantDTO> pageData = getPageData(userPage, TenantDTO.class);
  59 + determineTenantStatus(pageData.getItems());
  60 + return pageData;
  61 + }
  62 +
  63 + private void determineTenantStatus(Collection<TenantDTO> tenantDTOList) {
  64 + tenantDTOList.forEach(
  65 + tenantDTO -> {
  66 + if (!tenantDTO.isEnabled()) {
  67 + tenantDTO.setTenantStatus(TenantStatusEnum.DISABLED);
  68 + } else {
  69 + tenantDTO.setTenantStatus(TenantStatusEnum.NORMAL);
  70 + if (tenantDTO.getTenantExpireTime() != null
  71 + && LocalDateTime.now().isAfter(tenantDTO.getTenantExpireTime())) {
  72 + tenantDTO.setTenantStatus(TenantStatusEnum.EXPIRED);
  73 + }
  74 + }
  75 + });
  76 + }
  77 +
  78 + private void processTenantCode(TenantDTO tenantDTO) {
  79 + if (tenantDTO.getTenantCode() != null) {
  80 + if (tenantDTO.getTenantCode().length() > 30) {
  81 + throw new DataValidationException("tenant code too long");
  82 + }
  83 + int count =
  84 + baseMapper.selectCount(
  85 + new QueryWrapper<Tenant>()
  86 + .lambda()
  87 + .eq(Tenant::getTenantCode, tenantDTO.getTenantCode()));
  88 + if (count > 0) {
  89 + throw new DataValidationException("tenant code already exist");
  90 + }
  91 + } else {
  92 + tenantDTO.setTenantCode(RandomStringUtils.randomAlphabetic(20));
  93 + }
  94 + }
  95 +
  96 + @Override
  97 + @Transactional
  98 + public TenantDTO updateTenant(TenantDTO tenantDTO) {
  99 + Tenant tenant = baseMapper.selectById(tenantDTO.getId());
  100 + if (tenant == null) {
  101 + throw new DataValidationException("tenant does not exist");
  102 + }
  103 + String existTenantCode = tenant.getTenantCode();
  104 + tenantDTO.copyToEntity(tenant);
  105 + // tenantCode is immutable
  106 + tenant.setTenantCode(existTenantCode);
  107 + baseMapper.updateById(tenant);
  108 + tenant.copyToDTO(tenantDTO);
  109 + return tenantDTO;
  110 + }
  111 +
  112 + @Override
  113 + @Transactional
  114 + public boolean deleteTenants(String[] idArr) {
  115 + Set<String> ids = Set.of(idArr);
  116 +
  117 + Set<String> tenantCodes = baseMapper.getTenantCodesByTenantIds(ids);
  118 + // 1. GET ALL ROLE_ID
  119 + Set<String> allRoleIds = roleMapper.getAllIdsByTenantCode(tenantCodes);
  120 + // 2. DELETE SYS_ROLE SYS_ROLE_MENU SYS_USER_ROLE
  121 + if (!allRoleIds.isEmpty()) {
  122 + roleMapper.deleteBatchIds(allRoleIds);
  123 + roleMapper.deleteRoleMenuMappingByRoleIds(allRoleIds);
  124 + roleMapper.deleteRoleUserMappingByRoleIds(allRoleIds);
  125 + }
  126 + // 3. DELETE SYS_MENU SYS_TENANT_MENU
  127 + Set<String> allMenuIds = menuMapper.getAllIdsByTenantCode(tenantCodes);
  128 + if (!allMenuIds.isEmpty()) {
  129 + menuMapper.deleteBatchIds(allMenuIds);
  130 + menuMapper.deleteTenantMenuMappingByMenuIds(allMenuIds);
  131 + }
  132 + // 4. DELETE USER
  133 + userMapper.delete(new QueryWrapper<User>().lambda().in(User::getTenantCode, tenantCodes));
  134 + // 5. TELL RULE ENGINE TO STOP TENANT
  135 + // 6. DELETE OTHER RESOURCES IF ANY
  136 + // 7. DELETE TENANT
  137 + baseMapper.deleteBatchIds(ids);
  138 + // 删除 TENANT_ROLE、TENANT_MENU
  139 + deleteTenantRolesByTenantCode(tenantCodes);
  140 + deleteTenantMenusByTenantCode(tenantCodes);
  141 + // TODO 调用TB的API删除TB租户信息
  142 +
  143 + return true;
  144 + }
  145 +
  146 + /**
  147 + * 通过租户Code删除租户角色关系
  148 + * @param tenantCodes 租户Code
  149 + */
  150 + private void deleteTenantRolesByTenantCode(Set<String> tenantCodes) {
  151 + tenantRoleMapper.delete(
  152 + new QueryWrapper<TenantRole>().lambda().in(TenantRole::getTenantCode, tenantCodes));
  153 + }
  154 +
  155 + /**
  156 + * 通过租户Code删除租户角色关系
  157 + * @param tenantCodes 租户Code
  158 + */
  159 + private void deleteTenantMenusByTenantCode(Set<String> tenantCodes) {
  160 + tenantMenuMapper.delete(
  161 + new QueryWrapper<TenantMenu>().lambda().in(TenantMenu::getTenantCode, tenantCodes));
  162 + }
  163 +
  164 + @Override
  165 + public Optional<TenantDTO> findById(String id) {
  166 + return Optional.ofNullable(baseMapper.selectById(id))
  167 + .map(tenant -> tenant.getDTO(TenantDTO.class));
  168 + }
  169 +
  170 + @Override
  171 + @Transactional
  172 + public TenantDTO updateOrCreateTenant(TenantReqDTO tenantReqDTO) {
  173 + if (StringUtils.isNotBlank(tenantReqDTO.getId())) {
  174 + Tenant tenant;
  175 + tenant = baseMapper.selectById(tenantReqDTO.getId());
  176 + if (tenant != null) {
  177 + BeanUtils.copyProperties(tenantReqDTO, tenant);
  178 + baseMapper.updateById(tenant);
  179 + }
  180 + return null;
  181 + } else {
  182 + return createNewTenant(tenantReqDTO);
  183 + }
  184 + }
  185 +
  186 + @Override
  187 + public List<String> getTenantRolesByTenantCode(String tenantCode) {
  188 + if(StringUtils.isEmpty(tenantCode)){
  189 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  190 + }
  191 + List<String> roles = new ArrayList<>();
  192 + List<TenantRole> tenantRoleList = tenantRoleMapper
  193 + .selectList(
  194 + new QueryWrapper<TenantRole>().lambda().eq(TenantRole::getTenantCode, tenantCode));
  195 + tenantRoleList.forEach(role->roles.add(role.getRoleId()));
  196 + return roles;
  197 + }
  198 +
  199 + /**
  200 + * 保存租户与菜单、角色的映射关系
  201 + *
  202 + * @param tenantCode 租户Code
  203 + * @param roleIds 角色IDS
  204 + */
  205 + private void saveTenantMapping(String tenantCode, String[] roleIds) {
  206 + // 添加租户角色关系
  207 + for (String roleId : roleIds) {
  208 + saveTenantRoleMapping(roleId,tenantCode);
  209 + // 查询roleId有多少菜单
  210 + Set<String> menuIds = roleMapper.getMenuIdsByRoleId(roleId);
  211 + // 添加租户菜单关系
  212 + for (String menuId : menuIds) {
  213 + saveTenantMenuMapping(menuId,tenantCode);
  214 + }
  215 + }
  216 + }
  217 +
  218 + /**
  219 + * 保存租户与菜单的关系
  220 + * @param menuId 菜单ID
  221 + * @param tenantCode 租户Code
  222 + */
  223 + private void saveTenantMenuMapping(String menuId,String tenantCode){
  224 + TenantMenu tenantMenu = new TenantMenu();
  225 + tenantMenu.setMenuId(menuId);
  226 + tenantMenu.setTenantCode(tenantCode);
  227 + tenantMenuMapper.insert(tenantMenu);
  228 + }
  229 +
  230 + /**
  231 + * 保存租户与角色的关系
  232 + * @param roleId 角色ID
  233 + * @param tenantCode 租户Code
  234 + */
  235 + private void saveTenantRoleMapping(String roleId,String tenantCode){
  236 + TenantRole tenantRole = new TenantRole();
  237 + tenantRole.setTenantCode(tenantCode);
  238 + tenantRole.setRoleId(roleId);
  239 + tenantRoleMapper.insert(tenantRole);
  240 + }
  241 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.impl;
  2 +
  3 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  6 +import com.fasterxml.jackson.databind.JsonNode;
  7 +import com.fasterxml.jackson.databind.ObjectMapper;
  8 +import com.google.common.collect.Sets;
  9 +import lombok.RequiredArgsConstructor;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.apache.commons.lang3.RandomStringUtils;
  12 +import org.apache.commons.lang3.StringUtils;
  13 +import org.springframework.security.access.AccessDeniedException;
  14 +import org.springframework.security.crypto.password.PasswordEncoder;
  15 +import org.springframework.stereotype.Service;
  16 +import org.springframework.transaction.annotation.Transactional;
  17 +import org.springframework.util.Assert;
  18 +import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
  19 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  20 +import org.thingsboard.server.common.data.yunteng.core.exception.DataValidationException;
  21 +import org.thingsboard.server.common.data.yunteng.core.exception.FastIotException;
  22 +import org.thingsboard.server.common.data.yunteng.core.exception.NoneTenantAssetException;
  23 +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
  24 +import org.thingsboard.server.common.data.yunteng.dto.*;
  25 +import org.thingsboard.server.common.data.yunteng.dto.request.AccountReqDTO;
  26 +import org.thingsboard.server.common.data.yunteng.dto.request.RoleOrOrganizationReqDTO;
  27 +import org.thingsboard.server.common.data.yunteng.dto.request.SendResetPasswordEmailMsg;
  28 +import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO;
  29 +import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum;
  30 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
  31 +import org.thingsboard.server.common.data.yunteng.enums.RoleEnum;
  32 +import org.thingsboard.server.common.data.yunteng.enums.UserStatusEnum;
  33 +import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
  34 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  35 +import org.thingsboard.server.dao.yunteng.entities.*;
  36 +import org.thingsboard.server.dao.yunteng.mapper.*;
  37 +import org.thingsboard.server.dao.yunteng.service.*;
  38 +
  39 +import java.time.LocalDateTime;
  40 +import java.util.*;
  41 +import java.util.stream.Collectors;
  42 +
  43 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CHINA_MOBILE_PATTERN;
  44 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.EMAIL_PATTERN;
  45 +import static org.thingsboard.server.common.data.yunteng.constant.ModelConstants.TablePropertyMapping.*;
  46 +
  47 +@Service
  48 +@Slf4j
  49 +@RequiredArgsConstructor
  50 +public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> implements YtUserService {
  51 +
  52 + private final AdminSettingMapper adminSettingMapper;
  53 + private final ObjectMapper mapper;
  54 + private final TenantMapper tenantMapper;
  55 + private final RoleMapper roleMapper;
  56 + private final OrganizationMapper organizationMapper;
  57 + private final UserOrganizationMappingMapper userOrganizationMappingMapper;
  58 + private final UserRoleMapper userRoleMapper;
  59 + private final TenantRoleMapper tenantRoleMapper;
  60 +
  61 + private final YtSmsService ytSmsService;
  62 + private final MessageTemplateService messageTemplateService;
  63 + private final OrganizationService groupService;
  64 +
  65 + public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s";
  66 + private final PasswordEncoder passwordEncoder;
  67 + /** 默认密码 */
  68 + private static final String DEFAULT_PWD = "123456";
  69 +
  70 + @Override
  71 + public List<UserDetailsDTO> findUserDetailsByUsername(String username) {
  72 + // 多个租户可能存在多个username相同的情况
  73 + return baseMapper.findUserDetailsByUserName(username);
  74 + }
  75 +
  76 + @Override
  77 + @Transactional
  78 + public UserDTO saveAccount(UserDTO userDTO, boolean sendEmail, boolean sendMsg,boolean isSysadmin,String tenantId) {
  79 + boolean isAdminOperate = isSysadmin;
  80 + if (StringUtils.isAllBlank(userDTO.getUsername())) {
  81 + throw new DataValidationException("username is required");
  82 + }
  83 + validatePhoneNumberAndEmail(userDTO);
  84 + if (sendMsg && StringUtils.isAllBlank(userDTO.getPhoneNumber())) {
  85 + throw new DataValidationException(
  86 + "you must specify user phone number if you want send activate email to this user");
  87 + }
  88 + if (sendEmail && StringUtils.isAllBlank(userDTO.getEmail())) {
  89 + throw new DataValidationException(
  90 + "you must specify user email if you want send activate email to this user");
  91 + }
  92 + User user = new User();
  93 + userDTO.copyToEntity(user, ID, CREATE_TIME, UPDATE_TIME, TENANT_CODE, ACTIVATE_TOKEN);
  94 + boolean userExist;
  95 + if (StringUtils.isNotBlank(userDTO.getPassword())) {
  96 + user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
  97 + }
  98 + if (isAdminOperate) {
  99 + // 添加的租户管理员
  100 + if (StringUtils.isNotBlank(userDTO.getTenantCode())) {
  101 + user.setTenantCode(userDTO.getTenantCode());
  102 + user.setPassword(passwordEncoder.encode(DEFAULT_PWD));
  103 + int tenantExist =
  104 + tenantMapper.selectCount(
  105 + new QueryWrapper<Tenant>()
  106 + .lambda()
  107 + .eq(Tenant::getTenantCode, userDTO.getTenantCode()));
  108 + if (tenantExist == 0) {
  109 + throw new DataValidationException("tenant must exist");
  110 + }
  111 + } else {
  112 + // 添加的平台系统其他用户
  113 + user.setLevel(FastIotConstants.LevelValue.IS_OTHER_ADMIN);
  114 + user.setTenantCode(tenantId);
  115 + }
  116 + userExist =
  117 + baseMapper.selectCount(
  118 + new QueryWrapper<User>()
  119 + .lambda()
  120 + .eq(User::getUsername, userDTO.getUsername())
  121 + .eq(User::getTenantCode, userDTO.getTenantCode()))
  122 + > 0;
  123 + } else {
  124 + user.setLevel(FastIotConstants.LevelValue.IS_NORMAL);
  125 + user.setTenantCode(tenantId);
  126 + userExist =
  127 + baseMapper.selectCount(
  128 + new QueryWrapper<User>()
  129 + .lambda()
  130 + .eq(User::getUsername, userDTO.getUsername())
  131 + .eq(User::getTenantCode, tenantId))
  132 + > 0;
  133 + }
  134 + if (userExist) {
  135 + throw new DataValidationException(ErrorMessage.NAME_ALREADY_EXISTS.getMessage());
  136 + } else {
  137 + baseMapper.insert(user);
  138 + for (String roleId : userDTO.getRoleIds()) {
  139 + // 添加用户角色信息
  140 + UserRole userRole = new UserRole();
  141 + userRole.setUserId(user.getId());
  142 + userRole.setRoleId(roleId);
  143 + userRoleMapper.insert(userRole);
  144 + }
  145 + // 绑定用户和组织的关系
  146 + groupService.bindUserToOrganization(user.getId(), userDTO.getOrganizationIds());
  147 + user.copyToDTO(userDTO, PASSWORD, ACTIVATE_TOKEN);
  148 + return userDTO;
  149 + }
  150 + }
  151 +
  152 + private void validatePhoneNumberAndEmail(UserDTO userDTO) {
  153 + if (StringUtils.isNotBlank(userDTO.getPhoneNumber())) {
  154 + if (!CHINA_MOBILE_PATTERN.matcher(userDTO.getPhoneNumber()).matches()) {
  155 + throw new DataValidationException(ErrorMessage.PROVIDE_CORRECT_PHONE_NUMBER.getMessage());
  156 + }
  157 + }
  158 + if (StringUtils.isNotBlank(userDTO.getEmail())) {
  159 + if (!EMAIL_PATTERN.matcher(userDTO.getEmail()).matches()) {
  160 + throw new DataValidationException(ErrorMessage.PROVIDE_CORRECT_EMAIL.getMessage());
  161 + }
  162 + }
  163 + if (StringUtils.isAllBlank(userDTO.getEmail())
  164 + && StringUtils.isAllBlank(userDTO.getPhoneNumber())) {
  165 + throw new DataValidationException(ErrorMessage.PHONE_NUMBER_OR_EMAIL_REQUIRED.getMessage());
  166 + }
  167 + }
  168 +
  169 + @Override
  170 + public String getActivationLink(String userId,boolean isSysadmin,String tenantId) {
  171 + User user = baseMapper.selectById(userId);
  172 + if (!isSysadmin
  173 + && tenantId.equals(user.getTenantCode())) {
  174 + throw new AccessDeniedException(
  175 + "you don't have permission to get activation link for this user");
  176 + }
  177 + if (StringUtils.isAllBlank(user.getActivateToken())) {
  178 + throw new DataValidationException("user already activated");
  179 + }
  180 + try {
  181 + List<AdminSetting> generalSetting =
  182 + adminSettingMapper.selectList(
  183 + new QueryWrapper<AdminSetting>()
  184 + .lambda()
  185 + .eq(AdminSetting::getKey, ModelConstants.AdminSettingConfigKey.GENERAL_SETTING));
  186 + AdminSetting adminSetting = generalSetting.get(0);
  187 + JsonNode configNode = mapper.readTree(adminSetting.getConfigJson());
  188 + String baseUrl = configNode.get(FastIotConstants.ConfigJSONKey.BASE_URL).asText();
  189 + return String.format(ACTIVATE_URL_PATTERN, baseUrl, user.getActivateToken());
  190 + } catch (Exception e) {
  191 + throw new RuntimeException("error occurs");
  192 + }
  193 + }
  194 +
  195 + @Override
  196 + public UserInfoDTO me(String userId,String tenantId,Set<String> currentRoles) {
  197 + User user = baseMapper.selectById(userId);
  198 + UserInfoDTO userInfoDTO = new UserInfoDTO();
  199 + if (!StringUtils.isEmpty(user.getActivateToken())) {
  200 + userInfoDTO.setNeedSetPwd(false);
  201 + }
  202 + userInfoDTO.setUserId(userId);
  203 + userInfoDTO.setRealName(user.getRealName());
  204 + userInfoDTO.setAvatar(user.getAvatar());
  205 + userInfoDTO.setTenantCode(tenantId);
  206 + userInfoDTO.setRoles(currentRoles);
  207 + Set<Role> roles = roleMapper.selectRoleByUserId(userId);
  208 + Set<PlainRolesDTO> plainRolesDTOSet = Sets.newHashSet();
  209 + roles.forEach(
  210 + role -> {
  211 + PlainRolesDTO plainRolesDTO = new PlainRolesDTO();
  212 + plainRolesDTO.setRoleId(role.getId());
  213 + plainRolesDTO.setRoleName(role.getName());
  214 + plainRolesDTOSet.add(plainRolesDTO);
  215 + });
  216 + userInfoDTO.setPlainRoles(plainRolesDTOSet);
  217 + return userInfoDTO;
  218 + }
  219 +
  220 + @Override
  221 + public Optional<UserDTO> getUser(String userId,boolean isSysadmin,String tenantId) {
  222 + User user = baseMapper.selectById(userId);
  223 + if (user != null) {
  224 + UserDTO userDTO = new UserDTO();
  225 + user.copyToDTO(userDTO, PASSWORD, ACTIVATE_TOKEN);
  226 + if (!isSysadmin
  227 + && !tenantId.equals(user.getTenantCode())) {
  228 + return Optional.empty();
  229 + }
  230 + return Optional.of(userDTO);
  231 + } else {
  232 + return Optional.empty();
  233 + }
  234 + }
  235 +
  236 + @Override
  237 + @Transactional
  238 + public UserDTO updateUser(UserDTO userDTO,boolean isSysadmin,String tenantId) {
  239 + Assert.notNull(userDTO.getId(), "user is must be specified");
  240 + User user = baseMapper.selectById(userDTO.getId());
  241 + if (!isSysadmin
  242 + && !user.getTenantCode().equals(tenantId)) {
  243 + throw new NoneTenantAssetException("this user not belong to current tenant");
  244 + }
  245 + if (!user.getUsername().equals(userDTO.getUsername())) {
  246 + throw new DataValidationException("username is immutable");
  247 + }
  248 + validatePhoneNumberAndEmail(userDTO);
  249 + user.setRealName(userDTO.getRealName());
  250 + user.setEnabled(userDTO.isEnabled());
  251 + user.setPhoneNumber(userDTO.getPhoneNumber());
  252 + user.setEmail(userDTO.getEmail());
  253 + user.setAccountExpireTime(userDTO.getAccountExpireTime());
  254 + if (!userDTO.getPassword().equals("******")) {
  255 + user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
  256 + }
  257 + baseMapper.updateById(user);
  258 + user.copyToDTO(userDTO, PASSWORD, ACTIVATE_TOKEN);
  259 + return userDTO;
  260 + }
  261 +
  262 + @Override
  263 + public PageData<UserDTO> page(
  264 + Map<String, Object> queryMap,
  265 + boolean isSysadmin,
  266 + boolean isPlatformAdmin,
  267 + boolean isTenantAdmin,
  268 + String tenantId) {
  269 + IPage<UserDTO> userPage = new Page<>();
  270 + IPage<User> userIPage = getPage(queryMap, "create_time", true);
  271 + if (isSysadmin) {
  272 + String roleType = (String) queryMap.get("roleType");
  273 + if (StringUtils.isEmpty(roleType)) {
  274 + roleType = RoleEnum.ROLE_PLATFORM_ADMIN.name();
  275 + }
  276 + userPage =
  277 + baseMapper.getAdminUserPage(
  278 + userIPage, tenantId, roleType);
  279 + }
  280 + else if(isPlatformAdmin){
  281 + //平台管理员只能管理租户
  282 + userPage = baseMapper.selectAllTenantUser(userIPage);
  283 + }else if(isTenantAdmin){
  284 + Map<String, Object> map = new HashMap<>();
  285 + map.put("realName", queryMap.get("realName"));
  286 + map.put("username", queryMap.get("username"));
  287 + map.put("tenantCode", tenantId);
  288 + userPage = baseMapper.getUserPage(userIPage, map);
  289 + }
  290 + if (null != userPage) {
  291 + userPage
  292 + .getRecords()
  293 + .forEach(
  294 + record -> {
  295 + fillUserStatus(record);
  296 + if (StringUtils.isNotBlank(record.getActivateToken())) {
  297 + record.setHasPassword(true);
  298 + } else {
  299 + record.setHasPassword(false);
  300 + }
  301 + });
  302 + }
  303 + return getPageData(userPage, UserDTO.class);
  304 + }
  305 +
  306 + private void fillUserStatus(UserDTO userDTO) {
  307 + userDTO.setUserStatusEnum(UserStatusEnum.NORMAL);
  308 + if (!userDTO.isEnabled()) {
  309 + userDTO.setUserStatusEnum(UserStatusEnum.DISABLED);
  310 + } else {
  311 + if (userDTO.getAccountExpireTime() != null) {
  312 + if (userDTO.getAccountExpireTime().isBefore(LocalDateTime.now())) {
  313 + userDTO.setUserStatusEnum(UserStatusEnum.EXPIRED);
  314 + }
  315 + }
  316 + }
  317 + }
  318 +
  319 + @Override
  320 + @Transactional
  321 + public boolean deleteUser(Set<String> userIds,boolean isSysadmin,String tenantId) {
  322 + // 1. 判断是否所有的id都属于此人
  323 + if (!isSysadmin) {
  324 + int notTenantUserCount =
  325 + baseMapper.selectCount(
  326 + new QueryWrapper<User>()
  327 + .lambda()
  328 + .ne(User::getTenantCode, tenantId)
  329 + .in(User::getId, userIds));
  330 + if (notTenantUserCount > 0) {
  331 + throw new AccessDeniedException("cannot delete user that not belong to your tenant");
  332 + }
  333 + }
  334 + // 2. 删除人员对应的 role
  335 + roleMapper.deleteRoleUserMappingByUserIds(userIds);
  336 +
  337 + // 3. 解绑人员对应的group
  338 +
  339 + groupService.unBindUserToOrganization(userIds);
  340 +
  341 + // 4. 删除人员
  342 + baseMapper.deleteBatchIds(userIds);
  343 +
  344 + return true;
  345 + }
  346 +
  347 + @Override
  348 + @Transactional
  349 + public UserDTO saveTenantAdmin(UserDTO userDTO,boolean isSysadmin,String tenantId) {
  350 + if (StringUtils.isNotBlank(userDTO.getId())) {
  351 + return updateUser(userDTO,isSysadmin,tenantId);
  352 + }
  353 + validatePhoneNumberAndEmail(userDTO);
  354 + User user = new User();
  355 + userDTO.copyToEntity(user, ID, PASSWORD, CREATE_TIME, UPDATE_TIME, ACTIVATE_TOKEN);
  356 + user.setPassword(passwordEncoder.encode(DEFAULT_PWD));
  357 + List<User> users =
  358 + baseMapper.selectList(
  359 + new QueryWrapper<User>().lambda().eq(User::getUsername, userDTO.getUsername()));
  360 + if (!users.isEmpty()) {
  361 + throw new DataValidationException("用户已存在");
  362 + }
  363 + baseMapper.insert(user);
  364 + List<TenantRole> tenantRoleList =
  365 + tenantRoleMapper.selectList(
  366 + new QueryWrapper<TenantRole>()
  367 + .lambda()
  368 + .eq(TenantRole::getTenantCode, userDTO.getTenantCode()));
  369 + // 保存用户与角色的映射信息
  370 + if (null == tenantRoleList || tenantRoleList.size() == 0) {
  371 + throw new FastIotException(ErrorMessage.INVALID_PARAMETER);
  372 + }
  373 + for (TenantRole tenantRole : tenantRoleList) {
  374 + roleMapper.saveUserRoleMapping(user.getId(), tenantRole.getRoleId());
  375 + }
  376 + user.copyToDTO(userDTO, PASSWORD, ACTIVATE_TOKEN);
  377 + return userDTO;
  378 + }
  379 +
  380 + @Override
  381 + @Transactional
  382 + public void resetPassword(String userId,boolean isSysadmin,String tenantId) {
  383 + if (isSysadmin) {
  384 + baseMapper.setPassword2NullAndInsertActiveToken(
  385 + userId, RandomStringUtils.randomAlphabetic(10));
  386 + } else {
  387 + User user = baseMapper.selectById(userId);
  388 + if (user == null) {
  389 + return;
  390 + }
  391 + if (tenantId.equals(user.getTenantCode())) {
  392 + baseMapper.setPassword2NullAndInsertActiveToken(
  393 + userId, RandomStringUtils.randomAlphabetic(10));
  394 + }
  395 + }
  396 + }
  397 +
  398 + @Override
  399 + public List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber) {
  400 + return baseMapper.findUserDetailsByPhoneNumber(phoneNumber);
  401 + }
  402 +
  403 + @Override
  404 + public void sendRestPasswordMsg(SendResetPasswordEmailMsg msg) {
  405 + // 通过用户ID查询用户信息
  406 + User user = baseMapper.selectById(msg.getUserId());
  407 + if (null == user) {
  408 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  409 + }
  410 +
  411 + // 通过模板用途和状态查询模板信息
  412 + MessageTemplateDTO messageTemplateDTO = new MessageTemplateDTO();
  413 + String messageType = msg.getMessageTypeEnum().name();
  414 + messageTemplateDTO.setMessageType(messageType);
  415 + messageTemplateDTO.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_SET_PASSWORD.name());
  416 + messageTemplateDTO.setStatus(1);
  417 + List<MessageTemplateDTO> templateDTOList =
  418 + messageTemplateService.findMessageTemplate(messageTemplateDTO);
  419 + if (null == templateDTOList || templateDTOList.size() < 1) {
  420 + throw new DataValidationException(ErrorMessage.EXIST_ENABLE_TEMPLATE.getMessage());
  421 + }
  422 + if (messageType.equalsIgnoreCase(MessageTypeEnum.PHONE_MESSAGE.name())) {
  423 + SmsReqDTO smsReqDTO = new SmsReqDTO();
  424 + smsReqDTO.setPhoneNumbers(user.getPhoneNumber());
  425 + smsReqDTO.setId(templateDTOList.get(0).getId());
  426 + LinkedHashMap<String, String> params = new LinkedHashMap<>();
  427 + params.put("name", user.getRealName());
  428 + smsReqDTO.setParams(params);
  429 + ytSmsService.sendSms(smsReqDTO);
  430 + }
  431 + }
  432 +
  433 + @Override
  434 + public Optional<List<UserDTO>> getOrganizationUserByOrganizationId(String groupId,String tenantId) {
  435 + Organization group = organizationMapper.selectById(groupId);
  436 + if (group == null
  437 + || !group.getTenantCode().equals(tenantId)) {
  438 + return Optional.empty();
  439 + }
  440 + Set<String> userIds =
  441 + userOrganizationMappingMapper
  442 + .selectList(
  443 + new QueryWrapper<UserOrganizationMapping>()
  444 + .lambda()
  445 + .eq(UserOrganizationMapping::getOrganizationId, group))
  446 + .stream()
  447 + .map(UserOrganizationMapping::getUserId)
  448 + .collect(Collectors.toSet());
  449 + List<User> users = baseMapper.selectBatchIds(userIds);
  450 + return Optional.ofNullable(ReflectUtils.sourceToTarget(users, UserDTO.class));
  451 + }
  452 +
  453 + @Override
  454 + public String[] getUserRoleOrOrganization(RoleOrOrganizationReqDTO roleOrGroupReqDTO) {
  455 + String userId = roleOrGroupReqDTO.getUserId();
  456 + if (StringUtils.isEmpty(userId)) {
  457 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  458 + }
  459 + if (roleOrGroupReqDTO.isQueryRole()) {
  460 + List<String> roleIds =
  461 + userRoleMapper
  462 + .selectList(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, userId))
  463 + .stream()
  464 + .map(UserRole::getRoleId)
  465 + .collect(Collectors.toList());
  466 + return roleIds.toArray(new String[roleIds.size()]);
  467 + }
  468 + if (roleOrGroupReqDTO.isQueryOrganization()) {
  469 + List<String> roleIds =
  470 + userOrganizationMappingMapper
  471 + .selectList(
  472 + new QueryWrapper<UserOrganizationMapping>()
  473 + .lambda()
  474 + .eq(UserOrganizationMapping::getUserId, userId))
  475 + .stream()
  476 + .map(UserOrganizationMapping::getOrganizationId)
  477 + .collect(Collectors.toList());
  478 + return roleIds.toArray(new String[roleIds.size()]);
  479 + }
  480 + return null;
  481 + }
  482 +
  483 + @Override
  484 + @Transactional
  485 + public boolean changePassword(AccountReqDTO accountReqDTO) {
  486 + User user = baseMapper.selectById(accountReqDTO.getUserId());
  487 + if (null == user
  488 + || StringUtils.isEmpty(accountReqDTO.getPassword())
  489 + || StringUtils.isEmpty(accountReqDTO.getResetPassword())) {
  490 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  491 + }
  492 + if (!StringUtils.isEmpty(user.getPassword())) {
  493 + // 判断用户密码是否正确
  494 + boolean isMatch = passwordEncoder.matches(accountReqDTO.getPassword(), user.getPassword());
  495 + if (!isMatch) {
  496 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  497 + }
  498 + }
  499 + // 修改密码
  500 + user.setPassword(passwordEncoder.encode(accountReqDTO.getResetPassword()));
  501 + user.setActivateToken(RandomStringUtils.randomAlphabetic(10));
  502 + return baseMapper.updateById(user) > 0;
  503 + }
  504 +
  505 + @Override
  506 + public UserDTO accountExist(String userName,String tenantId) {
  507 + if (StringUtils.isEmpty(userName)) {
  508 + throw new DataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  509 + }
  510 + UserDTO userDTO = new UserDTO();
  511 + userDTO.setTenantCode(tenantId);
  512 + userDTO.setUsername(userName);
  513 + return baseMapper.findUserInfo(userDTO);
  514 + }
  515 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.AdminSetting;
  6 +
  7 +@Mapper
  8 +public interface AdminSettingMapper extends BaseMapper<AdminSetting> {
  9 +
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.AlarmContact;
  6 +
  7 +/** @Description 告警联系人持久化数据层 @Author cxy @Date 2021/11/2 11:52 */
  8 +@Mapper
  9 +public interface AlarmContactMapper extends BaseMapper<AlarmContact> {}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.thingsboard.server.dao.yunteng.entities.AlarmProfile;
  7 +
  8 +@Mapper
  9 +public interface AlarmProfileMapper extends BaseMapper<AlarmProfile> {
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.Device;
  8 +import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
  9 +import org.thingsboard.server.dao.yunteng.entities.YtDevice;
  10 +
  11 +import java.util.Map;
  12 +
  13 +@Mapper
  14 +public interface DeviceMapper extends BaseMapper<YtDevice> {
  15 +
  16 + IPage<DeviceDTO> getDevicePage(
  17 + IPage<?> page, @Param("queryMap") Map<String, Object> queryMap);
  18 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.thingsboard.server.common.data.DeviceProfile;
  7 +import org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO;
  8 +
  9 +import java.util.List;
  10 +
  11 +@Mapper
  12 +public interface DeviceProfileMapper extends BaseMapper<DeviceProfile> {
  13 +
  14 + List<DeviceProfileDTO> getDeviceProfileInfo(DeviceProfileDTO deviceProfileDTO);
  15 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.thingsboard.server.dao.yunteng.entities.DeviceType;
  7 +
  8 +@Mapper
  9 +public interface DeviceTypeMapper extends BaseMapper<DeviceType> {
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.MailLog;
  6 +
  7 +@Mapper
  8 +public interface MaiLogMapper extends BaseMapper<MailLog> {
  9 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.MenuDTO;
  8 +import org.thingsboard.server.dao.yunteng.entities.Menu;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +import java.util.Set;
  13 +
  14 +@Mapper
  15 +public interface MenuMapper extends BaseMapper<Menu> {
  16 + List<MenuDTO> selectTenantMenu(String tenantCode);
  17 +
  18 + List<MenuDTO> selectSysAdminMenu();
  19 +
  20 + List<MenuDTO> selectMyMenu(String userId);
  21 +
  22 + int deleteTenantMenuMappingByMenuIds(@Param("menuIds") Collection<String> menuIds);
  23 +
  24 + Set<String> selectTenantMenuIds(String tenantCode);
  25 +
  26 + Set<String> selectRoleMenuIds(String roleId);
  27 +
  28 + Set<String> getAllIdsByTenantCode(@Param("tenantCodes") Collection<String> tenantCodes);
  29 +
  30 + int addMenuToTenant(
  31 + @Param("tenantCode") String tenantCode, @Param("menuIds") Collection<String> menuIds);
  32 +
  33 + int addMenuToRole(
  34 + @Param("roleId") String roleId, @Param("menuIds") Collection<String> menuIds);
  35 +
  36 + int removeMenuFromTenant(
  37 + @Param("tenantCode") String tenantCode, @Param("menuIds") Collection<String> menuIds);
  38 +
  39 + int removeMenuFromRole(
  40 + @Param("roleId") String roleId, @Param("menuIds") Collection<String> menuIds);
  41 +
  42 + Set<String> getAllPermission();
  43 +
  44 + Set<String> getAllPermissionsByTenantCode(String tenantCode);
  45 +
  46 + Set<String> getAllPermissionsByUserId(String userId);
  47 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.apache.ibatis.annotations.Param;
  6 +import org.thingsboard.server.common.data.yunteng.dto.MessageConfigDTO;
  7 +import org.thingsboard.server.dao.yunteng.entities.MessageConfig;
  8 +
  9 +@Mapper
  10 +public interface MessageConfigMapper extends BaseMapper<MessageConfig> {
  11 + MessageConfigDTO getEnableConfigByMessageAndPlatform(
  12 + @Param("messageType") String messageType,
  13 + @Param("platformType") String platformType,
  14 + @Param("tenantCode") String tenantCode);
  15 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.MessageTemplateDTO;
  8 +import org.thingsboard.server.dao.yunteng.entities.MessageTemplate;
  9 +
  10 +import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +@Mapper
  14 +public interface MessageTemplateMapper extends BaseMapper<MessageTemplate> {
  15 + /**
  16 + * 获取模板分页数据
  17 + *
  18 + * @param page 分页数据
  19 + * @param queryMap 查询参数
  20 + * @return
  21 + */
  22 + IPage<MessageTemplateDTO> getTemplatePage(
  23 + IPage<?> page, @Param("queryMap") Map<String, Object> queryMap);
  24 +
  25 + /**
  26 + * 查询模板信息
  27 + * @param templateDTO 请求参数
  28 + * @return 模板信息列表 List<MessageTemplateDTO>
  29 + */
  30 + List<MessageTemplateDTO> findMessageTemplate(MessageTemplateDTO templateDTO);
  31 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.apache.ibatis.annotations.Param;
  6 +import org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO;
  7 +import org.thingsboard.server.dao.yunteng.entities.Organization;
  8 +
  9 +import java.util.Collection;
  10 +import java.util.List;
  11 +
  12 +@Mapper
  13 +public interface OrganizationMapper extends BaseMapper<Organization> {
  14 + /**
  15 + * 通过租户code和组织Id递归查询其组织及子组织的List
  16 + *
  17 + * @param tenantCode 租户code
  18 + * @param organizationIds 待查询的组织ID,可以为空
  19 + * @return 组织及子组织,直到叶节点
  20 + */
  21 + List<OrganizationDTO> findOrganizationTreeList(
  22 + @Param("tenantCode") String tenantCode, @Param("organizationIds") Collection<String> organizationIds);
  23 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.RateLimiterEntity;
  6 +
  7 +@Mapper
  8 +public interface RateLimiterMapper extends BaseMapper<RateLimiterEntity> {
  9 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.RoleDTO;
  8 +import org.thingsboard.server.dao.yunteng.entities.Role;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +import java.util.Set;
  13 +
  14 +@Mapper
  15 +public interface RoleMapper extends BaseMapper<Role> {
  16 + void deleteRoleBatchByTenantIds(@Param("tenantIds") Collection<String> tenantIds);
  17 +
  18 + int deleteRoleMenuMappingByRoleIds(@Param("roleIds") Collection<String> roleIds);
  19 +
  20 + int deleteRoleMenuMappingByMenuIds(@Param("menuIds") Collection<String> menuIds);
  21 +
  22 + int deleteRoleUserMappingByRoleIds(@Param("roleIds") Collection<String> roleIds);
  23 +
  24 + int deleteRoleUserMappingByUserIds(@Param("userIds") Collection<String> userIds);
  25 +
  26 + Set<String> getAllIdsByTenantCode(@Param("tenantCodes") Collection<String> tenantCodes);
  27 +
  28 + Set<String> checkRoleUserMappingByRoleIds(@Param("ids") Collection<String> ids);
  29 +
  30 + Set<Role> selectRoleByUserId(String userId);
  31 +
  32 + Set<String> getMenuIdsByRoleId(String roleId);
  33 +
  34 + void saveUserRoleMapping(@Param("userId")String userId,@Param("roleId")String roleId);
  35 +
  36 + List<RoleDTO> findRoleInfo(RoleDTO roleDTO);
  37 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.SmsLog;
  6 +
  7 +@Mapper
  8 +public interface SmsLogMapper extends BaseMapper<SmsLog> {
  9 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.SysDept;
  6 +
  7 +@Mapper
  8 +public interface SysDeptMapper extends BaseMapper<SysDept> {
  9 +
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.apache.ibatis.annotations.Param;
  6 +import org.thingsboard.server.common.data.yunteng.dto.SysDictItemDTO;
  7 +import org.thingsboard.server.dao.yunteng.entities.SysDictItem;
  8 +
  9 +import java.util.List;
  10 +
  11 +@Mapper
  12 +public interface SysDictItemMapper extends BaseMapper<SysDictItem> {
  13 + /**
  14 + * 通过dict表的Code和dictItem的codeText查询字典表的值
  15 + *
  16 + * @param dictCode 字典表Code
  17 + * @param itemValue 字典Item表文本值
  18 + * @return 返回字典Item表文本对应的文本
  19 + */
  20 + SysDictItemDTO getDictValueByCodeAndText(
  21 + @Param("dictCode") String dictCode,
  22 + @Param("itemValue") String itemValue);
  23 + /**
  24 + * 根据租户Code和字典表ID查询字典值
  25 + *
  26 + * @param dictId 字典表ID
  27 + * @return List<SysDictItemDTO>
  28 + */
  29 + List<SysDictItemDTO> getDictItemInfo(
  30 + @Param("dictId") String dictId,
  31 + @Param("dictCode") String dictCode);
  32 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.apache.ibatis.annotations.Param;
  6 +import org.thingsboard.server.common.data.yunteng.dto.SysDictDTO;
  7 +import org.thingsboard.server.dao.yunteng.entities.SysDict;
  8 +
  9 +@Mapper
  10 +public interface SysDictMapper extends BaseMapper<SysDict> {
  11 +
  12 + /**
  13 + * 根据租户Code和字典编码获取字典信息
  14 + *
  15 + * @param tenantCode 租户Code
  16 + * @param dictCode 字典信息
  17 + * @return SysDictDTO字典信息
  18 + */
  19 + SysDictDTO getDictInfoByCode(
  20 + @Param("tenantCode") String tenantCode,
  21 + @Param("dictCode") String dictCode);
  22 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.TenantDTO;
  8 +import org.thingsboard.server.dao.yunteng.entities.Tenant;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.Set;
  12 +
  13 +@Mapper
  14 +public interface TenantMapper extends BaseMapper<Tenant> {
  15 + Set<String> getTenantCodesByTenantIds(@Param("tenantIds") Collection<String> tenantIds);
  16 +
  17 + IPage<TenantDTO> getTenantPage(IPage<?> page, @Param("tenantName") String tenantName);
  18 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.thingsboard.server.dao.yunteng.entities.TenantMenu;
  7 +
  8 +@Mapper
  9 +public interface TenantMenuMapper extends BaseMapper<TenantMenu> {
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.TenantRole;
  6 +
  7 +@Mapper
  8 +public interface TenantRoleMapper extends BaseMapper<TenantRole> {
  9 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import com.baomidou.mybatisplus.core.metadata.IPage;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
  7 +import org.thingsboard.server.common.data.yunteng.dto.UserDTO;
  8 +import org.thingsboard.server.common.data.yunteng.dto.UserDetailsDTO;
  9 +import org.thingsboard.server.dao.yunteng.entities.User;
  10 +
  11 +import java.util.Collection;
  12 +import java.util.List;
  13 +import java.util.Map;
  14 +import java.util.Set;
  15 +
  16 +@Mapper
  17 +public interface UserMapper extends BaseMapper<User> {
  18 +
  19 + List<UserDetailsDTO> findUserDetailsByUserName(String username);
  20 +
  21 + List<UserDetailsDTO> findUserDetailsByPhoneNumber(String phoneNumber);
  22 +
  23 + IPage<UserDTO> getUserPage(IPage<?> page, @Param("queryMap") Map<String, Object> queryMap);
  24 +
  25 + IPage<UserDTO> getAdminUserPage(
  26 + IPage<?> page, @Param("tenantCode") String tenantCode, @Param("roleType") String roleType);
  27 +
  28 + IPage<UserDTO> selectAllTenantUser(IPage<?> page);
  29 +
  30 + Set<String> getAllIdsByTenantCode(@Param("tenantCodes") Collection<String> tenantCodes);
  31 +
  32 + void setPassword2NullAndInsertActiveToken(
  33 + @Param("userId") String userId, @Param("activeToken") String activeToken);
  34 +
  35 + UserDTO findUserInfo(UserDTO userDTO);
  36 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4 +import org.apache.ibatis.annotations.Mapper;
  5 +import org.thingsboard.server.dao.yunteng.entities.UserOrganizationMapping;
  6 +
  7 +@Mapper
  8 +public interface UserOrganizationMappingMapper extends BaseMapper<UserOrganizationMapping> {}
... ...
  1 +package org.thingsboard.server.dao.yunteng.mapper;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +import org.thingsboard.server.dao.yunteng.entities.UserRole;
  7 +
  8 +@Mapper
  9 +public interface UserRoleMapper extends BaseMapper<UserRole> {
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  5 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  6 +import com.baomidou.mybatisplus.core.metadata.IPage;
  7 +import com.baomidou.mybatisplus.core.metadata.OrderItem;
  8 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  9 +import org.apache.commons.lang3.StringUtils;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  12 +import org.thingsboard.server.common.data.yunteng.enums.OrderTypeEnum;
  13 +import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
  14 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  15 +import org.thingsboard.server.common.data.yunteng.utils.tools.TBPageData;
  16 +import org.thingsboard.server.dao.yunteng.entities.BaseEntity;
  17 +
  18 +import java.util.List;
  19 +import java.util.Map;
  20 +
  21 +import static org.thingsboard.server.common.data.yunteng.constant.QueryConstant.*;
  22 +
  23 +public abstract class AbstractBaseService<M extends BaseMapper<T>, T extends BaseEntity>
  24 + implements BaseService<T> {
  25 +
  26 + @Autowired protected M baseMapper;
  27 +
  28 + @Override
  29 + public List<T> findAllByTenant(String tenantId) {
  30 + QueryWrapper<T> wrapper = new QueryWrapper<>();
  31 + wrapper.eq(StringUtils.isNotBlank(tenantId), ModelConstants.TableFields.TENANT_ID, tenantId);
  32 + return baseMapper.selectList(wrapper);
  33 + }
  34 +
  35 + protected IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
  36 + int curPage = 1;
  37 + int limit = 10;
  38 + if (params.get(PAGE) != null) {
  39 + curPage = Integer.parseInt(params.get(PAGE).toString());
  40 + }
  41 +
  42 + if (params.get(PAGE_SIZE) != null) {
  43 + limit = Integer.parseInt(params.get(PAGE_SIZE).toString());
  44 + }
  45 +
  46 + Page<T> page = new Page<>(curPage, limit);
  47 + String orderField = (String) params.get(ORDER_FILED);
  48 + String order = (String) params.get(ORDER_TYPE);
  49 + if (StringUtils.isNotBlank(orderField) && StringUtils.isNotBlank(order)) {
  50 + return OrderTypeEnum.ASC.name().equalsIgnoreCase(order)
  51 + ? page.addOrder(OrderItem.asc(orderField))
  52 + : page.addOrder(OrderItem.desc(orderField));
  53 + } else if (StringUtils.isBlank(defaultOrderField)) {
  54 + return page;
  55 + } else {
  56 + if (isAsc) {
  57 + page.addOrder(OrderItem.asc(defaultOrderField));
  58 + } else {
  59 + page.addOrder(OrderItem.desc(defaultOrderField));
  60 + }
  61 + return page;
  62 + }
  63 + }
  64 +
  65 + protected <D> PageData<D> getPageData(IPage<?> iPage, Class<D> target) {
  66 + List<D> targetList = ReflectUtils.sourceToTarget(iPage.getRecords(), target);
  67 + return new PageData<>(targetList, iPage.getTotal());
  68 + }
  69 +
  70 + protected <D> PageData<D> getPageData(TBPageData<T> tbPageData, Class<D> target){
  71 + List<D> targetList = ReflectUtils.sourceToTarget(tbPageData.getData(),target);
  72 + return new PageData<>(targetList, tbPageData.getTotalElements());
  73 + }
  74 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +
  5 +import org.thingsboard.server.dao.yunteng.entities.BaseEntity;
  6 +
  7 +import java.util.List;
  8 +
  9 +public interface BaseService<T extends BaseEntity>{
  10 + List<T> findAllByTenant(String tenantId);
  11 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +
  5 +import org.thingsboard.server.common.data.yunteng.dto.MenuDTO;
  6 +
  7 +import java.util.List;
  8 +import java.util.Optional;
  9 +import java.util.Set;
  10 +
  11 +public interface MenuService {
  12 +
  13 + /**
  14 + * sysadmin获取所有的menu,但是不获取租户自己创建的menu
  15 + *
  16 + * @return list 树状menu
  17 + */
  18 + List<MenuDTO> getAllMenus(String tenantId);
  19 +
  20 + /**
  21 + * 获取自己的menu, 如果是tenant admin, 获取已分配的所有菜单,如果是普通用户,获取自己被租户管理员分配的菜单
  22 + *
  23 + * @return list 树状menu
  24 + */
  25 + List<MenuDTO> getMyMenus(String tenantId,String userId,boolean isSysAdmin,boolean isTenantAdmin);
  26 +
  27 + MenuDTO saveMenu(String tenantId,boolean isSysAdmin,MenuDTO menuDTO);
  28 +
  29 + Optional<MenuDTO> getMenu(String id);
  30 +
  31 + MenuDTO updateMenu(String tenantId,boolean isSysAdmin,MenuDTO menuDTO);
  32 +
  33 + boolean deleteMenus(String tenantId,String[] ids);
  34 +
  35 + boolean assignMenuToTenant(String tenantId,String[] menuId);
  36 +
  37 + boolean assignMenuToRole(String[] menuId, String roleId);
  38 +
  39 + Set<String> getMenuIdsByRoleId(String roleId);
  40 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +
  5 +import org.thingsboard.server.common.data.yunteng.dto.MessageTemplateDTO;
  6 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  7 +
  8 +import java.util.List;
  9 +import java.util.Map;
  10 +import java.util.Set;
  11 +
  12 +public interface MessageTemplateService {
  13 +
  14 + PageData<MessageTemplateDTO> page(Map<String, Object> queryMap);
  15 +
  16 + MessageTemplateDTO saveMessageTemplate(MessageTemplateDTO templateDTO);
  17 +
  18 + boolean deleteMessageTemplate(Set<String> ids);
  19 +
  20 + MessageTemplateDTO updateMessageTemplate(MessageTemplateDTO templateDTO);
  21 +
  22 + /**
  23 + * 查询模板信息
  24 + * @param templateDTO 请求信息
  25 + * @return MessageTemplateDTO模板信息
  26 + */
  27 + List<MessageTemplateDTO> findMessageTemplate(MessageTemplateDTO templateDTO);
  28 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +
  5 +import org.thingsboard.server.common.data.yunteng.dto.DeleteDTO;
  6 +import org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO;
  7 +
  8 +import java.util.List;
  9 +import java.util.Set;
  10 +
  11 +public interface OrganizationService {
  12 + OrganizationDTO saveOrganization(OrganizationDTO organizationDTO);
  13 +
  14 + boolean deleteOrganizations(DeleteDTO deleteDTO);
  15 +
  16 + List<OrganizationDTO> getMyOrganizations();
  17 +
  18 + OrganizationDTO updateOrganization(OrganizationDTO organizationDTO);
  19 +
  20 + void bindUserToOrganization(String userId, String[] organizationIds);
  21 +
  22 + void unBindUserToOrganization(Set<String> userIds);
  23 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +import org.thingsboard.server.common.data.yunteng.dto.RoleDTO;
  5 +import org.thingsboard.server.common.data.yunteng.dto.request.RoleReqDTO;
  6 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  7 +
  8 +import java.util.List;
  9 +import java.util.Map;
  10 +import java.util.Set;
  11 +
  12 +public interface RoleService {
  13 + PageData<RoleDTO> page(boolean isSysadmin,boolean isPlatformAdmin, String tenantId,Map<String, Object> queryMap);
  14 +
  15 + boolean deleteRole(String[] roleIds,String tenantId);
  16 +
  17 + Set<String> getPermissions(boolean isSysadmin,boolean isTenantAdmin,String tenantId,String useerId);
  18 +
  19 + void updateRoleStatus(String roleId, int status,boolean isSysadmin,String tenantId);
  20 +
  21 + RoleDTO saveOrUpdateRoleInfoWithMenu(RoleReqDTO roleReqDTO,boolean isSysadmin,boolean isPlatformAdmin,String tenantId);
  22 +
  23 + /**
  24 + * 查询所有的角色信息
  25 + * @param roleDTO 过滤条件
  26 + * @return 所有角色信息
  27 + */
  28 + List<RoleDTO> findRoleInfo(boolean isTenantAdmin,String tenantId,String userId,RoleDTO roleDTO);
  29 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +import org.thingsboard.server.common.data.yunteng.dto.DeviceDTO;
  4 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  5 +
  6 +import java.util.List;
  7 +import java.util.Map;
  8 +import java.util.Optional;
  9 +import java.util.Set;
  10 +
  11 +public interface YtDeviceService {
  12 + DeviceDTO insertOrUpdate(String tenantId,DeviceDTO deviceDTO);
  13 +
  14 + void deleteDevices(String tenantId,Set<String> ids);
  15 +
  16 + Optional<DeviceDTO> getDevice(String tenantId,String id);
  17 +
  18 + PageData<DeviceDTO> page(String tenantId,Map<String, Object> queryMap);
  19 +
  20 + /**
  21 + * 查询所有的设备信息
  22 + * @param deviceDTO 过滤参数
  23 + * @return List<DeviceDTO>
  24 + */
  25 + List<DeviceDTO> findDeviceInfo(String tenantId,DeviceDTO deviceDTO);
  26 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO;
  5 +
  6 +public interface YtSmsService {
  7 + boolean sendSms(SmsReqDTO smsReqDTO);
  8 +
  9 + boolean sendLoginSmsCode(String phoneNumber);
  10 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +
  4 +
  5 +import org.thingsboard.server.common.data.yunteng.dto.TenantDTO;
  6 +import org.thingsboard.server.common.data.yunteng.dto.request.TenantReqDTO;
  7 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  8 +
  9 +import java.util.List;
  10 +import java.util.Map;
  11 +import java.util.Optional;
  12 +
  13 +public interface YtTenantService {
  14 + TenantDTO createNewTenant(TenantReqDTO tenantReqDTO);
  15 +
  16 + TenantDTO updateTenant(TenantDTO tenantDTO);
  17 +
  18 + boolean deleteTenants(String[] ids);
  19 +
  20 + Optional<TenantDTO> findById(String id);
  21 +
  22 + PageData<TenantDTO> page(Map<String, Object> queryMap);
  23 +
  24 + TenantDTO updateOrCreateTenant(TenantReqDTO tenantReqDTO);
  25 +
  26 + List<String> getTenantRolesByTenantCode(String tenantCode);
  27 +}
... ...
  1 +package org.thingsboard.server.dao.yunteng.service;
  2 +
  3 +import org.thingsboard.server.common.data.yunteng.dto.UserDTO;
  4 +import org.thingsboard.server.common.data.yunteng.dto.UserDetailsDTO;
  5 +import org.thingsboard.server.common.data.yunteng.dto.UserInfoDTO;
  6 +import org.thingsboard.server.common.data.yunteng.dto.request.AccountReqDTO;
  7 +import org.thingsboard.server.common.data.yunteng.dto.request.RoleOrOrganizationReqDTO;
  8 +import org.thingsboard.server.common.data.yunteng.dto.request.SendResetPasswordEmailMsg;
  9 +import org.thingsboard.server.common.data.yunteng.utils.tools.PageData;
  10 +
  11 +import java.util.List;
  12 +import java.util.Map;
  13 +import java.util.Optional;
  14 +import java.util.Set;
  15 +
  16 +public interface YtUserService {
  17 + List<UserDetailsDTO> findUserDetailsByUsername(String username);
  18 +
  19 + UserDTO saveAccount(UserDTO userDTO, boolean sendEmail, boolean sendMsg,boolean isSysadmin,String tenantId);
  20 +
  21 + String getActivationLink(String userId,boolean isSysadmin,String tenantId);
  22 +
  23 + Optional<UserDTO> getUser(String userId,boolean isSysadmin,String tenantId);
  24 +
  25 + UserInfoDTO me(String userId,String tenantId,Set<String> currentRoles);
  26 +
  27 + PageData<UserDTO> page(Map<String, Object> queryMap,boolean isSysadmin,boolean isPlatformAdmin,boolean isTenantAdmin,String tenantId);
  28 +
  29 + UserDTO updateUser(UserDTO userDTO,boolean isSysadmin,String tenantId);
  30 +
  31 + boolean deleteUser(Set<String> userIds,boolean isSysadmin,String tenantId);
  32 +
  33 + UserDTO saveTenantAdmin(UserDTO userDTO,boolean isSysadmin,String tenantId);
  34 +
  35 + void resetPassword(String userId,boolean isSysadmin,String tenantId);
  36 +
  37 + List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber);
  38 +
  39 + /**
  40 + * 发送密码重置新消息
  41 + *
  42 + * @param msg 请求信息
  43 + */
  44 + void sendRestPasswordMsg(SendResetPasswordEmailMsg msg);
  45 +
  46 + /**
  47 + * 判断账号是否注册过
  48 + *
  49 + * @param username 账号
  50 + * @return 账号信息
  51 + */
  52 + UserDTO accountExist(String username,String tenantId);
  53 +
  54 + Optional<List<UserDTO>> getOrganizationUserByOrganizationId(String organizationId,String tenantId);
  55 +
  56 + /**
  57 + * 查询用户关联的Role或者Group
  58 + *
  59 + * @param roleOrOrganizationReqDTO 参数
  60 + * @return 返回关联的Role或者Group
  61 + */
  62 + String[] getUserRoleOrOrganization(RoleOrOrganizationReqDTO roleOrOrganizationReqDTO);
  63 +
  64 + /**
  65 + * 修改密码
  66 + *
  67 + * @param accountReqDTO 账号信息
  68 + * @return 修改成功、失败
  69 + */
  70 + boolean changePassword(AccountReqDTO accountReqDTO);
  71 +}
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.MenuMapper">
  5 + <resultMap type="org.thingsboard.server.common.data.yunteng.dto.MenuDTO" id="menuDTOMap">
  6 + <result property="id" column="id"/>
  7 + <result property="name" column="name"/>
  8 + <result property="parentId" column="parent_id"/>
  9 + <result property="path" column="path"/>
  10 + <result property="type" column="type" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
  11 + <result property="permission" column="permission"/>
  12 + <result property="sort" column="sort"/>
  13 + <result property="tenantCode" column="tenant_code"/>
  14 + <result property="component" column="component"/>
  15 + <result property="meta" column="meta"
  16 + typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
  17 + <result property="alias" column="alias"/>
  18 + <result property="redirect" column="redirect"/>
  19 + <result property="caseSensitive" column="case_sensitive"/>
  20 + <result property="createTime" column="create_time"/>
  21 + <result property="updateTime" column="update_time"/>
  22 + </resultMap>
  23 + <sql id="menuDTOMapColumn">
  24 + id,
  25 + parent_id,
  26 + path,
  27 + type,
  28 + permission,
  29 + sort,
  30 + component,
  31 + name,
  32 + meta,
  33 + alias,
  34 + redirect,
  35 + case_sensitive,
  36 + create_time,
  37 + update_time,
  38 + tenant_code
  39 + </sql>
  40 + <select id="selectTenantMenu" resultMap="menuDTOMap">
  41 + SELECT
  42 + <include refid="menuDTOMapColumn">
  43 + </include>
  44 + FROM sys_menu
  45 + WHERE id IN (SELECT menu_id FROM sys_tenant_menu WHERE tenant_code = #{tenantCode})
  46 + </select>
  47 +
  48 + <select id="selectMyMenu" resultMap="menuDTOMap">
  49 + SELECT
  50 + <include refid="menuDTOMapColumn">
  51 + </include>
  52 + FROM sys_menu
  53 + WHERE id IN (SELECT menu_id
  54 + FROM sys_role_menu
  55 + WHERE role_id IN (SELECT id FROM sys_role WHERE id in (SELECT role_id FROM sys_user_role WHERE user_id
  56 + = #{userId}) AND enabled=true))
  57 + </select>
  58 +
  59 + <delete id="deleteTenantMenuMappingByMenuIds">
  60 + DELETE FROM sys_tenant_menu WHERE menu_id IN
  61 + <foreach collection="menuIds" item="menuId" open="(" separator="," close=")">
  62 + #{menuId}
  63 + </foreach>
  64 + </delete>
  65 +
  66 + <select id="selectTenantMenuIds" resultType="java.lang.String">
  67 + SELECT menu_id
  68 + FROM sys_tenant_menu
  69 + WHERE tenant_code = #{tenantCode}
  70 + </select>
  71 +
  72 + <select id="selectRoleMenuIds" resultType="java.lang.String">
  73 + SELECT menu_id
  74 + FROM sys_role_menu
  75 + WHERE role_id = #{roleId}
  76 + </select>
  77 +
  78 + <insert id="addMenuToTenant">
  79 + INSERT INTO sys_tenant_menu(menu_id , tenant_code) VALUES
  80 + <foreach collection="menuIds" item="menuId" index="index" separator=",">
  81 + (#{menuId},#{tenantCode})
  82 + </foreach>
  83 + </insert>
  84 +
  85 + <insert id="addMenuToRole">
  86 + INSERT INTO sys_role_menu(menu_id , role_id) VALUES
  87 + <foreach collection="menuIds" item="menuId" index="index" separator=",">
  88 + (#{menuId},#{roleId})
  89 + </foreach>
  90 + </insert>
  91 + <delete id="removeMenuFromTenant">
  92 + DELETE FROM sys_tenant_menu WHERE
  93 + tenant_code =#{tenantCode} AND menu_id IN
  94 + <foreach collection="menuIds" item="menuId" open="(" separator="," close=")">
  95 + #{menuId}
  96 + </foreach>
  97 + </delete>
  98 +
  99 + <delete id="removeMenuFromRole">
  100 + DELETE FROM sys_role_menu WHERE
  101 + role_id =#{roleId} AND menu_id IN
  102 + <foreach collection="menuIds" item="menuId" open="(" separator="," close=")">
  103 + #{menuId}
  104 + </foreach>
  105 + </delete>
  106 +
  107 + <select id="getAllIdsByTenantCode" resultType="java.lang.String">
  108 + SELECT id FROM sys_menu WHERE tenant_code IN
  109 + <foreach collection="tenantCodes" item="tenantCode" open="(" separator="," close=")">
  110 + #{tenantCode}
  111 + </foreach>
  112 + </select>
  113 +
  114 + <select id="getAllPermission" resultType="java.lang.String">
  115 + SELECT permission
  116 + FROM sys_menu
  117 + </select>
  118 +
  119 + <select id="getAllPermissionsByTenantCode" resultType="java.lang.String">
  120 + SELECT permission
  121 + FROM sys_menu
  122 + WHERE id IN
  123 + (SELECT menu_id FROM sys_tenant_menu WHERE tenant_code = #{tenantCode})
  124 + </select>
  125 +
  126 + <select id="getAllPermissionsByUserId" resultType="java.lang.String">
  127 + SELECT permission
  128 + FROM sys_menu
  129 + WHERE id IN
  130 + (SELECT menu_id
  131 + FROM sys_role_menu
  132 + WHERE role_id IN (
  133 + SELECT role_id
  134 + FROM sys_user_role
  135 + WHERE user_id = #{userId}))
  136 + </select>
  137 +
  138 + <select id="selectSysAdminMenu" resultMap="menuDTOMap">
  139 + SELECT
  140 + <include refid="menuDTOMapColumn">
  141 + </include>
  142 + FROM sys_menu
  143 + WHERE type = 'SYSADMIN'
  144 + </select>
  145 +</mapper>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.OrganizationMapper">
  5 + <resultMap type="org.thingsboard.server.common.data.yunteng.dto.OrganizationDTO" id="organizationDTOMap">
  6 + <result property="id" column="id"/>
  7 + <result property="parentId" column="parent_id"/>
  8 + <result property="sort" column="sort"/>
  9 + <result property="name" column="name"/>
  10 + <result property="creator" column="creator"/>
  11 + <result property="createTime" column="create_time"/>
  12 + <result property="updater" column="updater"/>
  13 + <result property="updateTime" column="update_time"/>
  14 + <result property="remark" column="remark"/>
  15 + </resultMap>
  16 +
  17 + <select id="findOrganizationTreeList" resultMap="organizationDTOMap">
  18 + WITH RECURSIVE organization AS (
  19 + SELECT id, parent_id, name, sort,creator,create_time,updater,update_time,remark,tenant_code
  20 + FROM iotfs_organization
  21 + WHERE tenant_code = #{tenantCode}
  22 + <if test="organizationIds !=null and organizationIds.size() &gt; 0">
  23 + AND id IN
  24 + <foreach collection="organizationIds" item="organizationId" open="(" separator="," close=")">
  25 + #{organizationId}
  26 + </foreach>
  27 + </if>
  28 + UNION ALL
  29 + SELECT ig.id, ig.parent_id, ig.name, ig.sort,ig.creator,ig.create_time,ig.updater,ig.update_time,ig.remark,ig.tenant_code
  30 + FROM iotfs_organization ig
  31 + JOIN organization ON ig.parent_id = organization.id
  32 + WHERE ig.tenant_code = #{tenantCode}
  33 + )
  34 + SELECT id, parent_id, name, sort,creator,create_time,updater,update_time,remark,tenant_code
  35 + FROM organization WHERE tenant_code = #{tenantCode}
  36 + </select>
  37 +</mapper>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.RoleMapper">
  5 + <resultMap id="roleDtoMap" type="org.thingsboard.server.common.data.yunteng.dto.RoleDTO">
  6 + <result property="id" column="id"/>
  7 + <result property="name" column="name"/>
  8 + <result property="roleType" column="role_type"/>
  9 + <result property="tenantCode" column="tenant_code"/>
  10 + <result property="enabled" column="enabled"/>
  11 + <result property="creator" column="creator"/>
  12 + <result property="createTime" column="create_time"/>
  13 + <result property="updater" column="updater"/>
  14 + <result property="updateTime" column="update_time"/>
  15 + <result property="code" column="code"/>
  16 + </resultMap>
  17 + <select id="checkRoleUserMappingByRoleIds" resultType="java.lang.String">
  18 + SELECT user_id FROM sys_user_role WHERE role_id IN
  19 + <foreach collection="ids" item="id" open="(" separator="," close=")">
  20 + #{id}
  21 + </foreach>
  22 + GROUP BY user_id
  23 + </select>
  24 + <delete id="deleteRoleBatchByTenantIds">
  25 + DELETE FROM sys_role WHERE tenant_code in (
  26 + SELECT tenant_code FROM sys_tenant WHERE id IN
  27 + <foreach collection="tenantIds" item="tenantId" open="(" separator="," close=")">
  28 + #{tenantId}
  29 + </foreach>
  30 + )
  31 + </delete>
  32 +
  33 + <delete id="deleteRoleMenuMappingByRoleIds">
  34 + DELETE FROM sys_role_menu WHERE role_id IN
  35 + <foreach collection="roleIds" item="roleId" open="(" separator="," close=")">
  36 + #{roleId}
  37 + </foreach>
  38 + </delete>
  39 +
  40 + <delete id="deleteRoleUserMappingByRoleIds">
  41 + DELETE FROM sys_user_role WHERE role_id IN
  42 + <foreach collection="roleIds" item="roleId" open="(" separator="," close=")">
  43 + #{roleId}
  44 + </foreach>
  45 + </delete>
  46 +
  47 + <delete id="deleteRoleUserMappingByUserIds">
  48 + DELETE FROM sys_user_role WHERE user_id IN
  49 + <foreach collection="userIds" item="userId" open="(" separator="," close=")">
  50 + #{userId}
  51 + </foreach>
  52 + </delete>
  53 +
  54 + <delete id="deleteRoleMenuMappingByMenuIds">
  55 + DELETE FROM sys_role_menu WHERE menu_id IN
  56 + <foreach collection="menuIds" item="menuId" open="(" separator="," close=")">
  57 + #{menuId}
  58 + </foreach>
  59 + </delete>
  60 +
  61 + <select id="getAllIdsByTenantCode" resultType="java.lang.String">
  62 + SELECT id from sys_role WHERE tenant_code IN
  63 + <foreach collection="tenantCodes" item="tenantCode" open="(" separator="," close=")">
  64 + #{tenantCode}
  65 + </foreach>
  66 + </select>
  67 +
  68 + <select id="selectRoleByUserId" resultType="org.thingsboard.server.dao.yunteng.entities.Role">
  69 + SELECT *
  70 + FROM sys_role
  71 + WHERE id IN (SELECT role_id FROM sys_user_role WHERE user_id = #{userId})
  72 + </select>
  73 +
  74 + <select id="getMenuIdsByRoleId" resultType="java.lang.String">
  75 + SELECT menu_id
  76 + FROM sys_role_menu
  77 + WHERE role_id = #{roleId}
  78 + </select>
  79 +
  80 + <delete id="saveUserRoleMapping">
  81 + INSERT INTO sys_user_role(user_id, role_id)
  82 + VALUES (#{userId}, #{roleId})
  83 + </delete>
  84 +
  85 + <select id="findRoleInfo" resultMap="roleDtoMap">
  86 + SELECT id,name,role_type,tenant_code,creator,create_time,updater,update_time,remark,code FROM sys_role
  87 + <where>
  88 + enabled='t'
  89 + <if test="roleType !=null and roleType !=''">AND role_type=#{roleType}</if>
  90 + <if test="tenantCode !=null and tenantCode !=''">AND tenant_code=#{tenantCode}</if>
  91 + <if test="code !=null and code !=''">AND code=#{code}</if>
  92 + <if test="roleIds !=null">OR id IN
  93 + <foreach collection="roleIds" item="id" open="(" separator="," close=")">
  94 + #{id}
  95 + </foreach>
  96 + </if>
  97 + </where>
  98 +
  99 + </select>
  100 +</mapper>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.SysDictItemMapper">
  5 + <resultMap id="sysDictItemDTOMap" type="org.thingsboard.server.common.data.yunteng.dto.SysDictItemDTO">
  6 + <result property="id" column="id"/>
  7 + <result property="dictId" column="dict_id"/>
  8 + <result property="itemText" column="item_text"/>
  9 + <result property="itemValue" column="item_value"/>
  10 + <result property="description" column="description"/>
  11 + <result property="sort" column="sort"/>
  12 + <result property="status" column="status"/>
  13 + <result property="creator" column="creator"/>
  14 + <result property="createTime" column="create_time"/>
  15 + <result property="updater" column="updater"/>
  16 + <result property="updateTime" column="update_time"/>
  17 + <association property="sysDict" javaType="org.thingsboard.server.common.data.yunteng.dto.SysDictDTO">
  18 + <result property="dictName" column="dict_name"/>
  19 + <result property="dictCode" column="dict_code"/>
  20 + </association>
  21 + </resultMap>
  22 + <sql id="columns">
  23 + sdi.id,sdi.dict_id,sdi.item_text,sdi.item_value,sdi.description,sdi.sort,
  24 + sdi.status,sdi.create_time,sdi.update_time,sd. dict_name,sd.dict_code
  25 + </sql>
  26 + <select id="getDictValueByCodeAndText" resultMap="sysDictItemDTOMap">
  27 + SELECT
  28 + sd. dict_name,sd.dict_code,sdi.id,sdi.item_text,sdi.sort
  29 + FROM
  30 + sys_dict_item sdi
  31 + LEFT JOIN sys_dict sd ON sd.ID = sdi.dict_id
  32 + <where>
  33 + sdi.status = 1
  34 + <if test="tenantCode !=null and tenantCode!=''">AND sd.tenant_code=#{tenantCode}</if>
  35 + <if test="dictCode !=null and dictCode!=''">AND sd.dict_code = #{dictCode}</if>
  36 + <if test="itemValue !=null and itemValue!=''">AND sdi.item_value = #{itemValue}</if>
  37 + </where>
  38 + </select>
  39 +
  40 + <select id="getDictItemInfo" resultMap="sysDictItemDTOMap">
  41 + SELECT
  42 + <include refid="columns"/>
  43 + FROM
  44 + sys_dict_item sdi
  45 + LEFT JOIN sys_dict sd ON sd.ID = sdi.dict_id
  46 + <where>
  47 + <if test="dictId !=null and dictId!=''">AND sdi.dict_id=#{dictId}</if>
  48 + <if test="dictCode !=null and dictCode!=''">AND sd.dict_code=#{dictCode}</if>
  49 + </where>
  50 + </select>
  51 +</mapper>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.SysDictMapper">
  5 + <resultMap id="smsDictDTOMap" type="org.thingsboard.server.common.data.yunteng.dto.SysDictDTO" >
  6 + <result property="id" column="id"/>
  7 + <result property="dictName" column="dict_name"/>
  8 + <result property="dictCode" column="dict_code"/>
  9 + <result property="description" column="description"/>
  10 + <result property="tenantCode" column="tenant_code"/>
  11 + <result property="creator" column="creator"/>
  12 + <result property="createTime" column="create_time"/>
  13 + <result property="updater" column="updater"/>
  14 + <result property="updateTime" column="update_time"/>
  15 + </resultMap>
  16 + <sql id="columns">
  17 + id,dict_name,dict_code,description,tenant_code,creator,create_time,updater,update_time
  18 + </sql>
  19 + <select id="getDictInfoByCode" resultMap="smsDictDTOMap">
  20 + SELECT
  21 + <include refid="columns"/>
  22 + FROM sys_dict
  23 + <where>
  24 + <if test="tenantCode != null and tenantCode !=''">tenant_code=#{tenantCode}</if>
  25 + <if test="dictCode != null and dictCode !=''">AND dict_code=#{dictCode}</if>
  26 + </where>
  27 + </select>
  28 +</mapper>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.UserMapper">
  5 + <resultMap type="org.thingsboard.server.common.data.yunteng.dto.UserDetailsDTO" id="userDetailsMap">
  6 + <result property="id" column="id"/>
  7 + <result property="username" column="username"/>
  8 + <result property="password" column="password"/>
  9 + <result property="enabled" column="enabled"/>
  10 + <result property="accountExpireTime" column="account_expire_time"/>
  11 + <association property="tenant" javaType="org.thingsboard.server.common.data.yunteng.dto.TenantDTO">
  12 + <result column="tenant_name" property="name"/>
  13 + <result column="tenant_code" property="tenantCode"/>
  14 + <result column="tenant_enabled" property="enabled"/>
  15 + <result column="tenant_expire_time" property="tenantExpireTime"/>
  16 + </association>
  17 + <collection property="roles" javaType="java.util.Set" ofType="org.thingsboard.server.common.data.yunteng.dto.UserDetailRoleDTO">
  18 + <result column="role_type" property="roleType" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
  19 + </collection>
  20 + </resultMap>
  21 + <resultMap type="org.thingsboard.server.common.data.yunteng.dto.UserDTO" id="userDTOMap">
  22 + <result property="id" column="id"/>
  23 + <result property="username" column="username"/>
  24 + <result property="password" column="password"/>
  25 + <result property="realName" column="real_name"/>
  26 + <result property="enabled" column="enabled"/>
  27 + <result property="phoneNumber" column="phone_number"/>
  28 + <result property="email" column="email"/>
  29 + <result property="avatar" column="avatar"/>
  30 + <result property="deptId" column="dept_id"/>
  31 + <result property="tenantName" column="tenant_name"/>
  32 + <result property="tenantCode" column="tenant_code"/>
  33 + <result property="createTime" column="create_time"/>
  34 + <result property="updateTime" column="update_time"/>
  35 + <result property="accountExpireTime" column="account_expire_time"/>
  36 + <result property="level" column="level"/>
  37 + </resultMap>
  38 +
  39 + <sql id="columns">
  40 + su.id AS id,
  41 + su.username AS username,
  42 + su.password AS password,
  43 + su.phone_number AS phone_number,
  44 + su.email AS email,
  45 + su.avatar AS avatar,
  46 + su.enabled AS enabled,
  47 + su.account_expire_time AS account_expire_time,
  48 + su.tenant_code AS tenant_code,
  49 + su.create_time AS create_time,
  50 + su.update_time AS update_time,
  51 + su.real_name AS real_name,
  52 + su.dept_id AS dept_id,
  53 + su.level AS level
  54 + </sql>
  55 +
  56 + <select id="findUserDetailsByUserName" resultMap="userDetailsMap">
  57 + SELECT su.id as id,
  58 + su.username as username,
  59 + su.password as password,
  60 + su.enabled as enabled,
  61 + su.account_expire_time as account_expire_time,
  62 + st.name as tenant_name,
  63 + st.tenant_code as tenant_code,
  64 + st.enabled as tenant_enabled,
  65 + st.tenant_expire_time as tenant_expire_time,
  66 + rr.role_type as role_type
  67 + FROM sys_user su
  68 + LEFT JOIN sys_tenant st ON su.tenant_code = st.tenant_code
  69 + LEFT JOIN (
  70 + SELECT sur.user_id,
  71 + sr.role_type
  72 + FROM sys_user_role sur
  73 + LEFT JOIN sys_role sr ON sur.role_id = sr.id
  74 + WHERE sur.user_id = (SELECT id FROM sys_user WHERE username = #{username})
  75 + ) rr ON su.id = rr.user_id
  76 + WHERE su.username = #{username};
  77 + </select>
  78 +
  79 + <select id="getUserPage" resultMap="userDTOMap">
  80 + SELECT
  81 + <include refid="columns"/>,
  82 + st.name AS tenant_name
  83 + FROM sys_user su
  84 + LEFT JOIN sys_tenant st ON su.tenant_code = st.tenant_code
  85 + <where>
  86 + <if test="queryMap.realName!=null and queryMap.realName!=''">
  87 + AND su.real_name LIKE CONCAT('%',#{queryMap.realName}::TEXT,'%')
  88 + </if>
  89 + <if test="queryMap.username!=null and queryMap.username!=''">
  90 + AND su.username LIKE CONCAT('%',#{queryMap.username}::TEXT,'%')
  91 + </if>
  92 + <if test="queryMap.tenantCode !=null and queryMap.tenantCode!=''">
  93 + AND su.tenant_code=#{queryMap.tenantCode}
  94 + </if>
  95 + </where>
  96 + </select>
  97 +
  98 + <select id="getAdminUserPage" resultMap="userDTOMap">
  99 + SELECT
  100 + <include refid="columns"/>,
  101 + st.name AS tenant_name
  102 + FROM sys_user su
  103 + LEFT JOIN sys_tenant st ON su.tenant_code = st.tenant_code
  104 + WHERE su.ID IN (SELECT user_id
  105 + FROM sys_user_role
  106 + WHERE role_id IN (SELECT ID
  107 + FROM sys_role
  108 + WHERE role_type = #{roleType}
  109 + <if test="roleType == 'ROLE_PLATFORM_ADMIN'">
  110 + OR role_type = 'ROLE_SYS_ADMIN'
  111 + </if>
  112 + AND tenant_code = #{tenantCode}))
  113 + </select>
  114 + <select id="selectAllTenantUser" resultMap="userDTOMap">
  115 + SELECT
  116 + <include refid="columns"/>,
  117 + st.name AS tenant_name
  118 + FROM sys_user su
  119 + LEFT JOIN sys_tenant st ON su.tenant_code = st.tenant_code
  120 + WHERE su.level = 2;
  121 + </select>
  122 + <select id="getAllIdsByTenantCode" resultType="java.lang.String">
  123 + SELECT id FROM sys_user WHERE tenant_code IN
  124 + <foreach collection="tenantCodes" item="tenantCode" open="(" separator="," close=")">
  125 + #{tenantCode}
  126 + </foreach>
  127 + </select>
  128 +
  129 + <update id="setPassword2NullAndInsertActiveToken">
  130 + UPDATE sys_user
  131 + SET password=null,
  132 + activate_token=#{activeToken}
  133 + WHERE id = #{userId}
  134 + </update>
  135 +
  136 + <select id="findUserDetailsByPhoneNumber" resultMap="userDetailsMap">
  137 + SELECT su.id as id,
  138 + su.username as username,
  139 + su.password as password,
  140 + su.enabled as enabled,
  141 + su.account_expire_time as account_expire_time,
  142 + st.name as tenant_name,
  143 + st.tenant_code as tenant_code,
  144 + st.enabled as tenant_enabled,
  145 + st.tenant_expire_time as tenant_expire_time,
  146 + rr.role_type as role_type
  147 + FROM sys_user su
  148 + LEFT JOIN sys_tenant st ON su.tenant_code = st.tenant_code
  149 + LEFT JOIN (
  150 + SELECT sur.user_id,
  151 + sr.role_type
  152 + FROM sys_user_role sur
  153 + LEFT JOIN sys_role sr ON sur.role_id = sr.id
  154 + WHERE sur.user_id = (SELECT id FROM sys_user WHERE phone_number = #{phoneNumber})
  155 + ) rr ON su.id = rr.user_id
  156 + WHERE su.phone_number = #{phoneNumber};
  157 + </select>
  158 + <select id="findUserInfo" resultMap="userDTOMap">
  159 + SELECT
  160 + <include refid="columns"/>
  161 + FROM sys_user su
  162 + <where>
  163 + <if test="username !=null and username!=''">AND su.username=#{username}</if>
  164 + <if test="tenantCode !=null and tenantCode!=''">AND su.tenant_code=#{tenantCode}</if>
  165 + </where>
  166 + </select>
  167 +</mapper>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +
  4 +<mapper namespace="org.thingsboard.server.dao.yunteng.mapper.UserRoleMapper">
  5 + <resultMap type="org.thingsboard.server.common.data.yunteng.dto.UserRoleDTO" id="userRoleMap">
  6 + <result property="userId" column="user_id"/>
  7 + <result property="roleId" column="role_id"/>
  8 + </resultMap>
  9 +</mapper>
... ...
... ... @@ -55,7 +55,7 @@
55 55 <cassandra-driver-core.version>3.11.0</cassandra-driver-core.version>
56 56 <guava.version>30.0-jre</guava.version>
57 57 <caffeine.version>2.6.1</caffeine.version>
58   - <commons-lang3.version>3.4</commons-lang3.version>
  58 + <commons-lang3.version>3.12.0</commons-lang3.version>
59 59 <commons-codec.version>1.15</commons-codec.version>
60 60 <commons-io.version>2.11.0</commons-io.version>
61 61 <commons-logging.version>1.2</commons-logging.version>
... ... @@ -130,6 +130,13 @@
130 130 <!-- BLACKBOX TEST SCOPE -->
131 131 <testcontainers.version>1.16.0</testcontainers.version>
132 132 <zeroturnaround.version>1.12</zeroturnaround.version>
  133 + <!-- 新增的开始 -->
  134 + <mybatis-plus.version>3.4.1</mybatis-plus.version>
  135 + <aliyun.sdk.core>4.5.20</aliyun.sdk.core>
  136 + <aliyun.sdk.dysmsapi>2.1.0</aliyun.sdk.dysmsapi>
  137 + <jakarta.mail.version>2.0.1</jakarta.mail.version>
  138 + <io.minio.version>8.3.1</io.minio.version>
  139 + <com.alibaba.easyexcel.version>3.0.1</com.alibaba.easyexcel.version>
133 140 </properties>
134 141
135 142 <modules>
... ...