Commit d1cb0d70d272c7ccba37eefdb8d6f8b7582915b2

Authored by xp.Huang
2 parents 846f63ff f7faa072

Merge branch '20220304' into 'master'

feat: 密码找回

See merge request huang/thingsboard3.3.2!55
1 package org.thingsboard.server.controller.yunteng; 1 package org.thingsboard.server.controller.yunteng;
2 2
  3 +import io.swagger.annotations.ApiOperation;
3 import lombok.RequiredArgsConstructor; 4 import lombok.RequiredArgsConstructor;
4 import org.springframework.util.Assert; 5 import org.springframework.util.Assert;
5 -import org.springframework.web.bind.annotation.PathVariable;  
6 -import org.springframework.web.bind.annotation.PostMapping;  
7 -import org.springframework.web.bind.annotation.RequestMapping;  
8 -import org.springframework.web.bind.annotation.RestController; 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.request.AccountReqDTO;
  9 +import org.thingsboard.server.common.data.yunteng.dto.request.SendResetPasswordEmailMsg;
  10 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
9 import org.thingsboard.server.dao.yunteng.service.YtSmsService; 11 import org.thingsboard.server.dao.yunteng.service.YtSmsService;
  12 +import org.thingsboard.server.dao.yunteng.service.YtUserService;
10 13
11 import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CHINA_MOBILE_PATTERN; 14 import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CHINA_MOBILE_PATTERN;
12 15
@@ -16,11 +19,24 @@ import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstan @@ -16,11 +19,24 @@ import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstan
16 public class YtNoAuthController { 19 public class YtNoAuthController {
17 20
18 private final YtSmsService smsService; 21 private final YtSmsService smsService;
  22 + private final YtUserService userService;
19 23
20 @PostMapping("/sendLoginSmsCode/{phoneNumber}") 24 @PostMapping("/sendLoginSmsCode/{phoneNumber}")
21 public boolean sendVerificationCode(@PathVariable("phoneNumber") String phoneNumber) { 25 public boolean sendVerificationCode(@PathVariable("phoneNumber") String phoneNumber) {
22 Assert.isTrue( 26 Assert.isTrue(
23 CHINA_MOBILE_PATTERN.matcher(phoneNumber).matches(), "please input correct phone number"); 27 CHINA_MOBILE_PATTERN.matcher(phoneNumber).matches(), "please input correct phone number");
24 - return smsService.sendLoginSmsCode(phoneNumber); 28 + return smsService.sendSmsCode(phoneNumber, MsgTemplatePurposeEnum.FOR_LOGIN);
  29 + }
  30 +
  31 + @PostMapping("/reset/{userId}")
  32 + @ApiOperation("密码找回")
  33 + public void saveForgetPassword(@PathVariable("phoneNumber") String phoneNumber,@RequestBody AccountReqDTO forget) throws ThingsboardException {
  34 + userService.forgetPassword(phoneNumber,forget);
  35 + }
  36 +
  37 + @PostMapping("/resetCode/{phoneNumber}")
  38 + @ApiOperation("密码找回短信验证码")
  39 + public void forgetPasswordCode(@PathVariable("phoneNumber") String phoneNumber) {
  40 + smsService.sendSmsCode(phoneNumber, MsgTemplatePurposeEnum.FOR_FORGET_PASSWORD);
25 } 41 }
26 } 42 }
@@ -10,6 +10,7 @@ import org.thingsboard.server.dao.yunteng.service.YtUserService; @@ -10,6 +10,7 @@ import org.thingsboard.server.dao.yunteng.service.YtUserService;
10 @RestController 10 @RestController
11 @RequestMapping("/api/yt/tenant") 11 @RequestMapping("/api/yt/tenant")
12 @RequiredArgsConstructor 12 @RequiredArgsConstructor
  13 +@Deprecated
