Browse Source

simplified data structure for mobile all store info object

pull/11835/head
dashevchenko 2 years ago
parent
commit
d32fb472d1
  1. 8
      application/src/main/data/upgrade/3.8.0/schema_update.sql
  2. 19
      application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java
  3. 46
      application/src/test/java/org/thingsboard/server/controller/MobileAppControllerTest.java
  4. 14
      application/src/test/java/org/thingsboard/server/controller/QrCodeSettingsControllerTest.java
  5. 49
      common/data/src/main/java/org/thingsboard/server/common/data/mobile/AndroidQrCodeConfig.java
  6. 6
      common/data/src/main/java/org/thingsboard/server/common/data/mobile/MobileApp.java
  7. 38
      common/data/src/main/java/org/thingsboard/server/common/data/mobile/QrCodeConfig.java
  8. 18
      common/data/src/main/java/org/thingsboard/server/common/data/mobile/StoreInfo.java
  9. 4
      dao/src/main/java/org/thingsboard/server/dao/mobile/QrCodeSettingService.java
  10. 6
      dao/src/main/java/org/thingsboard/server/dao/mobile/QrCodeSettingServiceImpl.java
  11. 6
      dao/src/main/java/org/thingsboard/server/dao/model/sql/MobileAppEntity.java

8
application/src/main/data/upgrade/3.8.0/schema_update.sql

@ -109,13 +109,13 @@ $$
androidAppId := uuid_generate_v4();
INSERT INTO mobile_app(id, created_time, tenant_id, pkg_name, platform_type, status, qr_code_config)
VALUES (androidAppId, (extract(epoch from now()) * 1000), qrCodeRecord.tenant_id,
qrCodeRecord.android_config::jsonb ->> 'appPackage', 'ANDROID', 'PUBLISHED', qrCodeRecord.android_config::jsonb || '{"type": "ANDROID"}'::jsonb);
qrCodeRecord.android_config::jsonb ->> 'appPackage', 'ANDROID', 'PUBLISHED', qrCodeRecord.android_config::jsonb - 'appPackage');
generatedBundleId := uuid_generate_v4();
INSERT INTO mobile_app_bundle(id, created_time, tenant_id, title, android_app_id)
VALUES (generatedBundleId, (extract(epoch from now()) * 1000), qrCodeRecord.tenant_id, 'App bundle for qr code', androidAppId);
UPDATE qr_code_settings SET mobile_app_bundle_id = generatedBundleId WHERE id = qrCodeRecord.id;
ELSE
UPDATE mobile_app SET qr_code_config = qrCodeRecord.android_config::jsonb || '{"type": "ANDROID"}'::jsonb WHERE id = androidAppId;
UPDATE mobile_app SET qr_code_config = qrCodeRecord.android_config::jsonb - 'appPackage' WHERE id = androidAppId;
UPDATE qr_code_settings SET mobile_app_bundle_id = (SELECT id FROM mobile_app_bundle WHERE mobile_app_bundle.android_app_id = androidAppId) WHERE id = qrCodeRecord.id;
END IF;
@ -126,7 +126,7 @@ $$
iosAppId := uuid_generate_v4();
INSERT INTO mobile_app(id, created_time, tenant_id, pkg_name, platform_type, status, qr_code_config)
VALUES (iosAppId, (extract(epoch from now()) * 1000), qrCodeRecord.tenant_id,
iosPkgName, 'IOS', 'PUBLISHED', qrCodeRecord.ios_config::jsonb || '{"type": "IOS"}'::jsonb);
iosPkgName, 'IOS', 'PUBLISHED', qrCodeRecord.ios_config);
IF generatedBundleId IS NULL THEN
generatedBundleId := uuid_generate_v4();
INSERT INTO mobile_app_bundle(id, created_time, tenant_id, title, ios_app_id)
@ -136,7 +136,7 @@ $$
UPDATE mobile_app_bundle SET ios_app_id = iosAppId WHERE id = generatedBundleId;
END IF;
ELSE
UPDATE mobile_app SET qr_code_config = qrCodeRecord.ios_config::jsonb || '{"type": "IOS"}'::jsonb WHERE id = iosAppId;
UPDATE mobile_app SET qr_code_config = qrCodeRecord.ios_config WHERE id = iosAppId;
UPDATE qr_code_settings SET mobile_app_bundle_id = (SELECT id FROM mobile_app_bundle WHERE mobile_app_bundle.ios_app_id = iosAppId) WHERE id = qrCodeRecord.id;
END IF;
END LOOP;

