Commit d1cb0d70d272c7ccba37eefdb8d6f8b7582915b2
Merge branch '20220304' into 'master'
feat: 密码找回 See merge request huang/thingsboard3.3.2!55
Showing
10 changed files
with
180 additions
and
37 deletions
1 | 1 | package org.thingsboard.server.controller.yunteng; |
2 | 2 | |
3 | +import io.swagger.annotations.ApiOperation; | |
3 | 4 | import lombok.RequiredArgsConstructor; |
4 | 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 | 11 | import org.thingsboard.server.dao.yunteng.service.YtSmsService; |
12 | +import org.thingsboard.server.dao.yunteng.service.YtUserService; | |
10 | 13 | |
11 | 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 | 19 | public class YtNoAuthController { |
17 | 20 | |
18 | 21 | private final YtSmsService smsService; |
22 | + private final YtUserService userService; | |
19 | 23 | |
20 | 24 | @PostMapping("/sendLoginSmsCode/{phoneNumber}") |
21 | 25 | public boolean sendVerificationCode(@PathVariable("phoneNumber") String phoneNumber) { |
22 | 26 | Assert.isTrue( |
23 | 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 | 10 | @RestController |
11 | 11 | @RequestMapping("/api/yt/tenant") |
12 | 12 | @RequiredArgsConstructor |
13 | +@Deprecated | |
13 | 14 | public class YtTenantController extends BaseController { |
14 | 15 | |
15 | 16 | private final YtUserService userService; | ... | ... |
1 | 1 | package org.thingsboard.server.common.data.yunteng.dto; |
2 | 2 | |
3 | +import com.fasterxml.jackson.databind.JsonNode; | |
3 | 4 | import io.swagger.annotations.ApiModelProperty; |
4 | 5 | import lombok.Data; |
5 | 6 | import lombok.EqualsAndHashCode; |
7 | +import org.thingsboard.common.util.JacksonUtil; | |
8 | +import org.thingsboard.server.common.data.DeviceProfileType; | |
6 | 9 | import org.thingsboard.server.common.data.DeviceTransportType; |
7 | 10 | import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
8 | 11 | import org.thingsboard.server.common.data.yunteng.common.AddGroup; |
... | ... | @@ -50,26 +53,39 @@ public class DeviceProfileDTO extends TenantDTO { |
50 | 53 | /**默认消息队列*/ |
51 | 54 | private String defaultQueueName; |
52 | 55 | |
56 | + /**设备配置图片*/ | |
57 | + private String image; | |
58 | + /**是否默认设备配置*/ | |
59 | + private boolean isDefault; | |
60 | + private String type; | |
61 | + | |
53 | 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 | 66 | setId(id.toString()); |
58 | 67 | setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC)); |
59 | 68 | this.name = name; |
69 | + this.isDefault = isDefault; | |
70 | + this.image = image; | |
60 | 71 | this.description = description; |
72 | + this.type = type.name(); | |
61 | 73 | this.transportType = transportType.name(); |
62 | 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 | 80 | setId(id.toString()); |
67 | 81 | setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneOffset.UTC)); |
68 | 82 | this.name = name; |
83 | + this.isDefault = isDefault; | |
84 | + this.image = image; | |
69 | 85 | this.description = description; |
86 | + this.type = type.name(); | |
70 | 87 | this.convertJs = convertJs; |
71 | 88 | this.transportType = transportType.name(); |
72 | 89 | this.defaultRuleChainId = defaultRuleChainId.toString(); |
73 | - this.profileData = profileData; | |
74 | 90 | } |
75 | 91 | } | ... | ... |
... | ... | @@ -106,9 +106,10 @@ public class YtSmsServiceImpl implements YtSmsService { |
106 | 106 | return false; |
107 | 107 | } |
108 | 108 | |
109 | + | |
109 | 110 | @Override |
110 | 111 | @Transactional |
111 | - public boolean sendLoginSmsCode(String phoneNumber) { | |
112 | + public boolean sendSmsCode(String phoneNumber,MsgTemplatePurposeEnum purpose) { | |
112 | 113 | // 检查手机号码是否存在系统,以免乱发消息 |
113 | 114 | if (userMapper |
114 | 115 | .selectList(new QueryWrapper<User>().lambda().eq(User::getPhoneNumber, phoneNumber)) |
... | ... | @@ -117,7 +118,7 @@ public class YtSmsServiceImpl implements YtSmsService { |
117 | 118 | } |
118 | 119 | // 获取是否有验证码存在,防止发送数量过多 |
119 | 120 | String key = |
120 | - MsgTemplatePurposeEnum.FOR_LOGIN.name() | |
121 | + purpose.name() | |
121 | 122 | + DEFAULT_DELIMITER |
122 | 123 | + MessageTypeEnum.PHONE_MESSAGE.name() |
123 | 124 | + DEFAULT_DELIMITER |
... | ... | @@ -139,7 +140,7 @@ public class YtSmsServiceImpl implements YtSmsService { |
139 | 140 | messageTemplateMapper.selectList( |
140 | 141 | new QueryWrapper<MessageTemplate>() |
141 | 142 | .lambda() |
142 | - .eq(MessageTemplate::getTemplatePurpose, MsgTemplatePurposeEnum.FOR_LOGIN.name()) | |
143 | + .eq(MessageTemplate::getTemplatePurpose, purpose.name()) | |
143 | 144 | .eq(MessageTemplate::getMessageType, MessageTypeEnum.PHONE_MESSAGE.name())); |
144 | 145 | if (messageTemplates.isEmpty()) { |
145 | 146 | throw new YtDataValidationException("no sms provider config"); |
... | ... | @@ -152,7 +153,7 @@ public class YtSmsServiceImpl implements YtSmsService { |
152 | 153 | smsReqDTO.setParams(params); |
153 | 154 | smsReqDTO.setPhoneNumbers(phoneNumber); |
154 | 155 | smsReqDTO.setId(messageTemplate.getId()); |
155 | - smsReqDTO.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_LOGIN.name()); | |
156 | + smsReqDTO.setTemplatePurpose(purpose.name()); | |
156 | 157 | if (this.sendSms(smsReqDTO)) { |
157 | 158 | cacheUtils.put(MOBILE_LOGIN_SMS_CODE, key, new CodeTTL(code, System.currentTimeMillis())); |
158 | 159 | return true; | ... | ... |
... | ... | @@ -11,28 +11,34 @@ import lombok.RequiredArgsConstructor; |
11 | 11 | import lombok.extern.slf4j.Slf4j; |
12 | 12 | import org.apache.commons.lang3.RandomStringUtils; |
13 | 13 | import org.apache.commons.lang3.StringUtils; |
14 | +import org.springframework.context.ApplicationEventPublisher; | |
14 | 15 | import org.springframework.scheduling.annotation.Async; |
15 | 16 | import org.springframework.security.access.AccessDeniedException; |
17 | +import org.springframework.security.authentication.BadCredentialsException; | |
16 | 18 | import org.springframework.security.crypto.password.PasswordEncoder; |
17 | 19 | import org.springframework.stereotype.Service; |
18 | 20 | import org.springframework.transaction.annotation.Transactional; |
21 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | |
19 | 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 | 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 | 28 | import org.thingsboard.server.common.data.yunteng.constant.FastIotConstants; |
22 | 29 | import org.thingsboard.server.common.data.yunteng.constant.ModelConstants; |
30 | +import org.thingsboard.server.common.data.yunteng.core.cache.CacheUtils; | |
23 | 31 | import org.thingsboard.server.common.data.yunteng.core.exception.YtDataValidationException; |
24 | 32 | import org.thingsboard.server.common.data.yunteng.core.exception.NoneTenantAssetException; |
25 | 33 | import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; |
26 | 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 | 36 | import org.thingsboard.server.common.data.yunteng.enums.MessageTypeEnum; |
32 | 37 | import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum; |
33 | 38 | import org.thingsboard.server.common.data.yunteng.enums.UserStatusEnum; |
34 | 39 | import org.thingsboard.server.common.data.yunteng.utils.ReflectUtils; |
35 | 40 | import org.thingsboard.server.common.data.yunteng.utils.tools.YtPageData; |
41 | +import org.thingsboard.server.dao.user.UserService; | |
36 | 42 | import org.thingsboard.server.dao.yunteng.entities.*; |
37 | 43 | import org.thingsboard.server.dao.yunteng.mapper.*; |
38 | 44 | import org.thingsboard.server.dao.yunteng.service.*; |
... | ... | @@ -43,8 +49,9 @@ import java.util.*; |
43 | 49 | import java.util.concurrent.CompletableFuture; |
44 | 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 | 55 | import static org.thingsboard.server.common.data.yunteng.constant.ModelConstants.TablePropertyMapping.*; |
49 | 56 | |
50 | 57 | @Service |
... | ... | @@ -68,6 +75,10 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> |
68 | 75 | public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s"; |
69 | 76 | private final PasswordEncoder passwordEncoder; |
70 | 77 | |
78 | + private CacheUtils cacheUtils; | |
79 | + private final UserService tbUserService; | |
80 | + private final ApplicationEventPublisher eventPublisher; | |
81 | + | |
71 | 82 | @Override |
72 | 83 | public List<UserDetailsDTO> findUserDetailsByUsername(String username) { |
73 | 84 | // 多个租户可能存在多个username相同的情况 |
... | ... | @@ -427,6 +438,52 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> |
427 | 438 | } |
428 | 439 | |
429 | 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 | 487 | public List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber) { |
431 | 488 | return baseMapper.findUserDetailsByPhoneNumber(phoneNumber); |
432 | 489 | } |
... | ... | @@ -586,6 +643,11 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> |
586 | 643 | @Override |
587 | 644 | public User validateChangePasswordAccount(AccountReqDTO accountReqDTO) { |
588 | 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 | 651 | if (null == user |
590 | 652 | || StringUtils.isEmpty(accountReqDTO.getPassword()) |
591 | 653 | || StringUtils.isEmpty(accountReqDTO.getResetPassword())) { |
... | ... | @@ -597,7 +659,6 @@ public class YtUserServiceImpl extends AbstractBaseService<UserMapper, User> |
597 | 659 | throw new YtDataValidationException(ErrorMessage.USERNAME_PASSWORD_INCORRECT.getMessage()); |
598 | 660 | } |
599 | 661 | user.setPassword(accountReqDTO.getResetPassword()); |
600 | - return user; | |
601 | 662 | } |
602 | 663 | |
603 | 664 | /** | ... | ... |
... | ... | @@ -30,7 +30,7 @@ import java.util.UUID; |
30 | 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 | 34 | "FROM DeviceProfileEntity d WHERE " + |
35 | 35 | "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") |
36 | 36 | Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId, |
... | ... | @@ -38,7 +38,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn |
38 | 38 | @Param("transportType") DeviceTransportType transportType, |
39 | 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 | 42 | "FROM DeviceProfileEntity d WHERE " + |
43 | 43 | "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%'))") |
44 | 44 | Page<DeviceProfileDTO> findDeviceProfileInfos(@Param("tenantId") UUID tenantId, |
... | ... | @@ -46,7 +46,7 @@ public interface YtDeviceProfileRepository extends JpaRepository<DeviceProfileEn |
46 | 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 | 50 | "FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId ") |
51 | 51 | List<DeviceProfileDTO> findDeviceProfileByTenantId(@Param("tenantId") UUID tenantId); |
52 | 52 | ... | ... |
... | ... | @@ -2,9 +2,16 @@ package org.thingsboard.server.dao.yunteng.service; |
2 | 2 | |
3 | 3 | |
4 | 4 | import org.thingsboard.server.common.data.yunteng.dto.request.SmsReqDTO; |
5 | +import org.thingsboard.server.common.data.yunteng.enums.MsgTemplatePurposeEnum; | |
5 | 6 | |
6 | 7 | public interface YtSmsService { |
7 | 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 | 42 | |
43 | 43 | void resetPassword(String userId, boolean isPtSysadmin, String tenantId); |
44 | 44 | |
45 | + void forgetPassword(String phoneNumber,AccountReqDTO forget); | |
46 | + | |
45 | 47 | List<UserDetailsDTO> getUserByPhoneNumber(String phoneNumber); |
46 | 48 | |
47 | 49 | void validateUserNameAndPhoneNumberAndEmail(UserDTO userDTO); | ... | ... |
... | ... | @@ -3,10 +3,8 @@ |
3 | 3 | */ |
4 | 4 | package org.thingsboard.rule.engine.yunteng.scene; |
5 | 5 | |
6 | -import com.fasterxml.jackson.databind.JsonNode; | |
7 | 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 | 8 | import org.thingsboard.rule.engine.api.TbContext; |
11 | 9 | import org.thingsboard.server.common.data.DataConstants; |
12 | 10 | import org.thingsboard.server.common.data.device.profile.AlarmCondition; |
... | ... | @@ -14,7 +12,6 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; |
14 | 12 | import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; |
15 | 13 | import org.thingsboard.server.common.data.rule.RuleNodeState; |
16 | 14 | import org.thingsboard.server.common.data.yunteng.dto.TriggerDTO; |
17 | -import org.thingsboard.server.common.data.yunteng.enums.ActionTypeEnum; | |
18 | 15 | import org.thingsboard.server.common.data.yunteng.utils.SpringBeanUtils; |
19 | 16 | import org.thingsboard.server.common.msg.TbMsg; |
20 | 17 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
... | ... | @@ -41,6 +38,12 @@ class ReactState { |
41 | 38 | */ |
42 | 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 | 74 | public void process(TbContext ctx, TbMsg msg,String deviceId) throws ExecutionException, InterruptedException { |
72 | 75 | TriggerState triggerState = getOrCreateTriggerState(deviceId); |
73 | 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 | 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 | 101 | if(matched){ |
83 | 102 | for(DoAction item: actions){ |
84 | 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 | 120 | TriggerService triggerService = SpringBeanUtils.getBean(TriggerService.class); |
100 | 121 | TriggerDTO trigger =triggerService.getTrigger(reactId,deviceId); |
101 | 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 | 124 | triggerState.put(deviceId, state); |
109 | - return state; | |
125 | + return state; | |
110 | 126 | } |
111 | 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 | 152 | private void pushMsg(TbContext ctx, TbMsg msg, DoAction action) { |
115 | 153 | TbMsgMetaData metaData = //lastMsgMetaData != null ? lastMsgMetaData.copy() : |
116 | 154 | new TbMsgMetaData(); | ... | ... |
... | ... | @@ -110,6 +110,7 @@ public class TbSceneReactNode implements TbNode { |
110 | 110 | @Override |
111 | 111 | public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) { |
112 | 112 | // Cleanup the cache for all entities that are no longer assigned to current server partitions |
113 | + reactStates.clear(); | |
113 | 114 | } |
114 | 115 | |
115 | 116 | protected ReactState getOrCreateReactState(TbContext ctx, TbSceneReactNodeConfig config, String sceneId) { | ... | ... |