Browse Source

Merge pull request #14249 from thingsboard/lts-4.2

LTS to rc
pull/14266/head
Viacheslav Klimov 10 months ago
committed by GitHub
parent
commit
8b94bf38f4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      application/src/main/java/org/thingsboard/server/controller/UserController.java
  2. 20
      application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
  3. 1
      common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java
  4. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java
  5. 36
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java
  6. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java
  7. 5
      dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java
  8. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java
  9. 1
      dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java
  10. 5
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

3
application/src/main/java/org/thingsboard/server/controller/UserController.java

@ -266,6 +266,9 @@ public class UserController extends BaseController {
if (user.getAuthority() == Authority.SYS_ADMIN && getCurrentUser().getId().equals(userId)) {
throw new ThingsboardException("Sysadmin is not allowed to delete himself", ThingsboardErrorCode.PERMISSION_DENIED);
}
if (user.getAuthority() == Authority.TENANT_ADMIN && userService.countTenantAdmins(user.getTenantId()) == 1) {
throw new ThingsboardException("At least one tenant administrator must remain!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
tbUserService.delete(getTenantId(), getCurrentUser().getCustomerId(), user, getCurrentUser());
}

20
application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java

@ -284,6 +284,26 @@ public class UserControllerTest extends AbstractControllerTest {
ActionType.ADDED, new DataValidationException(msgError));
}
@Test
public void testShouldNotDeleteLastTenantAdmin() throws Exception {
loginSysAdmin();
User tenantAdmin2 = new User();
tenantAdmin2.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin2.setTenantId(tenantId);
tenantAdmin2.setEmail("tenant2@thingsboard.io");
tenantAdmin2 = doPost("/api/user", tenantAdmin2, User.class);
// delete second tenant admin - ok
doDelete("/api/user/" + tenantAdmin2.getId().getId().toString())
.andExpect(status().isOk());
// delete last tenant admin - forbidden
doDelete("/api/user/" + tenantAdminUser.getId().getId().toString())
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("At least one tenant administrator must remain!")));
}
@Test
public void testSaveUserWithInvalidEmail() throws Exception {
loginSysAdmin();

1
common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java

@ -109,4 +109,5 @@ public interface UserService extends EntityDaoService {
void removeMobileSession(TenantId tenantId, String mobileToken);
int countTenantAdmins(TenantId tenantId);
}

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java

@ -20,7 +20,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
@ -196,14 +195,13 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
root = new CoapResource("");
coapServer.add(root);
}
root.add(new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE, serverCoapConfig.get(CoapConfig.PREFERRED_BLOCK_SIZE), serverCoapConfig.get(CoapConfig.MAX_RESOURCE_BODY_SIZE)));
root.add(new LwM2mTransportCoapResource(otaPackageDataCache, SOFTWARE_UPDATE_COAP_RESOURCE,serverCoapConfig.get(CoapConfig.PREFERRED_BLOCK_SIZE), serverCoapConfig.get(CoapConfig.MAX_RESOURCE_BODY_SIZE)));
root.add(new LwM2mTransportCoapResource(otaPackageDataCache, FIRMWARE_UPDATE_COAP_RESOURCE));
root.add(new LwM2mTransportCoapResource(otaPackageDataCache, SOFTWARE_UPDATE_COAP_RESOURCE));
}
return leshanServer;
}
private void setServerWithCredentials(LeshanServerBuilder builder) {
// private void setServerWithCredentials(LeshanServerBuilder builder) {
if (this.config.getSslCredentials() != null) {
SslCredentials sslCredentials = this.config.getSslCredentials();
builder.setPublicKey(sslCredentials.getPublicKey());

36
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java

@ -34,21 +34,15 @@ import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.FIRMWARE_UPDATE_COAP_RESOURCE;
import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService.SOFTWARE_UPDATE_COAP_RESOURCE;
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.calculateSzx;
@Slf4j
public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
private final ConcurrentMap<String, ObserveRelation> tokenToObserveRelationMap = new ConcurrentHashMap<>();
private final ConcurrentMap<String, AtomicInteger> tokenToObserveNotificationSeqMap = new ConcurrentHashMap<>();
private final OtaPackageDataCache otaPackageDataCache;
private final int chunkSize;
private final int maxResourceBodySize;
public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name, int chunkSize, int maxResourceBodySize) {
public LwM2mTransportCoapResource(OtaPackageDataCache otaPackageDataCache, String name) {
super(name);
this.otaPackageDataCache = otaPackageDataCache;
this.chunkSize = chunkSize;
this.maxResourceBodySize = maxResourceBodySize;
this.setObservable(true); // enable observing
this.addObserver(new CoapResourceObserver());
}
@ -141,29 +135,23 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
String idStr = exchange.getRequestOptions().getUriPath().get(exchange.getRequestOptions().getUriPath().size() - 1
);
UUID currentId = UUID.fromString(idStr);
log.info("Start Read ota data (path): [{}]", exchange.getRequestOptions().getUriPath().toString());
Response response = new Response(CoAP.ResponseCode.CONTENT);
byte[] otaData = this.getOtaData(currentId);
if (otaData != null && otaData.length > 0) {
if (otaData.length <= this.maxResourceBodySize) {
log.info("Read ota data (length): [{}]", otaData.length);
response.setPayload(otaData);
int chunkSize = calculateSzx(this.chunkSize);
if (exchange.getRequestOptions().hasBlock2()) {
chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
} else if (exchange.getRequestOptions().hasBlock1()) {
chunkSize = exchange.getRequestOptions().getBlock1().getSzx();
}
log.info("With block2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), otaData.length, chunkSize, false);
boolean lastFlag = otaData.length <= this.chunkSize;
response.getOptions().setBlock2(chunkSize, lastFlag, 0);
response.setType(CoAP.Type.CON);
exchange.respond(response);
log.debug("Read ota data (length): [{}]", otaData.length);
response.setPayload(otaData);
if (exchange.getRequestOptions().getBlock2() != null) {
int szx = exchange.getRequestOptions().getBlock2().getSzx();
int chunkSize = exchange.getRequestOptions().getBlock2().getSize();
boolean lastFlag = otaData.length <= chunkSize;
response.getOptions().setBlock2(szx, lastFlag, 0);
log.trace("With block2 Send currentId: [{}], length: [{}], chunkSize [{}], szx [{}], moreFlag [{}]", currentId, otaData.length, chunkSize, szx, lastFlag);
} else {
log.info("Ota package size: [{}] is larger than server's MAX_RESOURCE_BODY_SIZE [{}]", otaData.length, this.maxResourceBodySize);
log.trace("With block1 Send currentId: [{}], length: [{}], ", currentId, otaData.length);
}
exchange.respond(response);
} else {
log.info("Ota packaged currentId: [{}] is not found.", currentId.toString());
log.trace("Ota packaged currentId: [{}] is not found.", currentId);
}
}

11
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java

@ -120,10 +120,6 @@ public class LwM2MTransportUtil {
}
}
public static List<LwM2MBootstrapServerCredential> getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) {
return toLwM2MClientProfile(deviceProfile).getBootstrap();
}
public static String fromVersionedIdToObjectId(String pathIdVer) {
try {
if (pathIdVer == null) {
@ -398,13 +394,6 @@ public class LwM2MTransportUtil {
}
}
public static int calculateSzx(int size) {
if (size < 16 || size > 1024 || (size & (size - 1)) != 0) {
throw new IllegalArgumentException("Size must be a power of 2 between 16 and 1024.");
}
return (int) (Math.log(size / 16) / Math.log(2));
}
public static ConcurrentHashMap<Integer, String[]> groupByObjectIdVersionedIds(Set<String> targetIds) {
return targetIds.stream()
.collect(Collectors.groupingBy(

5
dao/src/main/java/org/thingsboard/server/dao/sql/user/JpaUserDao.java

@ -136,6 +136,11 @@ public class JpaUserDao extends JpaAbstractDao<UserEntity, User> implements User
DaoUtil.toPageable(pageLink)));
}
@Override
public int countTenantAdmins(UUID tenantId) {
return userRepository.countByTenantIdAndAuthority(tenantId, Authority.TENANT_ADMIN);
}
@Override
public Long countByTenantId(TenantId tenantId) {
return userRepository.countByTenantId(tenantId.getId());

2
dao/src/main/java/org/thingsboard/server/dao/sql/user/UserRepository.java

@ -78,4 +78,6 @@ public interface UserRepository extends JpaRepository<UserEntity, UUID> {
"u.customerId, u.version, u.firstName, u.lastName, u.email, u.phone, u.additionalInfo) " +
"FROM UserEntity u WHERE u.id > :id ORDER BY u.id")
List<UserFields> findNextBatch(@Param("id") UUID id, Limit limit);
int countByTenantIdAndAuthority(UUID tenantId, Authority authority);
}

1
dao/src/main/java/org/thingsboard/server/dao/user/UserDao.java

@ -101,4 +101,5 @@ public interface UserDao extends Dao<User>, TenantEntityDao<User> {
PageData<User> findByAuthorityAndTenantProfilesIds(Authority authority, List<TenantProfileId> tenantProfilesIds, PageLink pageLink);
int countTenantAdmins(UUID tenantId);
}

5
dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

@ -485,6 +485,11 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U
}
}
@Override
public int countTenantAdmins(TenantId tenantId) {
return userDao.countTenantAdmins(tenantId.getId());
}
private Optional<UserMobileSessionInfo> findMobileSessionInfo(TenantId tenantId, UserId userId) {
return Optional.ofNullable(userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.MOBILE))
.map(UserSettings::getSettings).map(settings -> JacksonUtil.treeToValue(settings, UserMobileSessionInfo.class));

Loading…
Cancel
Save