13 public class YtTenantController extends BaseController { 14 public class YtTenantController extends BaseController {
14 15
15 private final YtUserService userService; 16 private final YtUserService userService;
1 package org.thingsboard.server.common.data.yunteng.dto; 1 package org.thingsboard.server.common.data.yunteng.dto;
2 2
  3 +import com.fasterxml.jackson.databind.JsonNode;
3 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
  7 +import org.thingsboard.common.util.JacksonUtil;
  8 +import org.thingsboard.server.common.data.DeviceProfileType;
6 import org.thingsboard.server.common.data.DeviceTransportType; 9 import org.thingsboard.server.common.data.DeviceTransportType;
7 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 10 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
8 import org.thingsboard.server.common.data.yunteng.common.AddGroup; 11 import org.thingsboard.server.common.data.yunteng.common.AddGroup;
@@ -50,26 +53,39 @@ public class DeviceProfileDTO extends TenantDTO { @@ -50,26 +53,39 @@ public class DeviceProfileDTO extends TenantDTO {
50 /**默认消息队列*/ 53 /**默认消息队列*/
51 private String defaultQueueName; 54 private String defaultQueueName;
52 55
  56 + /**设备配置图片*/
  57 + private String image;
  58 + /**是否默认设备配置*/
  59 + private boolean isDefault;
  60 + private String type;
  61 +
53 public DeviceProfileDTO() { 62 public DeviceProfileDTO() {
54 } 63 }
55 64
56 - public DeviceProfileDTO(UUID id, String name, Long time, String description, DeviceTransportType transportType, UUID defaultRuleChainId) { 65 + public DeviceProfileDTO(UUID id, String name, Long time, String description, DeviceTransportType transportType, UUID defaultRuleChainId,boolean isDefault,String image,DeviceProfileType type,Object profileData) {
57 setId(id.toString()); 66 setId(id.toString());
58 setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC)); 67 setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC));
59 this.name = name; 68 this.name = name;
  69 + this.isDefault = isDefault;
  70 + this.image = image;
60 this.description = description; 71 this.description = description;
  72 + this.type = type.name();
61 this.transportType = transportType.name(); 73 this.transportType = transportType.name();
62 this.defaultRuleChainId = Optional.ofNullable(defaultRuleChainId).map(chainId -> chainId.toString()).orElse(null); 74 this.defaultRuleChainId = Optional.ofNullable(defaultRuleChainId).map(chainId -> chainId.toString()).orElse(null);
  75 + this.profileData = JacksonUtil.convertValue(profileData, DeviceProfileData.class);
  76 +
63 } 77 }
64 78
65 - public DeviceProfileDTO(UUID id, String name, Long time, String description, String convertJs, DeviceTransportType transportType, DeviceProfileData profileData, String defaultRuleChainId) { 79 + public DeviceProfileDTO(UUID id, String name, Long time, String description, DeviceTransportType transportType, String defaultRuleChainId,boolean isDefault,String image,DeviceProfileType type, String convertJs) {
66 setId(id.toString()); 80 setId(id.toString());
67 setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC)); 81 setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC));
68 this.name = name; 82 this.name = name;
  83 + this.isDefault = isDefault;
  84 + this.image = image;
69 this.description = description; 85 this.description = description;
  86 + this.type = type.name();
70 this.convertJs = convertJs; 87 this.convertJs = convertJs;
71 this.transportType = transportType.name(); 88 this.transportType = transportType.name();
72 this.defaultRuleChainId = defaultRuleChainId.toString(); 89 this.defaultRuleChainId = defaultRuleChainId.toString();
73 - this.profileData = profileData;  
74 } 90 }
75 } 91 }
@@ -106,9 +106,10 @@ public class YtSmsServiceImpl implements YtSmsService { @@ -106,9 +106,10 @@ public class YtSmsServiceImpl implements YtSmsService {
106 return false; 106 return false;
107 } 107 }
108 108
  109 +
