Merge branch 'feature/mobile-app-bundle' of github.com:thingsboard/thingsboard into feature/mobile-app-bundle
This commit is contained in:
		
						commit
						01806027b6
					
				@ -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;
 | 
			
		||||
$$;
 | 
			
		||||
 | 
			
		||||
@ -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<MobilePage> getVisiblePages(MobileAppBundle mobileAppBundle) throws JsonProcessingException {
 | 
			
		||||
    private JsonNode getVisiblePages(MobileAppBundle mobileAppBundle) throws JsonProcessingException {
 | 
			
		||||
        if (mobileAppBundle != null && mobileAppBundle.getLayoutConfig() != null) {
 | 
			
		||||
            List<MobilePage> 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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -31,17 +31,16 @@ public interface MobileAppBundleService extends EntityDaoService {
 | 
			
		||||
 | 
			
		||||
    MobileAppBundle saveMobileAppBundle(TenantId tenantId, MobileAppBundle mobileAppBundle);
 | 
			
		||||
 | 
			
		||||
    void updateOauth2Clients(TenantId tenantId, MobileAppBundleId mobileAppBundleId, List<OAuth2ClientId> oAuth2ClientIds);
 | 
			
		||||
 | 
			
		||||
    MobileAppBundle findMobileAppBundleById(TenantId tenantId, MobileAppBundleId mobileAppBundleId);
 | 
			
		||||
 | 
			
		||||
    PageData<MobileAppBundleInfo> findMobileAppBundleInfosByTenantId(TenantId tenantId, PageLink pageLink);
 | 
			
		||||
 | 
			
		||||
    MobileAppBundleInfo findMobileAppBundleInfoById(TenantId tenantId, MobileAppBundleId mobileAppBundleId);
 | 
			
		||||
 | 
			
		||||
    void updateOauth2Clients(TenantId tenantId, MobileAppBundleId mobileAppBundleId, List<OAuth2ClientId> oAuth2ClientIds);
 | 
			
		||||
 | 
			
		||||
    MobileAppBundle findMobileAppBundleByPkgNameAndPlatform(TenantId tenantId, String pkgName, PlatformType platform);
 | 
			
		||||
 | 
			
		||||
    void deleteMobileAppBundleById(TenantId tenantId, MobileAppBundleId mobileAppBundleId);
 | 
			
		||||
 | 
			
		||||
    void deleteMobileAppBundlesByTenantId(TenantId tenantId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,4 @@ public interface MobileAppService extends EntityDaoService {
 | 
			
		||||
 | 
			
		||||
    void deleteMobileAppById(TenantId tenantId, MobileAppId mobileAppId);
 | 
			
		||||
 | 
			
		||||
    void deleteMobileAppsByTenantId(TenantId tenantId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<MobilePage> pages) {
 | 
			
		||||
public record UserMobileInfo(User user, HomeDashboardInfo homeDashboardInfo, JsonNode pages) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<OAuth2ClientId> oAuth2ClientIds) {
 | 
			
		||||
        log.trace("Executing updateOauth2Clients, mobileAppId [{}], oAuth2ClientIds [{}]", mobileAppBundleId, oAuth2ClientIds);
 | 
			
		||||
        Set<MobileAppBundleOauth2Client> newClientList = oAuth2ClientIds.stream()
 | 
			
		||||
                .map(clientId -> new MobileAppBundleOauth2Client(mobileAppBundleId, clientId))
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
 | 
			
		||||
        List<MobileAppBundleOauth2Client> existingClients = mobileAppBundleDao.findOauth2ClientsByMobileAppBundleId(tenantId, mobileAppBundleId);
 | 
			
		||||
        List<MobileAppBundleOauth2Client> 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<OAuth2ClientId> oAuth2ClientIds) {
 | 
			
		||||
        log.trace("Executing updateOauth2Clients, mobileAppId [{}], oAuth2ClientIds [{}]", mobileAppBundleId, oAuth2ClientIds);
 | 
			
		||||
        Set<MobileAppBundleOauth2Client> newClientList = oAuth2ClientIds.stream()
 | 
			
		||||
                .map(clientId -> new MobileAppBundleOauth2Client(mobileAppBundleId, clientId))
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
 | 
			
		||||
        List<MobileAppBundleOauth2Client> existingClients = mobileAppBundleDao.findOauth2ClientsByMobileAppBundleId(tenantId, mobileAppBundleId);
 | 
			
		||||
        List<MobileAppBundleOauth2Client> 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<HasId<?>> 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;
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -51,9 +51,9 @@ public final class MobileAppBundleOauth2ClientEntity implements ToData<MobileApp
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public MobileAppBundleOauth2ClientEntity(MobileAppBundleOauth2Client domainOauth2Provider) {
 | 
			
		||||
        mobileAppBundleId = domainOauth2Provider.getMobileAppBundleId().getId();
 | 
			
		||||
        oauth2ClientId = domainOauth2Provider.getOAuth2ClientId().getId();
 | 
			
		||||
    public MobileAppBundleOauth2ClientEntity(MobileAppBundleOauth2Client mobileAppBundleOauth2Client) {
 | 
			
		||||
        mobileAppBundleId = mobileAppBundleOauth2Client.getMobileAppBundleId().getId();
 | 
			
		||||
        oauth2ClientId = mobileAppBundleOauth2Client.getOAuth2ClientId().getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,8 @@ import org.springframework.stereotype.Component;
 | 
			
		||||
import org.thingsboard.server.common.data.id.MobileAppBundleId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.mobile.app.MobileApp;
 | 
			
		||||
import org.thingsboard.server.common.data.mobile.qrCodeSettings.QRCodeConfig;
 | 
			
		||||
import org.thingsboard.server.common.data.mobile.app.MobileAppStatus;
 | 
			
		||||
import org.thingsboard.server.common.data.mobile.qrCodeSettings.QrCodeSettings;
 | 
			
		||||
import org.thingsboard.server.common.data.mobile.app.StoreInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.oauth2.PlatformType;
 | 
			
		||||
import org.thingsboard.server.dao.exception.DataValidationException;
 | 
			
		||||
import org.thingsboard.server.dao.mobile.MobileAppDao;
 | 
			
		||||
@ -45,13 +44,13 @@ public class QrCodeSettingsDataValidator extends DataValidator<QrCodeSettings> {
 | 
			
		||||
        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!");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user