extended mobile application settings with default store links
This commit is contained in:
parent
be5220a9e9
commit
951f017e7c
@ -58,6 +58,8 @@ public class MobileApplicationController extends BaseController {
|
|||||||
|
|
||||||
@Value("${cache.specs.mobileSecretKey.timeToLiveInMinutes:2}")
|
@Value("${cache.specs.mobileSecretKey.timeToLiveInMinutes:2}")
|
||||||
private int mobileSecretKeyTtl;
|
private int mobileSecretKeyTtl;
|
||||||
|
@Value("${mobileApp.domain:demo.thingsboard.io}")
|
||||||
|
private String defaultAppDomain;
|
||||||
|
|
||||||
public static final String ASSET_LINKS_PATTERN = "[{\n" +
|
public static final String ASSET_LINKS_PATTERN = "[{\n" +
|
||||||
" \"relation\": [\"delegate_permission/common.handle_all_urls\"],\n" +
|
" \"relation\": [\"delegate_permission/common.handle_all_urls\"],\n" +
|
||||||
@ -83,7 +85,6 @@ public class MobileApplicationController extends BaseController {
|
|||||||
|
|
||||||
public static final String SECRET = "secret";
|
public static final String SECRET = "secret";
|
||||||
public static final String SECRET_PARAM_DESCRIPTION = "A string value representing short-lived secret key";
|
public static final String SECRET_PARAM_DESCRIPTION = "A string value representing short-lived secret key";
|
||||||
public static final String DEFAULT_APP_DOMAIN = "demo.thingsboard.io";
|
|
||||||
public static final String DEEP_LINK_PATTERN = "https://%s/api/noauth/qr?secret=%s&ttl=%s";
|
public static final String DEEP_LINK_PATTERN = "https://%s/api/noauth/qr?secret=%s&ttl=%s";
|
||||||
|
|
||||||
private final SystemSecurityService systemSecurityService;
|
private final SystemSecurityService systemSecurityService;
|
||||||
@ -149,7 +150,7 @@ public class MobileApplicationController extends BaseController {
|
|||||||
if (!mobileAppSettings.isUseDefaultApp()) {
|
if (!mobileAppSettings.isUseDefaultApp()) {
|
||||||
appDomain = platformDomain;
|
appDomain = platformDomain;
|
||||||
} else {
|
} else {
|
||||||
appDomain = DEFAULT_APP_DOMAIN;
|
appDomain = defaultAppDomain;
|
||||||
}
|
}
|
||||||
String deepLink = String.format(DEEP_LINK_PATTERN, appDomain, secret, mobileSecretKeyTtl);
|
String deepLink = String.format(DEEP_LINK_PATTERN, appDomain, secret, mobileSecretKeyTtl);
|
||||||
if (!appDomain.equals(platformDomain)) {
|
if (!appDomain.equals(platformDomain)) {
|
||||||
@ -170,13 +171,16 @@ public class MobileApplicationController extends BaseController {
|
|||||||
@GetMapping(value = "/api/noauth/qr")
|
@GetMapping(value = "/api/noauth/qr")
|
||||||
public ResponseEntity<?> getApplicationRedirect(@RequestHeader(value = "User-Agent") String userAgent) {
|
public ResponseEntity<?> getApplicationRedirect(@RequestHeader(value = "User-Agent") String userAgent) {
|
||||||
MobileAppSettings mobileAppSettings = mobileAppSettingsService.getMobileAppSettings(TenantId.SYS_TENANT_ID);
|
MobileAppSettings mobileAppSettings = mobileAppSettingsService.getMobileAppSettings(TenantId.SYS_TENANT_ID);
|
||||||
|
boolean useDefaultApp = mobileAppSettings.isUseDefaultApp();
|
||||||
|
String googlePlayLink = useDefaultApp ? mobileAppSettings.getDefaultGooglePlayLink() : mobileAppSettings.getAndroidConfig().getStoreLink();
|
||||||
|
String appStoreLink = useDefaultApp ? mobileAppSettings.getDefaultGooglePlayLink() : mobileAppSettings.getIosConfig().getStoreLink();
|
||||||
if (userAgent.contains("Android")) {
|
if (userAgent.contains("Android")) {
|
||||||
return ResponseEntity.status(HttpStatus.FOUND)
|
return ResponseEntity.status(HttpStatus.FOUND)
|
||||||
.header("Location", mobileAppSettings.getAndroidConfig().getStoreLink())
|
.header("Location", googlePlayLink)
|
||||||
.build();
|
.build();
|
||||||
} else if (userAgent.contains("iPhone") || userAgent.contains("iPad")) {
|
} else if (userAgent.contains("iPhone") || userAgent.contains("iPad")) {
|
||||||
return ResponseEntity.status(HttpStatus.FOUND)
|
return ResponseEntity.status(HttpStatus.FOUND)
|
||||||
.header("Location", mobileAppSettings.getIosConfig().getStoreLink())
|
.header("Location", appStoreLink)
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
|
|||||||
@ -1463,9 +1463,9 @@ queue:
|
|||||||
- key: max.poll.interval.ms
|
- key: max.poll.interval.ms
|
||||||
# Example of specific consumer properties value per topic for VC
|
# Example of specific consumer properties value per topic for VC
|
||||||
value: "${TB_QUEUE_KAFKA_VC_MAX_POLL_INTERVAL_MS:600000}"
|
value: "${TB_QUEUE_KAFKA_VC_MAX_POLL_INTERVAL_MS:600000}"
|
||||||
# tb_rule_engine.sq:
|
# tb_rule_engine.sq:
|
||||||
# - key: max.poll.records
|
# - key: max.poll.records
|
||||||
# value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}"
|
# value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}"
|
||||||
tb_housekeeper:
|
tb_housekeeper:
|
||||||
# Consumer properties for Housekeeper tasks topic
|
# Consumer properties for Housekeeper tasks topic
|
||||||
- key: max.poll.records
|
- key: max.poll.records
|
||||||
@ -1794,3 +1794,12 @@ management:
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
# Enable the org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator.doHealthCheck
|
# Enable the org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator.doHealthCheck
|
||||||
enabled: "false"
|
enabled: "false"
|
||||||
|
|
||||||
|
# Mobile application settings for Thingsboard mobile application
|
||||||
|
mobileApp:
|
||||||
|
# Host for default Thingsboard mobile application for common edition
|
||||||
|
domain: "${TB_MOBILE_APP_DOMAIN:demo.thingsboard.io}"
|
||||||
|
# Link to Google Play store for default Thingsboard mobile application
|
||||||
|
googlePlayLink: "${TB_MOBILE_APP_GOOGLE_PLAY_LINK:https://play.google.com/store/apps/details?id=org.thingsboard.demo.app}"
|
||||||
|
# Link to App Store for default Thingsboard mobile application
|
||||||
|
appStoreLink: "${TB_MOBILE_APP_APP_STORE_LINK:https://apps.apple.com/us/app/thingsboard-live/id1594355695}"
|
||||||
|
|||||||
@ -15,29 +15,46 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.common.data.mobile;
|
package org.thingsboard.server.common.data.mobile;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import org.thingsboard.server.common.data.BaseData;
|
import org.thingsboard.server.common.data.BaseData;
|
||||||
import org.thingsboard.server.common.data.HasTenantId;
|
import org.thingsboard.server.common.data.HasTenantId;
|
||||||
import org.thingsboard.server.common.data.id.MobileAppSettingsId;
|
import org.thingsboard.server.common.data.id.MobileAppSettingsId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
|
|
||||||
|
@Schema
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class MobileAppSettings extends BaseData<MobileAppSettingsId> implements HasTenantId {
|
public class MobileAppSettings extends BaseData<MobileAppSettingsId> implements HasTenantId {
|
||||||
|
|
||||||
private static final long serialVersionUID = 2628323657987010348L;
|
private static final long serialVersionUID = 2628323657987010348L;
|
||||||
|
|
||||||
|
@Schema(description = "JSON object with Tenant Id.", accessMode = Schema.AccessMode.READ_ONLY)
|
||||||
private TenantId tenantId;
|
private TenantId tenantId;
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "Type of application: true means use default Thingsboard app", example = "true")
|
||||||
private boolean useDefaultApp;
|
private boolean useDefaultApp;
|
||||||
@Valid
|
@Valid
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "Android mobile app configuration.")
|
||||||
private AndroidConfig androidConfig;
|
private AndroidConfig androidConfig;
|
||||||
@Valid
|
@Valid
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "Ios mobile app configuration.")
|
||||||
private IosConfig iosConfig;
|
private IosConfig iosConfig;
|
||||||
@Valid
|
@Valid
|
||||||
|
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "QR code config configuration.")
|
||||||
private QRCodeConfig qrCodeConfig;
|
private QRCodeConfig qrCodeConfig;
|
||||||
|
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
private String defaultGooglePlayLink;
|
||||||
|
|
||||||
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
|
private String defaultAppStoreLink;
|
||||||
|
|
||||||
public MobileAppSettings() {
|
public MobileAppSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MobileAppSettings(MobileAppSettingsId id) {
|
public MobileAppSettings(MobileAppSettingsId id) {
|
||||||
super(id);
|
super(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,9 +17,9 @@ package org.thingsboard.server.dao.mobile;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.event.TransactionalEventListener;
|
import org.springframework.transaction.event.TransactionalEventListener;
|
||||||
import org.thingsboard.server.common.data.StringUtils;
|
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.mobile.AndroidConfig;
|
import org.thingsboard.server.common.data.mobile.AndroidConfig;
|
||||||
import org.thingsboard.server.common.data.mobile.BadgePosition;
|
import org.thingsboard.server.common.data.mobile.BadgePosition;
|
||||||
@ -40,8 +40,11 @@ public class BaseMobileAppSettingsService extends AbstractCachedEntityService<Te
|
|||||||
|
|
||||||
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||||
private static final String DEFAULT_QR_CODE_LABEL = "Scan to connect or download mobile app";
|
private static final String DEFAULT_QR_CODE_LABEL = "Scan to connect or download mobile app";
|
||||||
public static final String DEFAULT_GOOGLE_APP_STORE_LINK = "https://play.google.com/store/apps/details?id=org.thingsboard.demo.app";
|
|
||||||
public static final String DEFAULT_APPLE_APP_STORE_LINK = "https://apps.apple.com/us/app/thingsboard-live/id1594355695";
|
@Value("${mobileApp.googlePlayLink:https://play.google.com/store/apps/details?id=org.thingsboard.demo.app}")
|
||||||
|
private String googlePlayLink;
|
||||||
|
@Value("${mobileApp.appStoreLink:https://play.google.com/store/apps/details?id=org.thingsboard.demo.app}")
|
||||||
|
private String appStoreLink;
|
||||||
|
|
||||||
private final MobileAppSettingsDao mobileAppSettingsDao;
|
private final MobileAppSettingsDao mobileAppSettingsDao;
|
||||||
private final DataValidator<MobileAppSettings> mobileAppSettingsDataValidator;
|
private final DataValidator<MobileAppSettings> mobileAppSettingsDataValidator;
|
||||||
@ -52,7 +55,7 @@ public class BaseMobileAppSettingsService extends AbstractCachedEntityService<Te
|
|||||||
try {
|
try {
|
||||||
MobileAppSettings savedMobileAppSettings = mobileAppSettingsDao.save(tenantId, mobileAppSettings);
|
MobileAppSettings savedMobileAppSettings = mobileAppSettingsDao.save(tenantId, mobileAppSettings);
|
||||||
publishEvictEvent(new MobileAppSettingsEvictEvent(tenantId));
|
publishEvictEvent(new MobileAppSettingsEvictEvent(tenantId));
|
||||||
return savedMobileAppSettings;
|
return constructMobileAppSettings(savedMobileAppSettings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
handleEvictEvent(new MobileAppSettingsEvictEvent(tenantId));
|
handleEvictEvent(new MobileAppSettingsEvictEvent(tenantId));
|
||||||
checkConstraintViolation(e, Map.of(
|
checkConstraintViolation(e, Map.of(
|
||||||
@ -90,11 +93,9 @@ public class BaseMobileAppSettingsService extends AbstractCachedEntityService<Te
|
|||||||
|
|
||||||
AndroidConfig androidConfig = AndroidConfig.builder()
|
AndroidConfig androidConfig = AndroidConfig.builder()
|
||||||
.enabled(true)
|
.enabled(true)
|
||||||
.storeLink(DEFAULT_GOOGLE_APP_STORE_LINK)
|
|
||||||
.build();
|
.build();
|
||||||
IosConfig iosConfig = IosConfig.builder()
|
IosConfig iosConfig = IosConfig.builder()
|
||||||
.enabled(true)
|
.enabled(true)
|
||||||
.storeLink(DEFAULT_APPLE_APP_STORE_LINK)
|
|
||||||
.build();
|
.build();
|
||||||
QRCodeConfig qrCodeConfig = QRCodeConfig.builder()
|
QRCodeConfig qrCodeConfig = QRCodeConfig.builder()
|
||||||
.showOnHomePage(true)
|
.showOnHomePage(true)
|
||||||
@ -108,13 +109,10 @@ public class BaseMobileAppSettingsService extends AbstractCachedEntityService<Te
|
|||||||
mobileAppSettings.setQrCodeConfig(qrCodeConfig);
|
mobileAppSettings.setQrCodeConfig(qrCodeConfig);
|
||||||
mobileAppSettings.setAndroidConfig(androidConfig);
|
mobileAppSettings.setAndroidConfig(androidConfig);
|
||||||
mobileAppSettings.setIosConfig(iosConfig);
|
mobileAppSettings.setIosConfig(iosConfig);
|
||||||
} else {
|
}
|
||||||
if (StringUtils.isEmpty(mobileAppSettings.getAndroidConfig().getStoreLink())) {
|
if (mobileAppSettings.isUseDefaultApp()) {
|
||||||
mobileAppSettings.getAndroidConfig().setStoreLink(DEFAULT_GOOGLE_APP_STORE_LINK);
|
mobileAppSettings.setDefaultGooglePlayLink(googlePlayLink);
|
||||||
}
|
mobileAppSettings.setDefaultAppStoreLink(appStoreLink);
|
||||||
if (StringUtils.isEmpty(mobileAppSettings.getIosConfig().getStoreLink())) {
|
|
||||||
mobileAppSettings.getIosConfig().setStoreLink(DEFAULT_APPLE_APP_STORE_LINK);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return mobileAppSettings;
|
return mobileAppSettings;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user