diff --git a/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java b/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java index a65d8506ff..0cd0884126 100644 --- a/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java @@ -135,7 +135,7 @@ public class MobileApplicationController extends BaseController { SecurityUser currentUser = getCurrentUser(); accessControlService.checkPermission(currentUser, Resource.MOBILE_APP_SETTINGS, Operation.READ); - return mobileAppSettingsService.getMobileAppSettings(currentUser.getTenantId()); + return mobileAppSettingsService.getMobileAppSettings(TenantId.SYS_TENANT_ID); } @ApiOperation(value = "Get the deep link to the associated mobile application (getMobileAppDeepLink)", diff --git a/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretCaffeineCache.java b/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretCaffeineCache.java index fb4c5e64cc..916d58afd7 100644 --- a/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretCaffeineCache.java +++ b/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretCaffeineCache.java @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.security.model.JwtPair; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) -@Service("QRSecretCache") +@Service("MobileSecretCache") public class MobileSecretCaffeineCache extends CaffeineTbTransactionalCache { public MobileSecretCaffeineCache(CacheManager cacheManager) { diff --git a/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretRedisCache.java b/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretRedisCache.java index d5cb25c909..d29a104ae9 100644 --- a/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretRedisCache.java +++ b/application/src/main/java/org/thingsboard/server/service/qr/MobileSecretRedisCache.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.model.JwtPair; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") -@Service("QRSecretCache") +@Service("MobileSecretCache") public class MobileSecretRedisCache extends RedisTbTransactionalCache { public MobileSecretRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java index d26e49e4ab..af1b34ae71 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPermissions.java @@ -49,6 +49,7 @@ public class CustomerUserPermissions extends AbstractPermissions { put(Resource.DEVICE_PROFILE, profilePermissionChecker); put(Resource.ASSET_PROFILE, profilePermissionChecker); put(Resource.TB_RESOURCE, customerResourcePermissionChecker); + put(Resource.MOBILE_APP_SETTINGS, new PermissionChecker.GenericPermissionChecker(Operation.READ)); } private static final PermissionChecker customerAlarmPermissionChecker = new PermissionChecker() { diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java index f4117e1a36..10807e4b5a 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java +++ b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java @@ -50,7 +50,7 @@ public class TenantAdminPermissions extends AbstractPermissions { put(Resource.QUEUE, queuePermissionChecker); put(Resource.VERSION_CONTROL, PermissionChecker.allowAllPermissionChecker); put(Resource.NOTIFICATION, tenantEntityPermissionChecker); - put(Resource.MOBILE_APP_SETTINGS, PermissionChecker.allowAllPermissionChecker); + put(Resource.MOBILE_APP_SETTINGS, new PermissionChecker.GenericPermissionChecker(Operation.READ)); } public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() { diff --git a/application/src/test/java/org/thingsboard/server/controller/MobileApplicationControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/MobileApplicationControllerTest.java index 16624cefb1..9e493980b1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/MobileApplicationControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/MobileApplicationControllerTest.java @@ -104,8 +104,10 @@ public class MobileApplicationControllerTest extends AbstractControllerTest { Pattern expectedPattern = Pattern.compile("https://([^/]+)/api/noauth/qr\\?secret=([^&]+)&ttl=([^&]+)&host=([^&]+)"); Matcher parsedDeepLink = expectedPattern.matcher(deepLink); assertThat(parsedDeepLink.matches()).isTrue(); + String appHost = parsedDeepLink.group(1); String secret = parsedDeepLink.group(2); String ttl = parsedDeepLink.group(3); + assertThat(appHost).isEqualTo("demo.thingsboard.io"); assertThat(ttl).isEqualTo(String.valueOf(mobileSecretKeyTtl)); JwtPair jwtPair = doGet("/api/noauth/qr/" + secret, JwtPair.class); @@ -128,5 +130,31 @@ public class MobileApplicationControllerTest extends AbstractControllerTest { JwtPair customerJwtPair = doGet("/api/noauth/qr/" + customerSecret, JwtPair.class); assertThat(customerJwtPair).isNotNull(); + + // update mobile setting to use custom one + loginSysAdmin(); + MobileAppSettings mobileAppSettings = doGet("/api/mobile/app/settings", MobileAppSettings.class); + mobileAppSettings.setUseDefault(false); + doPost("/api/mobile/app/settings", mobileAppSettings); + + String customAppDeepLink = doGet("/api/mobile/deepLink", String.class); + Pattern customAppExpectedPattern = Pattern.compile("https://([^/]+)/api/noauth/qr\\?secret=([^&]+)&ttl=([^&]+)"); + Matcher customAppParsedDeepLink = customAppExpectedPattern.matcher(customAppDeepLink); + assertThat(customAppParsedDeepLink.matches()).isTrue(); + assertThat(customAppParsedDeepLink.group(1)).isEqualTo("localhost"); + + loginTenantAdmin(); + String tenantCustomAppDeepLink = doGet("/api/mobile/deepLink", String.class); + Matcher tenantCustomAppParsedDeepLink = customAppExpectedPattern.matcher(tenantCustomAppDeepLink); + assertThat(tenantCustomAppParsedDeepLink.matches()).isTrue(); + assertThat(tenantCustomAppParsedDeepLink.group(1)).isEqualTo("localhost"); + + loginCustomerUser(); + String customerCustomAppDeepLink = doGet("/api/mobile/deepLink", String.class); + Matcher customerCustomAppParsedDeepLink = customAppExpectedPattern.matcher(customerCustomAppDeepLink); + assertThat(customerCustomAppParsedDeepLink.matches()).isTrue(); + assertThat(customerCustomAppParsedDeepLink.group(1)).isEqualTo("localhost"); + + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/mobile/QRCodeConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/mobile/QRCodeConfig.java index 20de410137..b3f975870e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/mobile/QRCodeConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/mobile/QRCodeConfig.java @@ -16,12 +16,14 @@ package org.thingsboard.server.common.data.mobile; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import org.thingsboard.server.common.data.validation.NoXss; @Data +@Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @@ -29,7 +31,7 @@ public class QRCodeConfig { private boolean showOnHomePage; private boolean badgeEnabled; - private boolean labelEnabled; + private boolean qrCodeLabelEnabled; private BadgePosition badgePosition; private BadgeStyle badgeStyle; @NoXss diff --git a/dao/src/main/java/org/thingsboard/server/dao/mobile/BaseMobileAppSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/mobile/BaseMobileAppSettingsService.java index 1c05cfbb92..d11edafb1b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/mobile/BaseMobileAppSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/mobile/BaseMobileAppSettingsService.java @@ -20,8 +20,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.mobile.AndroidConfig; import org.thingsboard.server.common.data.mobile.BadgePosition; import org.thingsboard.server.common.data.mobile.BadgeStyle; +import org.thingsboard.server.common.data.mobile.IosConfig; import org.thingsboard.server.common.data.mobile.MobileAppSettings; import org.thingsboard.server.common.data.mobile.QRCodeConfig; import org.thingsboard.server.dao.entity.AbstractCachedService; @@ -45,7 +47,7 @@ public class BaseMobileAppSettingsService extends AbstractCachedService mobileAppSettingsDao.findByTenantId(tenantId), false); + () -> mobileAppSettingsDao.findByTenantId(tenantId), true); return constructMobileAppSettings(mobileAppSettings); } @@ -60,14 +62,25 @@ public class BaseMobileAppSettingsService extends AbstractCachedService