109 @Override 110 @Override
110 @Transactional 111 @Transactional
111 - public boolean sendLoginSmsCode(String phoneNumber) { 112 + public boolean sendSmsCode(String phoneNumber,MsgTemplatePurposeEnum purpose) {
112 // 检查手机号码是否存在系统,以免乱发消息 113 // 检查手机号码是否存在系统,以免乱发消息
113 if (userMapper 114 if (userMapper
114 .selectList(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber)) 115 .selectList(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber))
@@ -117,7 +118,7 @@ public class YtSmsServiceImpl implements YtSmsService { @@ -117,7 +118,7 @@ public class YtSmsServiceImpl implements YtSmsService {
117 } 118 }
118 // 获取是否有验证码存在,防止发送数量过多 119 // 获取是否有验证码存在,防止发送数量过多
119 String key = 120 String key =
120 - MsgTemplatePurposeEnum.FOR_LOGIN.name() 121 + purpose.name()
121 + DEFAULT_DELIMITER 122 + DEFAULT_DELIMITER
122 + MessageTypeEnum.PHONE_MESSAGE.name() 123 + MessageTypeEnum.PHONE_MESSAGE.name()
123 + DEFAULT_DELIMITER 124 + DEFAULT_DELIMITER
@@ -139,7 +140,7 @@ public class YtSmsServiceImpl implements YtSmsService { @@ -139,7 +140,7 @@ public class YtSmsServiceImpl implements YtSmsService {
139 messageTemplateMapper.selectList( 140 messageTemplateMapper.selectList(
140 new QueryWrapper<MessageTemplate>() 141 new QueryWrapper<MessageTemplate>()
141 .lambda() 142 .lambda()
142 - .eq(MessageTemplate::getTemplatePurpose, MsgTemplatePurposeEnum.FOR_LOGIN.name()) 143 + .eq(MessageTemplate::getTemplatePurpose, purpose.name())
143 .eq(MessageTemplate::getMessageType, MessageTypeEnum.PHONE_MESSAGE.name())); 144 .eq(MessageTemplate::getMessageType, MessageTypeEnum.PHONE_MESSAGE.name()));
144 if (messageTemplates.isEmpty()) { 145 if (messageTemplates.isEmpty()) {
145 throw new YtDataValidationException("no sms provider config"); 146 throw new YtDataValidationException("no sms provider config");
@@ -152,7 +153,7 @@ public class YtSmsServiceImpl implements YtSmsService { @@ -152,7 +153,7 @@ public class YtSmsServiceImpl implements YtSmsService {
152 smsReqDTO.setParams(params); 153 smsReqDTO.setParams(params);
153 smsReqDTO.setPhoneNumbers(phoneNumber); 154 smsReqDTO.setPhoneNumbers(phoneNumber);
154 smsReqDTO.setId(messageTemplate.getId()); 155 smsReqDTO.setId(messageTemplate.getId());
155 - smsReqDTO.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_LOGIN.name()); 156 + smsReqDTO.setTemplatePurpose(purpose.name());
156 if (this.sendSms(smsReqDTO)) { 157 if (this.sendSms(smsReqDTO)) {
157 cacheUtils.put(MOBILE_LOGIN_SMS_CODE, key, new CodeTTL(code, System.currentTimeMillis())); 158 cacheUtils.put(MOBILE_LOGIN_SMS_CODE, key, new CodeTTL(code, System.currentTimeMillis()));
158 return true; 159 return true;
@@ -11,28 +11,34 @@ import lombok.RequiredArgsConstructor; @@ -11,28 +11,34 @@ import lombok.RequiredArgsConstructor;
11 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
12 import org.apache.commons.lang3.RandomStringUtils; 12 import org.apache.commons.lang3.RandomStringUtils;
13 import org.apache.commons.lang3.StringUtils; 13 import org.apache.commons.lang3.StringUtils;
  14 +import org.springframework.context.ApplicationEventPublisher;
14 import org.springframework.scheduling.annotation.Async; 15 import org.springframework.scheduling.annotation.Async;
15 import org.springframework.security.access.AccessDeniedException; 16 import org.springframework.security.access.AccessDeniedException;
  17 +import org.springframework.security.authentication.BadCredentialsException;
16 import org.springframework.security.crypto.password.PasswordEncoder; 18 import org.springframework.security.crypto.password.PasswordEncoder;
17 import org.springframework.stereotype.Service; 19 import org.springframework.stereotype.Service;
18 import org.springframework.transaction.annotation.Transactional; 20 import org.springframework.transaction.annotation.Transactional;
  21 +import org.thingsboard.server.common.data.edge.EdgeEventActionType;
19 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
  23 +import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.data.id.UserId;
20 import org.thingsboard.server.common.data.query.TsValue; 25 import org.thingsboard.server.common.data.query.TsValue;
  26 +import org.thingsboard.server.common.data.security.UserCredentials;
  27 +import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent;
21 import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; 28 import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants;
22 import org.thingsboard.server.common.data.yunteng.constant.ModelConstants; 29 import org.thingsboard.server.common.data.yunteng.constant.ModelConstants;
  30 +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils;
23 import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException; 31 import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException;
24 import org.thingsboard.server.common.data.yunteng.core.exception.NoneTenantAssetException; 32 import org.thingsboard.server.common.data.yunteng.core.exception.NoneTenantAssetException;
25 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; 33 import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage;
26 import org.thingsboard.server.common.data.yunteng.dto.*; 34 import org.thingsboard.server.common.data.yunteng.dto.*;
27 -import org.thingsboard.server.common.data.yunteng.dto.request.AccountReqDTO;  
28 -import org.thingsboard.server.common.data.yunteng.dto.request.RoleOrOrganizationReqDTO;  
29 -import org.thingsboard.server.common.data.yunteng.dto.request.SendResetPasswordEmailMsg;  
30 -import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO; 35 +import org.thingsboard.server.common.data.yunteng.dto.request.*;
31 import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum; 36 import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum;
32 import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum; 37 import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
33 import org.thingsboard.server.common.data.yunteng.enums.UserStatusEnum; 38 import org.thingsboard.server.common.data.yunteng.enums.UserStatusEnum;
34 import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils; 39 import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils;
35 import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; 40 import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData;
  41 +import org.thingsboard.server.dao.user.UserService;
36 import org.thingsboard.server.dao.yunteng.entities.*; 42 import org.thingsboard.server.dao.yunteng.entities.*;
37 import org.thingsboard.server.dao.yunteng.mapper.*; 43 import org.thingsboard.server.dao.yunteng.mapper.*;
38 import org.thingsboard.server.dao.yunteng.service.*; 44 import org.thingsboard.server.dao.yunteng.service.*;
@@ -43,8 +49,9 @@ import java.util.*; @@ -43,8 +49,9 @@ import java.util.*;
43 import java.util.concurrent.CompletableFuture; 49 import java.util.concurrent.CompletableFuture;
44 import java.util.stream.Collectors; 50 import java.util.stream.Collectors;
45 51
46 -import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CHINA_MOBILE_PATTERN;  
47 -import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.EMAIL_PATTERN; 52 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.*;
  53 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.CacheConfigKey.MOBILE_LOGIN_SMS_CODE;
  54 +import static org.thingsboard.server.common.data.yunteng.constant.FastIotConstants.DEFAULT_DELIMITER;
48 import static org.thingsboard.server.common.data.yunteng.constant.ModelConstants.TablePropertyMapping.*; 55 import static org.thingsboard.server.common.data.yunteng.constant.ModelConstants.TablePropertyMapping.*;
49 56
50 @Service 57 @Service
@@ -68,6 +75,10 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> @@ -68,6 +75,10 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
68 public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s"; 75 public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s";
69 private final PasswordEncoder passwordEncoder; 76 private final PasswordEncoder passwordEncoder;
70 77
  78 + private CacheUtils cacheUtils;
  79 + private final UserService tbUserService;
  80 + private final ApplicationEventPublisher eventPublisher;
  81 +
71 @Override 82 @Override
72 public List<UserDetailsDTO> findUserDetailsByUsername(String username) { 83 public List<UserDetailsDTO> findUserDetailsByUsername(String username) {
73 // 多个租户可能存在多个username相同的情况 84 // 多个租户可能存在多个username相同的情况
@@ -427,6 +438,52 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> @@ -427,6 +438,52 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
427 } 438 }
428 439
429 @Override 440 @Override
  441 + public void forgetPassword(String phoneNumber,AccountReqDTO forget) {
  442 + String key =
  443 + MsgTemplatePurposeEnum.FOR_FORGET_PASSWORD.name()
  444 + + DEFAULT_DELIMITER
  445 + + MessageTypeEnum.PHONE_MESSAGE.name()
  446 + + DEFAULT_DELIMITER
  447 + + phoneNumber;
  448 + boolean correct =
  449 + cacheUtils
  450 + .get(MOBILE_LOGIN_SMS_CODE, key)
  451 + .map(
  452 + o -> {
  453 + CodeTTL codeTTL = (CodeTTL) o;
  454 + if (System.currentTimeMillis() - codeTTL.getSendTs() < 5 * 60 * 1000) {
  455 + return Objects.equals(codeTTL.getCode(), forget.getUserId());
  456 + } else {
  457 + return false;
  458 + }
  459 + })
  460 + .orElse(false);
  461 + if (!correct) {
  462 + throw new BadCredentialsException("验证码不正确");
  463 + }
  464 + String pwd = forget.getPassword();
  465 + if (StringUtils.isEmpty(pwd)
  466 + || StringUtils.isEmpty(forget.getResetPassword())
  467 + || !pwd.equals(forget.getResetPassword())) {
  468 + throw new YtDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage());
  469 + }
  470 +
  471 + User user = baseMapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber));
  472 +
  473 + UserId userId = new UserId(UUID.fromString(user.getTbUser()));
  474 + UserCredentials userCredentials =
  475 + tbUserService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, userId);
  476 +
  477 + String encodePwd = passwordEncoder.encode(pwd);
  478 + userCredentials.setPassword(encodePwd);
  479 + user.setPassword(encodePwd);
  480 + tbUserService.replaceUserCredentials(new TenantId(UUID.fromString(user.getTenantId())), userCredentials);
  481 + eventPublisher.publishEvent(new UserAuthDataChangedEvent(userId));
  482 +
  483 + changePassword(user);
  484 + }
  485 +
  486 + @Override
430 public List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber) { 487 public List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber) {
431 return baseMapper.findUserDetailsByPhoneNumber(phoneNumber); 488 return baseMapper.findUserDetailsByPhoneNumber(phoneNumber);
432 } 489 }
@@ -586,6 +643,11 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> @@ -586,6 +643,11 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
586 @Override 643 @Override
587 public User validateChangePasswordAccount(AccountReqDTO accountReqDTO) { 644 public User validateChangePasswordAccount(AccountReqDTO accountReqDTO) {
588 User user = baseMapper.selectById(accountReqDTO.getUserId()); 645 User user = baseMapper.selectById(accountReqDTO.getUserId());
  646 + checkPassword(accountReqDTO, user);
  647 + return user;
  648 + }
  649 +
  650 + private void checkPassword(AccountReqDTO accountReqDTO, User user) {
589 if (null == user 651 if (null == user
590 || StringUtils.isEmpty(accountReqDTO.getPassword()) 652 || StringUtils.isEmpty(accountReqDTO.getPassword())
591 || StringUtils.isEmpty(accountReqDTO.getResetPassword())) { 653 || StringUtils.isEmpty(accountReqDTO.getResetPassword())) {
@@ -597,7 +659,6 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> @@ -597,7 +659,6 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User>
597 throw new YtDataValidationException(ErrorMessage.USERNAME_PASSWORD_INCORRECT.getMessage()); 659 throw new YtDataValidationException(ErrorMessage.USERNAME_PASSWORD_INCORRECT.getMessage());
598 } 660 }
599 user.setPassword(accountReqDTO.getResetPassword()); 661 user.setPassword(accountReqDTO.getResetPassword());
600 - return user;  
601 } 662 }
602 663
603 /** 664 /**
@@ -30,7 +30,7 @@ import java.util.UUID; @@ -30,7 +30,7 @@ import java.util.UUID;
30 public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEntity, UUID> { 30 public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEntity, UUID> {
31 31
32 32
33 - @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId) " + 33 + @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId,d.isDefault,d.image,d.type,d.profileData) " +
34 "FROM DeviceProfileEntity d WHERE " + 34 "FROM DeviceProfileEntity d WHERE " +
35 "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") 35 "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))")
36 Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId, 36 Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId,
@@ -38,7 +38,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn @@ -38,7 +38,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn
38 @Param("transportType") DeviceTransportType transportType, 38 @Param("transportType") DeviceTransportType transportType,
39 Pageable pageable); 39 Pageable pageable);
40 40
41 - @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId) " + 41 + @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId,d.isDefault,d.image,d.type,d.profileData) " +
42 "FROM DeviceProfileEntity d WHERE " + 42 "FROM DeviceProfileEntity d WHERE " +
43 "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") 43 "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))")
44 Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId, 44 Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId,
@@ -46,7 +46,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn @@ -46,7 +46,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn
46 Pageable pageable); 46 Pageable pageable);
47 47
48 48
49 - @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId) " + 49 + @Query("SELECT new org.thingsboard.server.common.data.yunteng.dto.DeviceProfileDTO(d.id, d.name, d.createdTime,d.description, d.transportType, d.defaultRuleChainId,d.isDefault,d.image,d.type,d.profileData) " +
50 "FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId ") 50 "FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId ")
51 List<DeviceProfileDTO> findDeviceProfileByTenantId(@Param("tenantId") UUID tenantId); 51 List<DeviceProfileDTO> findDeviceProfileByTenantId(@Param("tenantId") UUID tenantId);
52 52
@@ -2,9 +2,16 @@ package org.thingsboard.server.dao.yunteng.service; @@ -2,9 +2,16 @@ package org.thingsboard.server.dao.yunteng.service;
2 2
3 3
4 import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO; 4 import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO;
  5 +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum;
5 6
6 public interface YtSmsService { 7 public interface YtSmsService {
7 boolean sendSms(SmsReqDTO smsReqDTO); 8 boolean sendSms(SmsReqDTO smsReqDTO);
8 9
9 - boolean sendLoginSmsCode(String phoneNumber); 10 + /**
  11 + * 推送短信验证码
  12 + * @param phoneNumber 手机号
  13 + * @param purpose 模板用途
  14 + * @return
  15 + */
  16 + boolean sendSmsCode(String phoneNumber, MsgTemplatePurposeEnum purpose);
10 } 17 }
@@ -42,6 +42,8 @@ public interface YtUserService { @@ -42,6 +42,8 @@ public interface YtUserService {
42 42
43 void resetPassword(String userId, boolean isPtSysadmin, String tenantId); 43 void resetPassword(String userId, boolean isPtSysadmin, String tenantId);
44 44
  45 + void forgetPassword(String phoneNumber,AccountReqDTO forget);
  46 +
45 List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber); 47 List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber);
46 48
47 void validateUserNameAndPhoneNumberAndEmail(UserDTO userDTO); 49 void validateUserNameAndPhoneNumberAndEmail(UserDTO userDTO);
@@ -3,10 +3,8 @@ @@ -3,10 +3,8 @@
3 */ 3 */
4 package org.thingsboard.rule.engine.yunteng.scene; 4 package org.thingsboard.rule.engine.yunteng.scene;
5 5
6 -import com.fasterxml.jackson.databind.JsonNode;  
7 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
8 -import org.thingsboard.common.util.JacksonUtil;  
9 -import org.thingsboard.rule.engine.action.TbAlarmResult; 7 +import org.jetbrains.annotations.NotNull;
10 import org.thingsboard.rule.engine.api.TbContext; 8 import org.thingsboard.rule.engine.api.TbContext;
11 import org.thingsboard.server.common.data.DataConstants; 9 import org.thingsboard.server.common.data.DataConstants;
12 import org.thingsboard.server.common.data.device.profile.AlarmCondition; 10 import org.thingsboard.server.common.data.device.profile.AlarmCondition;
@@ -14,7 +12,6 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; @@ -14,7 +12,6 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter;
14 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; 12 import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey;
15 import org.thingsboard.server.common.data.rule.RuleNodeState; 13 import org.thingsboard.server.common.data.rule.RuleNodeState;
16 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO; 14 import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO;
17 -import org.thingsboard.server.common.data.yunteng.enums.ActionTypeEnum;  
18 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils; 15 import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils;
19 import org.thingsboard.server.common.msg.TbMsg; 16 import org.thingsboard.server.common.msg.TbMsg;
20 import org.thingsboard.server.common.msg.TbMsgMetaData; 17 import org.thingsboard.server.common.msg.TbMsgMetaData;
@@ -41,6 +38,12 @@ class ReactState { @@ -41,6 +38,12 @@ class ReactState {
41 */ 38 */
42 private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>(); 39 private ConcurrentHashMap<String, TriggerState> triggerState = new ConcurrentHashMap<>();
43 40
  41 + /**场景联动的执行条件状态
  42 + * 键:设备主键
  43 + * 值:设备指标参与的触发器
  44 + */
  45 + private ConcurrentHashMap<String, TriggerState> conditionState = new ConcurrentHashMap<>();
  46 +
44 47
45 48
46 49
@@ -71,18 +74,36 @@ class ReactState { @@ -71,18 +74,36 @@ class ReactState {
71 public void process(TbContext ctx, TbMsg msg,String deviceId) throws ExecutionException, InterruptedException { 74 public void process(TbContext ctx, TbMsg msg,String deviceId) throws ExecutionException, InterruptedException {
72 TriggerState triggerState = getOrCreateTriggerState(deviceId); 75 TriggerState triggerState = getOrCreateTriggerState(deviceId);
73 boolean matched = false; 76 boolean matched = false;
74 - if(triggerState != null && actions != null){ 77 + if( actions != null){
  78 + ctx.tellSuccess(msg);
  79 + }
  80 +
  81 + if(triggerState != null){
75 matched = triggerState.process(ctx,msg); 82 matched = triggerState.process(ctx,msg);
76 } 83 }
77 84
78 - if(matched){  
79 - // TODO 执行条件 85 +
  86 + if(matched && conditions != null ){
  87 + matched = false;
  88 + for(DoCondition item:conditions){
  89 + TriggerState conditionState = getOrCreateConditionState(item.getEntityId(),item.getTriggerCondition());
  90 + boolean result = false;
  91 + if( conditionState != null){
  92 + result =conditionState.process(ctx,msg);
  93 + }
  94 + if( result){
  95 + matched = true;
  96 + break;
  97 + }
  98 + }
80 } 99 }
81 100
82 if(matched){ 101 if(matched){
83 for(DoAction item: actions){ 102 for(DoAction item: actions){
84 pushMsg(ctx, msg, item); 103 pushMsg(ctx, msg, item);
85 } 104 }
  105 + }else{
  106 + ctx.tellSuccess(msg);
86 } 107 }
87 108
88 } 109 }
@@ -99,18 +120,35 @@ class ReactState { @@ -99,18 +120,35 @@ class ReactState {
99 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class); 120 TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class);
100 TriggerDTO trigger =triggerService.getTrigger(reactId,deviceId); 121 TriggerDTO trigger =triggerService.getTrigger(reactId,deviceId);
101 if(trigger != null){ 122 if(trigger != null){
102 - AlarmCondition condition = trigger.getTriggerCondition();  
103 - Set<AlarmConditionFilterKey> filterKeys = new HashSet<>();  
104 - for(AlarmConditionFilter filter :condition.getCondition()){  
105 - filterKeys.add(filter.getKey());  
106 - }  
107 - TriggerState state = new TriggerState(deviceId,condition, filterKeys,null); 123 + TriggerState state = createTriggerState(deviceId, trigger.getTriggerCondition());
108 triggerState.put(deviceId, state); 124 triggerState.put(deviceId, state);
109 - return state; 125 + return state;
110 } 126 }
111 return null; 127 return null;
112 } 128 }
113 129
  130 + protected TriggerState getOrCreateConditionState(String deviceId,AlarmCondition condition) {
  131 + if(conditionState.containsKey(deviceId)){
  132 + return conditionState.get(deviceId);
  133 + }else{
  134 + TriggerState state = createTriggerState(deviceId, condition);
  135 + conditionState.put(deviceId, state);
  136 + return state;
  137 + }
  138 +
  139 + }
  140 +
  141 + @NotNull
  142 + private TriggerState createTriggerState(String deviceId, AlarmCondition condition) {
  143 + Set<AlarmConditionFilterKey> filterKeys = new HashSet<>();
  144 + for(AlarmConditionFilter filter :condition.getCondition()){
  145 + filterKeys.add(filter.getKey());
  146 + }
  147 + TriggerState state = new TriggerState(deviceId,condition, filterKeys,null);
  148 +
  149 + return state;
  150 + }
  151 +
114 private void pushMsg(TbContext ctx, TbMsg msg, DoAction action) { 152 private void pushMsg(TbContext ctx, TbMsg msg, DoAction action) {
115 TbMsgMetaData metaData = //lastMsgMetaData != null ? lastMsgMetaData.copy() : 153 TbMsgMetaData metaData = //lastMsgMetaData != null ? lastMsgMetaData.copy() :
116 new TbMsgMetaData(); 154 new TbMsgMetaData();
@@ -110,6 +110,7 @@ public class TbSceneReactNode implements TbNode { @@ -110,6 +110,7 @@ public class TbSceneReactNode implements TbNode {
110 @Override 110 @Override
111 public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) { 111 public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) {
112 // Cleanup the cache for all entities that are no longer assigned to current server partitions 112 // Cleanup the cache for all entities that are no longer assigned to current server partitions
  113 + reactStates.clear();
113 } 114 }
114 115
115 protected ReactState getOrCreateReactState(TbContext ctx, TbSceneReactNodeConfig config, String sceneId) { 116 protected ReactState getOrCreateReactState(TbContext ctx, TbSceneReactNodeConfig config, String sceneId) {