19
application/src/main/java/org/thingsboard/server/controller/QrCodeSettingsController.java

@ -33,10 +33,9 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.MobileAppBundleId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.mobile.AndroidQrCodeConfig;
import org.thingsboard.server.common.data.mobile.IosQrCodeConfig;
import org.thingsboard.server.common.data.mobile.MobileApp;
import org.thingsboard.server.common.data.mobile.QrCodeSettings;
import org.thingsboard.server.common.data.mobile.StoreInfo;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.config.annotations.ApiOperation;
@ -101,9 +100,10 @@ public class QrCodeSettingsController extends BaseController {
@ApiOperation(value = "Get associated android applications (getAssetLinks)")
@GetMapping(value = "/.well-known/assetlinks.json")
public ResponseEntity<JsonNode> getAssetLinks() {
AndroidQrCodeConfig androidQrConfig = (AndroidQrCodeConfig) qrCodeSettingService.findAppQrCodeConfig(TenantId.SYS_TENANT_ID, ANDROID);
if (androidQrConfig != null && androidQrConfig.isEnabled()) {
return ResponseEntity.ok(JacksonUtil.toJsonNode(String.format(ASSET_LINKS_PATTERN, androidQrConfig.getAppPackage(), androidQrConfig.getSha256CertFingerprints())));
MobileApp mobileApp = qrCodeSettingService.findAppFromQrCodeSettings(TenantId.SYS_TENANT_ID, ANDROID);
StoreInfo storeInfo = mobileApp != null ? mobileApp.getStoreInfo() : null;
if (storeInfo != null && storeInfo.isEnabled() && storeInfo.getSha256CertFingerprints() != null) {
return ResponseEntity.ok(JacksonUtil.toJsonNode(String.format(ASSET_LINKS_PATTERN, mobileApp.getPkgName(), storeInfo.getSha256CertFingerprints())));
} else {
return ResponseEntity.notFound().build();
}
@ -112,9 +112,10 @@ public class QrCodeSettingsController extends BaseController {
@ApiOperation(value = "Get associated ios applications (getAppleAppSiteAssociation)")
@GetMapping(value = "/.well-known/apple-app-site-association")
public ResponseEntity<JsonNode> getAppleAppSiteAssociation() {
IosQrCodeConfig iosQrCodeConfig = (IosQrCodeConfig) qrCodeSettingService.findAppQrCodeConfig(TenantId.SYS_TENANT_ID, IOS);
if (iosQrCodeConfig != null && iosQrCodeConfig.isEnabled()) {
return ResponseEntity.ok(JacksonUtil.toJsonNode(String.format(APPLE_APP_SITE_ASSOCIATION_PATTERN, iosQrCodeConfig.getAppId())));
MobileApp mobileApp = qrCodeSettingService.findAppFromQrCodeSettings(TenantId.SYS_TENANT_ID, IOS);
StoreInfo storeInfo = mobileApp != null ? mobileApp.getStoreInfo() : null;
if (storeInfo != null && storeInfo.isEnabled() && storeInfo.getAppId() != null) {
return ResponseEntity.ok(JacksonUtil.toJsonNode(String.format(APPLE_APP_SITE_ASSOCIATION_PATTERN, storeInfo.getAppId())));
} else {
return ResponseEntity.notFound().build();
}
@ -197,7 +198,7 @@ public class QrCodeSettingsController extends BaseController {
return null;
}
MobileApp mobileApp = mobileAppService.findByBundleIdAndPlatformType(TenantId.SYS_TENANT_ID, mobileAppBundleId, platformType);
return (mobileApp != null && mobileApp.getQrCodeConfig() != null) ? mobileApp.getQrCodeConfig().getStoreLink() : null;
return (mobileApp != null && mobileApp.getStoreInfo() != null) ? mobileApp.getStoreInfo().getStoreLink() : null;
}
}

46
application/src/test/java/org/thingsboard/server/controller/MobileAppControllerTest.java

@ -21,8 +21,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.mobile.AndroidQrCodeConfig;
import org.thingsboard.server.common.data.mobile.IosQrCodeConfig;
import org.thingsboard.server.common.data.mobile.MobileApp;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.page.PageData;
@ -83,50 +81,6 @@ public class MobileAppControllerTest extends AbstractControllerTest {
.andExpect(statusReason(containsString("appSecret must be at least 16 and max 2048 characters")));
}
@Test
public void testShouldNotSaveMobileAppWithWrongQrCodeConf() throws Exception {
MobileApp mobileApp = validMobileApp("mobileApp.ce", PlatformType.ANDROID);
AndroidQrCodeConfig androidQrCodeConfig = AndroidQrCodeConfig.builder()
.enabled(true)
.appPackage(null)
.sha256CertFingerprints(null)
.build();
mobileApp.setQrCodeConfig(androidQrCodeConfig);
doPost("/api/mobile/app", mobileApp)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Validation error: appPackage must not be blank, sha256CertFingerprints must not be blank, storeLink must not be blank")));
androidQrCodeConfig.setAppPackage("test_app_package");
doPost("/api/mobile/app", mobileApp)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Validation error: sha256CertFingerprints must not be blank, storeLink must not be blank")));
androidQrCodeConfig.setSha256CertFingerprints("test_sha_256");
androidQrCodeConfig.setStoreLink("https://store.com");
doPost("/api/mobile/app", mobileApp)
.andExpect(status().isOk());
}
@Test
public void testShouldNotSaveMobileAppWithWrongIosConf() throws Exception {
MobileApp mobileApp = validMobileApp("mobileApp.ce", PlatformType.ANDROID);
IosQrCodeConfig iosQrCodeConfig = IosQrCodeConfig.builder()
.enabled(true)
.appId(null)
.build();
mobileApp.setQrCodeConfig(iosQrCodeConfig);
doPost("/api/mobile/app", mobileApp)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Validation error: appId must not be blank, storeLink must not be blank")));
iosQrCodeConfig.setAppId("test_app_id");
iosQrCodeConfig.setStoreLink("https://store.com");
doPost("/api/mobile/app", mobileApp)
.andExpect(status().isOk());
}
@Test
public void testGetTenantAppsByPlatformTypeSaveMobileApp() throws Exception {
MobileApp androidApp = doPost("/api/mobile/app", validMobileApp("android.1", PlatformType.ANDROID), MobileApp.class);

14
application/src/test/java/org/thingsboard/server/controller/QrCodeSettingsControllerTest.java

@ -23,13 +23,12 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.mobile.AndroidQrCodeConfig;
import org.thingsboard.server.common.data.mobile.IosQrCodeConfig;
import org.thingsboard.server.common.data.mobile.MobileApp;
import org.thingsboard.server.common.data.mobile.MobileAppBundle;
import org.thingsboard.server.common.data.mobile.MobileAppBundleInfo;
import org.thingsboard.server.common.data.mobile.QRCodeConfig;
import org.thingsboard.server.common.data.mobile.QrCodeSettings;
import org.thingsboard.server.common.data.mobile.StoreInfo;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -68,22 +67,21 @@ public class QrCodeSettingsControllerTest extends AbstractControllerTest {
loginSysAdmin();
MobileApp androidApp = validMobileApp( "my.android.package", PlatformType.ANDROID);
AndroidQrCodeConfig androidQrCodeConfig = AndroidQrCodeConfig.builder()
.appPackage(ANDROID_PACKAGE_NAME)
StoreInfo androidStoreInfo = StoreInfo.builder()
.sha256CertFingerprints(ANDROID_APP_SHA256)
.storeLink(ANDROID_STORE_LINK)
.enabled(true)
.build();
androidApp.setQrCodeConfig(androidQrCodeConfig);
androidApp.setStoreInfo(androidStoreInfo);
MobileApp savedAndroidApp = doPost("/api/mobile/app", androidApp, MobileApp.class);
MobileApp iosApp = validMobileApp( "my.ios.package", PlatformType.IOS);
IosQrCodeConfig iosQrCodeConfig = IosQrCodeConfig.builder()
StoreInfo iosQrCodeConfig = StoreInfo.builder()
.appId(APPLE_APP_ID)
.enabled(true)
.storeLink(IOS_STORE_LINK)
.build();
iosApp.setQrCodeConfig(iosQrCodeConfig);
iosApp.setStoreInfo(iosQrCodeConfig);
MobileApp savedIosApp = doPost("/api/mobile/app", iosApp, MobileApp.class);
mobileAppBundle = new MobileAppBundle();
@ -180,7 +178,7 @@ public class QrCodeSettingsControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
JsonNode assetLinks = doGet("/.well-known/assetlinks.json", JsonNode.class);
assertThat(assetLinks.get(0).get("target").get("package_name").asText()).isEqualTo(ANDROID_PACKAGE_NAME);
assertThat(assetLinks.get(0).get("target").get("package_name").asText()).isEqualTo("my.android.package");
assertThat(assetLinks.get(0).get("target").get("sha256_cert_fingerprints").get(0).asText()).isEqualTo(ANDROID_APP_SHA256);
JsonNode appleAssociation = doGet("/.well-known/apple-app-site-association", JsonNode.class);

49
common/data/src/main/java/org/thingsboard/server/common/data/mobile/AndroidQrCodeConfig.java

@ -1,49 +0,0 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.mobile;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.validation.NoXss;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class AndroidQrCodeConfig implements QrCodeConfig {
private boolean enabled;
@NoXss
@NotBlank
private String appPackage;
@NoXss
@NotBlank
private String sha256CertFingerprints;
@NoXss
@NotBlank
private String storeLink;
@Override
public PlatformType getType() {
return PlatformType.ANDROID;
}
}

6
common/data/src/main/java/org/thingsboard/server/common/data/mobile/MobileApp.java

@ -55,9 +55,9 @@ public class MobileApp extends BaseData<MobileAppId> implements HasTenantId, Has
@Schema(description = "Application version info")
@Valid
private MobileAppVersionInfo versionInfo;
@Schema(description = "Application qr code configuration")
@Schema(description = "Application store information")
@Valid
private QrCodeConfig qrCodeConfig;
private StoreInfo storeInfo;
public MobileApp() {
super();
@ -75,7 +75,7 @@ public class MobileApp extends BaseData<MobileAppId> implements HasTenantId, Has
this.platformType = mobile.platformType;
this.status = mobile.status;
this.versionInfo = mobile.versionInfo;
this.qrCodeConfig = mobile.qrCodeConfig;
this.storeInfo = mobile.storeInfo;
}
@Override

38
common/data/src/main/java/org/thingsboard/server/common/data/mobile/QrCodeConfig.java

@ -1,38 +0,0 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.mobile;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.thingsboard.server.common.data.oauth2.PlatformType;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = AndroidQrCodeConfig.class, name = "ANDROID"),
@JsonSubTypes.Type(value = IosQrCodeConfig.class, name = "IOS")
})
public interface QrCodeConfig {
PlatformType getType();
String getStoreLink();
}

18
common/data/src/main/java/org/thingsboard/server/common/data/mobile/IosQrCodeConfig.java → common/data/src/main/java/org/thingsboard/server/common/data/mobile/StoreInfo.java

@ -15,32 +15,20 @@
*/
package org.thingsboard.server.common.data.mobile;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.common.data.validation.NoXss;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class IosQrCodeConfig implements QrCodeConfig {
public class StoreInfo {
private boolean enabled;
@NoXss
@NotBlank
private String appId;
@NoXss
@NotBlank
private String sha256CertFingerprints;
@NoXss
private String storeLink;
@Override
public PlatformType getType() {
return PlatformType.IOS;
}
}

4
dao/src/main/java/org/thingsboard/server/dao/mobile/QrCodeSettingService.java

@ -16,7 +16,7 @@
package org.thingsboard.server.dao.mobile;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.mobile.QrCodeConfig;
import org.thingsboard.server.common.data.mobile.MobileApp;
import org.thingsboard.server.common.data.mobile.QrCodeSettings;
import org.thingsboard.server.common.data.oauth2.PlatformType;
@ -26,7 +26,7 @@ public interface QrCodeSettingService {
QrCodeSettings findQrCodeSettings(TenantId tenantId);
QrCodeConfig findAppQrCodeConfig(TenantId sysTenantId, PlatformType platformType);
MobileApp findAppFromQrCodeSettings(TenantId sysTenantId, PlatformType platformType);
void deleteByTenantId(TenantId tenantId);

6
dao/src/main/java/org/thingsboard/server/dao/mobile/QrCodeSettingServiceImpl.java

@ -22,7 +22,7 @@ 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.BadgePosition;
import org.thingsboard.server.common.data.mobile.QrCodeConfig;
import org.thingsboard.server.common.data.mobile.MobileApp;
import org.thingsboard.server.common.data.mobile.QrCodeSettings;
import org.thingsboard.server.common.data.mobile.QRCodeConfig;
import org.thingsboard.server.common.data.oauth2.PlatformType;
@ -75,10 +75,10 @@ public class QrCodeSettingServiceImpl extends AbstractCachedEntityService<Tenant
}
@Override
public QrCodeConfig findAppQrCodeConfig(TenantId tenantId, PlatformType platformType) {
public MobileApp findAppFromQrCodeSettings(TenantId tenantId, PlatformType platformType) {
log.trace("Executing findAppQrCodeConfig for tenant [{}] ", tenantId);
QrCodeSettings qrCodeSettings = findQrCodeSettings(tenantId);
return qrCodeSettings.getMobileAppBundleId() != null ? mobileAppService.findByBundleIdAndPlatformType(tenantId, qrCodeSettings.getMobileAppBundleId(), platformType).getQrCodeConfig() : null;
return qrCodeSettings.getMobileAppBundleId() != null ? mobileAppService.findByBundleIdAndPlatformType(tenantId, qrCodeSettings.getMobileAppBundleId(), platformType) : null;
}
@Override

6
dao/src/main/java/org/thingsboard/server/dao/model/sql/MobileAppEntity.java

@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.mobile.MobileAppStatus;
import org.thingsboard.server.common.data.mobile.MobileApp;
import org.thingsboard.server.common.data.mobile.MobileAppVersionInfo;
import org.thingsboard.server.common.data.mobile.QrCodeConfig;
import org.thingsboard.server.common.data.mobile.StoreInfo;
import org.thingsboard.server.common.data.oauth2.PlatformType;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
@ -84,7 +84,7 @@ public class MobileAppEntity extends BaseSqlEntity<MobileApp> {
this.platformType = mobile.getPlatformType();
this.status = mobile.getStatus();
this.versionInfo = toJson(mobile.getVersionInfo());
this.qrCodeConfig = toJson(mobile.getQrCodeConfig());
this.qrCodeConfig = toJson(mobile.getStoreInfo());
}
@Override
@ -100,7 +100,7 @@ public class MobileAppEntity extends BaseSqlEntity<MobileApp> {
mobile.setPlatformType(platformType);
mobile.setStatus(status);
mobile.setVersionInfo(fromJson(versionInfo, MobileAppVersionInfo.class));
mobile.setQrCodeConfig(fromJson(qrCodeConfig, QrCodeConfig.class));
mobile.setStoreInfo(fromJson(qrCodeConfig, StoreInfo.class));
return mobile;
}
}

Loading…
Cancel
Save