diff --git a/application/src/main/data/upgrade/3.8.1/schema_update.sql b/application/src/main/data/upgrade/3.8.1/schema_update.sql index 35f1c6d7ac..8783ccf3e3 100644 --- a/application/src/main/data/upgrade/3.8.1/schema_update.sql +++ b/application/src/main/data/upgrade/3.8.1/schema_update.sql @@ -59,6 +59,10 @@ $$ ALTER TABLE mobile_app_oauth2_client RENAME TO mobile_app_bundle_oauth2_client; ALTER TABLE mobile_app_bundle_oauth2_client DROP CONSTRAINT IF EXISTS fk_domain; ALTER TABLE mobile_app_bundle_oauth2_client RENAME COLUMN mobile_app_id TO mobile_app_bundle_id; + IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_mobile_app_bundle_oauth2_client_bundle_id') THEN + ALTER TABLE mobile_app_bundle_oauth2_client ADD CONSTRAINT fk_mobile_app_bundle_oauth2_client_bundle_id + FOREIGN KEY (mobile_app_bundle_id) REFERENCES mobile_app_bundle(id) ON DELETE CASCADE; + END IF; END IF; END; $$; diff --git a/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java b/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java index 8f74aab7af..da206193fb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java +++ b/application/src/main/java/org/thingsboard/server/controller/MobileAppController.java @@ -16,7 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; @@ -54,7 +54,6 @@ import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; -import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -77,7 +76,7 @@ public class MobileAppController extends BaseController { private final TbMobileAppService tbMobileAppService; @ApiOperation(value = "Get mobile app login info (getLoginMobileInfo)") - @GetMapping(value = "/api/noauth/mobile") + @GetMapping(value = "/noauth/mobile") public LoginMobileInfo getLoginMobileInfo(@Parameter(description = "Mobile application package name") @RequestParam String pkgName, @Parameter(description = "Platform type", schema = @Schema(allowableValues = {"ANDROID", "IOS"})) @@ -89,7 +88,7 @@ public class MobileAppController extends BaseController { @ApiOperation(value = "Get user mobile app basic info (getUserMobileInfo)", notes = AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')") - @GetMapping(value = "/api/mobile") + @GetMapping(value = "/mobile") public UserMobileInfo getUserMobileInfo(@Parameter(description = "Mobile application package name") @RequestParam String pkgName, @Parameter(description = "Platform type", schema = @Schema(allowableValues = {"ANDROID", "IOS"})) @@ -102,7 +101,7 @@ public class MobileAppController extends BaseController { } @ApiOperation(value = "Get mobile app version info (getMobileVersionInfo)") - @GetMapping(value = "/api/mobile/versionInfo") + @GetMapping(value = "/mobile/versionInfo") public MobileAppVersionInfo getMobileVersionInfo(@Parameter(description = "Mobile application package name") @RequestParam String pkgName, @Parameter(description = "Platform type", schema = @Schema(allowableValues = {"ANDROID", "IOS"})) @@ -164,15 +163,15 @@ public class MobileAppController extends BaseController { tbMobileAppService.delete(mobileApp, getCurrentUser()); } - private List getVisiblePages(MobileAppBundle mobileAppBundle) throws JsonProcessingException { + private JsonNode getVisiblePages(MobileAppBundle mobileAppBundle) throws JsonProcessingException { if (mobileAppBundle != null && mobileAppBundle.getLayoutConfig() != null) { List mobilePages = mobileAppBundle.getLayoutConfig().getPages() .stream() .filter(MobilePage::isVisible) .collect(Collectors.toList()); - return JacksonUtil.readValue(JacksonUtil.writeValueAsViewIgnoringNullFields(mobilePages, Views.Public.class), new TypeReference<>() {}); + return JacksonUtil.toJsonNode(JacksonUtil.writeValueAsViewIgnoringNullFields(mobilePages, Views.Public.class)); } else { - return Collections.emptyList(); + return JacksonUtil.newArrayNode(); } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleService.java index 234d83ec79..35943e72c7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleService.java @@ -31,17 +31,16 @@ public interface MobileAppBundleService extends EntityDaoService { MobileAppBundle saveMobileAppBundle(TenantId tenantId, MobileAppBundle mobileAppBundle); + void updateOauth2Clients(TenantId tenantId, MobileAppBundleId mobileAppBundleId, List oAuth2ClientIds); + MobileAppBundle findMobileAppBundleById(TenantId tenantId, MobileAppBundleId mobileAppBundleId); PageData findMobileAppBundleInfosByTenantId(TenantId tenantId, PageLink pageLink); MobileAppBundleInfo findMobileAppBundleInfoById(TenantId tenantId, MobileAppBundleId mobileAppBundleId); - void updateOauth2Clients(TenantId tenantId, MobileAppBundleId mobileAppBundleId, List oAuth2ClientIds); - MobileAppBundle findMobileAppBundleByPkgNameAndPlatform(TenantId tenantId, String pkgName, PlatformType platform); void deleteMobileAppBundleById(TenantId tenantId, MobileAppBundleId mobileAppBundleId); - void deleteMobileAppBundlesByTenantId(TenantId tenantId); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppService.java index 2da9ba3c2f..570531eb86 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/mobile/MobileAppService.java @@ -38,6 +38,4 @@ public interface MobileAppService extends EntityDaoService { void deleteMobileAppById(TenantId tenantId, MobileAppId mobileAppId); - void deleteMobileAppsByTenantId(TenantId tenantId); - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/mobile/UserMobileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/mobile/UserMobileInfo.java index d93a86f7d6..f7a4033b16 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/mobile/UserMobileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/mobile/UserMobileInfo.java @@ -15,11 +15,10 @@ */ package org.thingsboard.server.common.data.mobile; +import com.fasterxml.jackson.databind.JsonNode; import org.thingsboard.server.common.data.HomeDashboardInfo; import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.mobile.layout.MobilePage; -import java.util.List; -public record UserMobileInfo(User user, HomeDashboardInfo homeDashboardInfo, List pages) { +public record UserMobileInfo(User user, HomeDashboardInfo homeDashboardInfo, JsonNode pages) { } diff --git a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java index cbb6c6a2a7..4997ad8d30 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppBundleServiceImpl.java @@ -78,10 +78,26 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements } @Override - public void deleteMobileAppBundleById(TenantId tenantId, MobileAppBundleId mobileAppBundleId) { - log.trace("Executing deleteMobileAppBundleById [{}]", mobileAppBundleId.getId()); - mobileAppBundleDao.removeById(tenantId, mobileAppBundleId.getId()); - eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(mobileAppBundleId).build()); + public void updateOauth2Clients(TenantId tenantId, MobileAppBundleId mobileAppBundleId, List oAuth2ClientIds) { + log.trace("Executing updateOauth2Clients, mobileAppId [{}], oAuth2ClientIds [{}]", mobileAppBundleId, oAuth2ClientIds); + Set newClientList = oAuth2ClientIds.stream() + .map(clientId -> new MobileAppBundleOauth2Client(mobileAppBundleId, clientId)) + .collect(Collectors.toSet()); + + List existingClients = mobileAppBundleDao.findOauth2ClientsByMobileAppBundleId(tenantId, mobileAppBundleId); + List toRemoveList = existingClients.stream() + .filter(client -> !newClientList.contains(client)) + .toList(); + newClientList.removeIf(existingClients::contains); + + for (MobileAppBundleOauth2Client client : toRemoveList) { + mobileAppBundleDao.removeOauth2Client(tenantId, client); + } + for (MobileAppBundleOauth2Client client : newClientList) { + mobileAppBundleDao.addOauth2Client(tenantId, client); + } + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId) + .entityId(mobileAppBundleId).created(false).build()); } @Override @@ -108,29 +124,6 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements return mobileAppBundleInfo; } - @Override - public void updateOauth2Clients(TenantId tenantId, MobileAppBundleId mobileAppBundleId, List oAuth2ClientIds) { - log.trace("Executing updateOauth2Clients, mobileAppId [{}], oAuth2ClientIds [{}]", mobileAppBundleId, oAuth2ClientIds); - Set newClientList = oAuth2ClientIds.stream() - .map(clientId -> new MobileAppBundleOauth2Client(mobileAppBundleId, clientId)) - .collect(Collectors.toSet()); - - List existingClients = mobileAppBundleDao.findOauth2ClientsByMobileAppBundleId(tenantId, mobileAppBundleId); - List toRemoveList = existingClients.stream() - .filter(client -> !newClientList.contains(client)) - .toList(); - newClientList.removeIf(existingClients::contains); - - for (MobileAppBundleOauth2Client client : toRemoveList) { - mobileAppBundleDao.removeOauth2Client(tenantId, client); - } - for (MobileAppBundleOauth2Client client : newClientList) { - mobileAppBundleDao.addOauth2Client(tenantId, client); - } - eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId) - .entityId(mobileAppBundleId).created(false).build()); - } - @Override public MobileAppBundle findMobileAppBundleByPkgNameAndPlatform(TenantId tenantId, String pkgName, PlatformType platform) { log.trace("Executing findMobileAppBundleByPkgNameAndPlatform, tenantId [{}], pkgName [{}], platform [{}]", tenantId, pkgName, platform); @@ -138,6 +131,19 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements return mobileAppBundleDao.findByPkgNameAndPlatform(tenantId, pkgName, platform); } + @Override + public void deleteMobileAppBundleById(TenantId tenantId, MobileAppBundleId mobileAppBundleId) { + log.trace("Executing deleteMobileAppBundleById [{}]", mobileAppBundleId.getId()); + mobileAppBundleDao.removeById(tenantId, mobileAppBundleId.getId()); + eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(mobileAppBundleId).build()); + } + + @Override + public void deleteByTenantId(TenantId tenantId) { + log.trace("Executing deleteMobileAppsByTenantId, tenantId [{}]", tenantId); + mobileAppBundleDao.deleteByTenantId(tenantId); + } + @Override public Optional> findEntity(TenantId tenantId, EntityId entityId) { return Optional.ofNullable(findMobileAppBundleById(tenantId, new MobileAppBundleId(entityId.getId()))); @@ -149,17 +155,6 @@ public class MobileAppBundleServiceImpl extends AbstractEntityService implements deleteMobileAppBundleById(tenantId, (MobileAppBundleId) id); } - @Override - public void deleteMobileAppBundlesByTenantId(TenantId tenantId) { - log.trace("Executing deleteMobileAppsByTenantId, tenantId [{}]", tenantId); - mobileAppBundleDao.deleteByTenantId(tenantId); - } - - @Override - public void deleteByTenantId(TenantId tenantId) { - deleteMobileAppBundlesByTenantId(tenantId); - } - @Override public EntityType getEntityType() { return EntityType.MOBILE_APP_BUNDLE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java index 132ee6bb36..efd152f944 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/mobile/MobileAppServiceImpl.java @@ -102,12 +102,6 @@ public class MobileAppServiceImpl extends AbstractEntityService implements Mobil deleteMobileAppById(tenantId, (MobileAppId) id); } - @Override - public void deleteMobileAppsByTenantId(TenantId tenantId) { - log.trace("Executing deleteMobileAppsByTenantId, tenantId [{}]", tenantId); - mobileAppDao.deleteByTenantId(tenantId); - } - @Override public MobileApp findByBundleIdAndPlatformType(TenantId tenantId, MobileAppBundleId mobileAppBundleId, PlatformType platformType) { log.trace("Executing findAndroidQrConfig, tenantId [{}], mobileAppBundleId [{}]", tenantId, mobileAppBundleId); @@ -123,7 +117,8 @@ public class MobileAppServiceImpl extends AbstractEntityService implements Mobil @Override public void deleteByTenantId(TenantId tenantId) { - deleteMobileAppsByTenantId(tenantId); + log.trace("Executing deleteByTenantId, tenantId [{}]", tenantId); + mobileAppDao.deleteByTenantId(tenantId); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/MobileAppBundleOauth2ClientEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/MobileAppBundleOauth2ClientEntity.java index 7232687cc1..152c8e3ebf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/MobileAppBundleOauth2ClientEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/MobileAppBundleOauth2ClientEntity.java @@ -51,9 +51,9 @@ public final class MobileAppBundleOauth2ClientEntity implements ToData { if (!qrCodeSettings.isUseDefaultApp()) { if (qrCodeSettings.isAndroidEnabled()) { MobileApp androidApp = mobileAppDao.findByBundleIdAndPlatformType(tenantId, mobileAppBundleId, PlatformType.ANDROID); - if (androidApp != null && androidApp.getStoreInfo() == null) { + if (androidApp != null && androidApp.getStatus() != MobileAppStatus.PUBLISHED) { throw new DataValidationException("The mobile app bundle references an Android app that has not been published!"); } } if (qrCodeSettings.isIosEnabled()) { MobileApp iosApp = mobileAppDao.findByBundleIdAndPlatformType(tenantId, mobileAppBundleId, PlatformType.IOS); - if (iosApp != null && iosApp.getStoreInfo() == null) { + if (iosApp != null && iosApp.getStatus() != MobileAppStatus.PUBLISHED) { throw new DataValidationException("The mobile app bundle references an iOS app that has not been published!"); } }