## Description Implements backend APIs for Uploading and Deleting Navigation Logo Fixes #19164 ## Type of change - New feature (non-breaking change which adds functionality) ## How Has This Been Tested? - Manual - Postman - JUnit Tests ## Checklist: ### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test
This commit is contained in:
parent
44fa7dfbd5
commit
6531bd6aeb
|
|
@ -3,4 +3,5 @@ package com.appsmith.server.constants;
|
|||
public class Constraint {
|
||||
public static final int WORKSPACE_LOGO_SIZE_KB = 250;
|
||||
public static final int THUMBNAIL_PHOTO_DIMENSION = 128;
|
||||
public static final int MAX_LOGO_SIZE_KB = 1024;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
public Mono<ResponseDTO<ReleaseItemsDTO>> getReleaseItemsInformation() {
|
||||
log.debug("Going to get version release items");
|
||||
return applicationFetcher.getReleaseItems()
|
||||
.map(applications -> new ResponseDTO<>(HttpStatus.OK.value(), applications, null));
|
||||
.map(applications -> new ResponseDTO<>(HttpStatus.OK.value(), applications, null));
|
||||
}
|
||||
|
||||
@PutMapping("/{defaultApplicationId}/changeAccess")
|
||||
|
|
@ -222,11 +222,28 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
.map(result -> new ResponseDTO<>(HttpStatus.OK.value(), result, null));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/{defaultApplicationId}/logo", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public Mono<ResponseDTO<Application>> uploadAppNavigationLogo(@PathVariable String defaultApplicationId,
|
||||
@RequestPart("file") Mono<Part> fileMono,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
return fileMono
|
||||
.flatMap(part -> service.saveAppNavigationLogo(branchName, defaultApplicationId, part))
|
||||
.map(url -> new ResponseDTO<>(HttpStatus.OK.value(), url, null));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{defaultApplicationId}/logo")
|
||||
public Mono<ResponseDTO<Void>> deleteAppNavigationLogo(@PathVariable String defaultApplicationId,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName){
|
||||
return service.deleteAppNavigationLogo(branchName, defaultApplicationId)
|
||||
.map(ignored -> new ResponseDTO<>(HttpStatus.OK.value(), null, null));
|
||||
}
|
||||
|
||||
|
||||
// !! This API endpoint should not be exposed !!
|
||||
@Override
|
||||
@GetMapping("")
|
||||
public Mono<ResponseDTO<List<Application>>> getAll(@RequestParam MultiValueMap<String, String> params,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
return Mono.just(
|
||||
new ResponseDTO<>(HttpStatus.BAD_REQUEST.value(), null, AppsmithError.UNSUPPORTED_OPERATION.getMessage())
|
||||
);
|
||||
|
|
|
|||
|
|
@ -34,13 +34,14 @@ public class ApplicationServiceImpl extends ApplicationServiceCEImpl implements
|
|||
ResponseUtils responseUtils,
|
||||
PermissionGroupService permissionGroupService,
|
||||
TenantService tenantService,
|
||||
AssetService assetService,
|
||||
UserRepository userRepository,
|
||||
DatasourcePermission datasourcePermission,
|
||||
ApplicationPermission applicationPermission) {
|
||||
|
||||
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService, policyUtils,
|
||||
configService, commentThreadRepository, sessionUserService, responseUtils, permissionGroupService, tenantService, userRepository,
|
||||
datasourcePermission, applicationPermission);
|
||||
configService, commentThreadRepository, sessionUserService, responseUtils, permissionGroupService, tenantService, assetService,
|
||||
userRepository, datasourcePermission, applicationPermission);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.appsmith.server.dtos.ApplicationAccessDTO;
|
|||
import com.appsmith.server.dtos.GitAuthDTO;
|
||||
import com.appsmith.server.services.CrudService;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
|
@ -93,4 +94,9 @@ public interface ApplicationServiceCE extends CrudService<Application, String> {
|
|||
Mono<Application> getApplicationByDefaultApplicationIdAndDefaultBranch(String defaultApplicationId);
|
||||
|
||||
Mono<Application> findByIdAndExportWithConfiguration(String applicationId, Boolean exportWithConfiguration);
|
||||
|
||||
Mono<Application> saveAppNavigationLogo(String branchName, String applicationId, Part filePart);
|
||||
|
||||
public Mono<Void> deleteAppNavigationLogo(String branchName, String applicationId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.appsmith.server.domains.Action;
|
|||
import com.appsmith.server.domains.ActionCollection;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.ApplicationMode;
|
||||
import com.appsmith.server.domains.Asset;
|
||||
import com.appsmith.server.domains.GitApplicationMetadata;
|
||||
import com.appsmith.server.domains.GitAuth;
|
||||
import com.appsmith.server.domains.NewAction;
|
||||
|
|
@ -34,6 +35,7 @@ import com.appsmith.server.repositories.ApplicationRepository;
|
|||
import com.appsmith.server.repositories.CommentThreadRepository;
|
||||
import com.appsmith.server.repositories.UserRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.AssetService;
|
||||
import com.appsmith.server.services.BaseService;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.PermissionGroupService;
|
||||
|
|
@ -48,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
|
@ -64,8 +67,8 @@ import java.util.Set;
|
|||
|
||||
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
|
||||
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
|
||||
import static com.appsmith.server.constants.Constraint.MAX_LOGO_SIZE_KB;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
@Slf4j
|
||||
public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository, Application, String> implements ApplicationServiceCE {
|
||||
|
||||
|
|
@ -79,6 +82,8 @@ public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository,
|
|||
|
||||
private final TenantService tenantService;
|
||||
|
||||
private final AssetService assetService;
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final DatasourcePermission datasourcePermission;
|
||||
private final ApplicationPermission applicationPermission;
|
||||
|
|
@ -97,6 +102,7 @@ public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository,
|
|||
ResponseUtils responseUtils,
|
||||
PermissionGroupService permissionGroupService,
|
||||
TenantService tenantService,
|
||||
AssetService assetService,
|
||||
UserRepository userRepository,
|
||||
DatasourcePermission datasourcePermission,
|
||||
ApplicationPermission applicationPermission) {
|
||||
|
|
@ -109,6 +115,7 @@ public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository,
|
|||
this.responseUtils = responseUtils;
|
||||
this.permissionGroupService = permissionGroupService;
|
||||
this.tenantService = tenantService;
|
||||
this.assetService = assetService;
|
||||
this.userRepository = userRepository;
|
||||
this.datasourcePermission = datasourcePermission;
|
||||
this.applicationPermission = applicationPermission;
|
||||
|
|
@ -317,7 +324,9 @@ public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository,
|
|||
Application.NavigationSetting requestNavSetting = application.getUnpublishedNavigationSetting();
|
||||
if (requestNavSetting != null) {
|
||||
Application.NavigationSetting presetNavSetting = ObjectUtils.defaultIfNull(branchedApplication.getUnpublishedNavigationSetting(), new Application.NavigationSetting());
|
||||
requestNavSetting.setLogoAssetId(ObjectUtils.defaultIfNull(presetNavSetting.getLogoAssetId(), ""));
|
||||
String presetLogoAssetId = ObjectUtils.defaultIfNull(presetNavSetting.getLogoAssetId(), "");
|
||||
String requestLogoAssetId = ObjectUtils.defaultIfNull(requestNavSetting.getLogoAssetId(), null);
|
||||
requestNavSetting.setLogoAssetId(ObjectUtils.defaultIfNull(requestLogoAssetId, presetLogoAssetId));
|
||||
application.setUnpublishedNavigationSetting(requestNavSetting);
|
||||
}
|
||||
return this.update(branchedApplication.getId(), application);
|
||||
|
|
@ -772,4 +781,64 @@ public class ApplicationServiceCEImpl extends BaseService<ApplicationRepository,
|
|||
public Mono<Application> findByIdAndExportWithConfiguration(String applicationId, Boolean exportWithConfiguration) {
|
||||
return repository.findByIdAndExportWithConfiguration(applicationId, exportWithConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Application> saveAppNavigationLogo(String branchName, String applicationId, Part filePart) {
|
||||
return this.findByBranchNameAndDefaultApplicationId(branchName, applicationId, applicationPermission.getEditPermission())
|
||||
.flatMap(branchedApplication -> {
|
||||
|
||||
Application.NavigationSetting rootAppUnpublishedNavigationSetting = ObjectUtils.defaultIfNull(
|
||||
branchedApplication.getUnpublishedNavigationSetting(),
|
||||
new Application.NavigationSetting()
|
||||
);
|
||||
|
||||
String rootAppLogoAssetId = ObjectUtils.defaultIfNull(
|
||||
rootAppUnpublishedNavigationSetting.getLogoAssetId(),
|
||||
""
|
||||
);
|
||||
|
||||
final Mono<String> prevAssetIdMono = Mono.just(rootAppLogoAssetId);
|
||||
|
||||
final Mono<Asset> uploaderMono = assetService.upload(List.of(filePart), MAX_LOGO_SIZE_KB, true);
|
||||
|
||||
return Mono.zip(prevAssetIdMono, uploaderMono)
|
||||
.flatMap(tuple -> {
|
||||
final String oldAssetId = tuple.getT1();
|
||||
final Asset uploadedAsset = tuple.getT2();
|
||||
Application.NavigationSetting navSetting = ObjectUtils.defaultIfNull(
|
||||
branchedApplication.getUnpublishedNavigationSetting(),
|
||||
new Application.NavigationSetting());
|
||||
navSetting.setLogoAssetId(uploadedAsset.getId());
|
||||
branchedApplication.setUnpublishedNavigationSetting(navSetting);
|
||||
|
||||
final Mono<Application> updateMono = this.update(applicationId, branchedApplication, branchName);
|
||||
|
||||
if (!StringUtils.hasLength(oldAssetId)){
|
||||
return updateMono;
|
||||
} else {
|
||||
return assetService.remove(oldAssetId).then(updateMono);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteAppNavigationLogo(String branchName, String applicationId){
|
||||
return this.findByBranchNameAndDefaultApplicationId(branchName, applicationId, applicationPermission.getEditPermission())
|
||||
.flatMap(branchedApplication -> {
|
||||
|
||||
Application.NavigationSetting unpublishedNavSetting = ObjectUtils.defaultIfNull(branchedApplication.getUnpublishedNavigationSetting(), new Application.NavigationSetting());
|
||||
|
||||
String navLogoAssetId = ObjectUtils.defaultIfNull(unpublishedNavSetting.getLogoAssetId(), "");
|
||||
|
||||
unpublishedNavSetting.setLogoAssetId(null);
|
||||
branchedApplication.setUnpublishedNavigationSetting(unpublishedNavSetting);
|
||||
return repository.save(branchedApplication).thenReturn(navLogoAssetId);
|
||||
})
|
||||
.flatMap(assetService::remove);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2199,6 +2199,218 @@ public class GitServiceTest {
|
|||
.verifyComplete();
|
||||
}
|
||||
|
||||
private void mockitoSetUp(GitBranchDTO createGitBranchDTO) throws GitAPIException, IOException{
|
||||
Mockito.when(gitExecutor.checkoutToBranch(Mockito.any(Path.class), Mockito.anyString()))
|
||||
.thenReturn(Mono.just(true));
|
||||
Mockito.when(gitExecutor.fetchRemote(Mockito.any(Path.class), Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyString(), Mockito.anyBoolean()))
|
||||
.thenReturn(Mono.just("fetchResult"));
|
||||
Mockito.when(gitExecutor.listBranches(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(new ArrayList<>()));
|
||||
Mockito.when(gitExecutor.createAndCheckoutToBranch(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(createGitBranchDTO.getBranchName()));
|
||||
Mockito.when(gitFileUtils.saveApplicationToLocalRepo(Mockito.any(Path.class), Mockito.any(ApplicationJson.class), Mockito.anyString()))
|
||||
.thenReturn(Mono.just(Paths.get("")));
|
||||
Mockito.when(gitExecutor.commitApplication(Mockito.any(Path.class), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyBoolean()))
|
||||
.thenReturn(Mono.just("System generated commit"));
|
||||
Mockito.when(gitExecutor.checkoutToBranch(Mockito.any(Path.class), Mockito.anyString()))
|
||||
.thenReturn(Mono.just(true));
|
||||
Mockito.when(gitExecutor.pushApplication(Mockito.any(Path.class), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
|
||||
.thenReturn(Mono.just("pushed successfully"));
|
||||
|
||||
Mockito.when(gitExecutor.cloneApplication(Mockito.any(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
|
||||
.thenReturn(Mono.just(DEFAULT_BRANCH));
|
||||
Mockito.when(gitFileUtils.checkIfDirectoryIsEmpty(Mockito.any(Path.class))).thenReturn(Mono.just(true));
|
||||
Mockito.when(gitFileUtils.initializeReadme(Mockito.any(Path.class), Mockito.anyString(), Mockito.anyString()))
|
||||
.thenReturn(Mono.just(Paths.get("textPath")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void createBranch_BranchHasCustomNavigationSettings_SrcBranchRemainsUnchanged() throws GitAPIException, IOException {
|
||||
GitBranchDTO createGitBranchDTO = new GitBranchDTO();
|
||||
createGitBranchDTO.setBranchName("valid_branch");
|
||||
|
||||
GitConnectDTO gitConnectDTO = getConnectRequest("git@github.com:test/testRepo.git", testUserProfile);
|
||||
mockitoSetUp(createGitBranchDTO);
|
||||
|
||||
Application testApplication = new Application();
|
||||
GitApplicationMetadata gitApplicationMetadata = new GitApplicationMetadata();
|
||||
GitAuth gitAuth = new GitAuth();
|
||||
gitAuth.setPublicKey("testkey");
|
||||
gitAuth.setPrivateKey("privatekey");
|
||||
gitApplicationMetadata.setGitAuth(gitAuth);
|
||||
testApplication.setGitApplicationMetadata(gitApplicationMetadata);
|
||||
testApplication.setName("Test App" + UUID.randomUUID().toString());
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
|
||||
Mono<Tuple2<Application, Application>> createBranchMono = applicationPageService.createApplication(testApplication)
|
||||
.flatMap(application -> gitService.connectApplicationToGit(application.getId(), gitConnectDTO, "origin"))
|
||||
.flatMap(application -> gitService.createBranch(
|
||||
application.getId(), createGitBranchDTO, application.getGitApplicationMetadata().getBranchName())
|
||||
.then(applicationService.findByBranchNameAndDefaultApplicationId(
|
||||
createGitBranchDTO.getBranchName(),
|
||||
application.getId(),
|
||||
READ_APPLICATIONS
|
||||
))
|
||||
|
||||
|
||||
)
|
||||
.flatMap(branchedApplication -> {
|
||||
|
||||
Application.NavigationSetting appNavigationSetting = new Application.NavigationSetting();
|
||||
appNavigationSetting.setOrientation("top");
|
||||
branchedApplication.setNavigationSetting(appNavigationSetting);
|
||||
return Mono.just(branchedApplication);
|
||||
})
|
||||
.flatMap(branchedApplication->
|
||||
applicationService.update(
|
||||
branchedApplication.getGitApplicationMetadata().getDefaultApplicationId(),
|
||||
branchedApplication, branchedApplication.getGitApplicationMetadata().getBranchName()
|
||||
)
|
||||
)
|
||||
.zipWhen(application ->
|
||||
applicationService.findById(application.getGitApplicationMetadata().getDefaultApplicationId())
|
||||
);
|
||||
|
||||
StepVerifier
|
||||
.create(createBranchMono)
|
||||
.assertNext(tuple -> {
|
||||
Application branchedApp = tuple.getT1();
|
||||
Application srcApp = tuple.getT2();
|
||||
assertThat(branchedApp.getUnpublishedNavigationSetting().getOrientation()).isEqualTo("top");
|
||||
assertThat(srcApp.getUnpublishedNavigationSetting()).isNull();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
private FilePart createMockFilePart() {
|
||||
FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
Flux<DataBuffer> dataBufferFlux = DataBufferUtils
|
||||
.read(new ClassPathResource("test_assets/WorkspaceServiceTest/my_workspace_logo.png"), new DefaultDataBufferFactory(), 4096).cache();
|
||||
Mockito.when(filepart.content()).thenReturn(dataBufferFlux);
|
||||
Mockito.when(filepart.headers().getContentType()).thenReturn(MediaType.IMAGE_PNG);
|
||||
return filepart;
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void createBranch_BranchUploadLogo_SrcBranchRemainsUnchanged() throws GitAPIException, IOException {
|
||||
GitBranchDTO createGitBranchDTO = new GitBranchDTO();
|
||||
createGitBranchDTO.setBranchName("valid_branch");
|
||||
|
||||
GitConnectDTO gitConnectDTO = getConnectRequest("git@github.com:test/testRepo.git", testUserProfile);
|
||||
mockitoSetUp(createGitBranchDTO);
|
||||
|
||||
Application testApplication = new Application();
|
||||
GitApplicationMetadata gitApplicationMetadata = new GitApplicationMetadata();
|
||||
GitAuth gitAuth = new GitAuth();
|
||||
gitAuth.setPublicKey("testkey");
|
||||
gitAuth.setPrivateKey("privatekey");
|
||||
gitApplicationMetadata.setGitAuth(gitAuth);
|
||||
testApplication.setGitApplicationMetadata(gitApplicationMetadata);
|
||||
testApplication.setName("Test App" + UUID.randomUUID().toString());
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
|
||||
Mono<Tuple2<Application, Application>> createBranchMono = applicationPageService.createApplication(testApplication)
|
||||
.flatMap(application -> gitService.connectApplicationToGit(application.getId(), gitConnectDTO, "origin"))
|
||||
.flatMap(application -> gitService.createBranch(
|
||||
application.getId(), createGitBranchDTO, application.getGitApplicationMetadata().getBranchName())
|
||||
.then(applicationService.findByBranchNameAndDefaultApplicationId(
|
||||
createGitBranchDTO.getBranchName(),
|
||||
application.getId(),
|
||||
READ_APPLICATIONS
|
||||
))
|
||||
)
|
||||
.flatMap(branchedApplication -> {
|
||||
|
||||
FilePart filepart = createMockFilePart();
|
||||
return applicationService.saveAppNavigationLogo(branchedApplication.getGitApplicationMetadata().getBranchName(), branchedApplication.getGitApplicationMetadata().getDefaultApplicationId(), filepart).cache();
|
||||
|
||||
})
|
||||
.zipWhen(application ->
|
||||
applicationService.findById(application.getGitApplicationMetadata().getDefaultApplicationId())
|
||||
);
|
||||
|
||||
StepVerifier
|
||||
.create(createBranchMono)
|
||||
.assertNext(tuple -> {
|
||||
Application branchedApp = tuple.getT1();
|
||||
Application srcApp = tuple.getT2();
|
||||
assertThat(branchedApp.getUnpublishedNavigationSetting()).isNotNull();
|
||||
assertThat(branchedApp.getUnpublishedNavigationSetting().getLogoAssetId()).isNotNull();
|
||||
assertThat(srcApp.getUnpublishedNavigationSetting()).isNull();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void createBranch_BranchDeleteLogo_SrcLogoRemainsUnchanged() throws GitAPIException, IOException {
|
||||
GitBranchDTO createGitBranchDTO = new GitBranchDTO();
|
||||
createGitBranchDTO.setBranchName("valid_branch");
|
||||
|
||||
GitConnectDTO gitConnectDTO = getConnectRequest("git@github.com:test/testRepo.git", testUserProfile);
|
||||
mockitoSetUp(createGitBranchDTO);
|
||||
|
||||
Application testApplication = new Application();
|
||||
GitApplicationMetadata gitApplicationMetadata = new GitApplicationMetadata();
|
||||
GitAuth gitAuth = new GitAuth();
|
||||
gitAuth.setPublicKey("testkey");
|
||||
gitAuth.setPrivateKey("privatekey");
|
||||
gitApplicationMetadata.setGitAuth(gitAuth);
|
||||
testApplication.setGitApplicationMetadata(gitApplicationMetadata);
|
||||
testApplication.setName("Test App" + UUID.randomUUID().toString());
|
||||
testApplication.setWorkspaceId(workspaceId);
|
||||
|
||||
Mono<Tuple2<Application, Application>> createBranchMono = applicationPageService.createApplication(testApplication)
|
||||
.flatMap(application -> gitService.connectApplicationToGit(application.getId(), gitConnectDTO, "origin"))
|
||||
.flatMap(application ->
|
||||
Mono.zip(gitService
|
||||
.createBranch(application.getId(), createGitBranchDTO, application.getGitApplicationMetadata().getBranchName())
|
||||
.then(applicationService.findByBranchNameAndDefaultApplicationId(createGitBranchDTO.getBranchName(), application.getId(), READ_APPLICATIONS)),
|
||||
Mono.just(application))
|
||||
|
||||
)
|
||||
.flatMap(applicationTuple->{
|
||||
Application branchedApplication = applicationTuple.getT1();
|
||||
Application application = applicationTuple.getT2();
|
||||
String srcBranchName = application.getGitApplicationMetadata().getBranchName();
|
||||
String otherBranchName = branchedApplication.getGitApplicationMetadata().getBranchName();
|
||||
String defaultApplicationId = branchedApplication.getGitApplicationMetadata().getDefaultApplicationId();
|
||||
|
||||
FilePart filepart = createMockFilePart();
|
||||
return Mono.zip(
|
||||
applicationService.saveAppNavigationLogo(otherBranchName, defaultApplicationId, filepart).cache(),
|
||||
applicationService.saveAppNavigationLogo(srcBranchName, defaultApplicationId, filepart).cache()
|
||||
);
|
||||
})
|
||||
.flatMap(appTuple->{
|
||||
Application branchedApplication = appTuple.getT1();
|
||||
Application application = appTuple.getT2();
|
||||
|
||||
return applicationService.deleteAppNavigationLogo(branchedApplication.getGitApplicationMetadata().getBranchName(), branchedApplication.getGitApplicationMetadata().getDefaultApplicationId())
|
||||
.then(applicationService.findByIdAndBranchName(branchedApplication.getGitApplicationMetadata().getDefaultApplicationId(), branchedApplication.getGitApplicationMetadata().getBranchName()));
|
||||
})
|
||||
.zipWhen(application ->
|
||||
applicationService.findById(application.getGitApplicationMetadata().getDefaultApplicationId())
|
||||
);
|
||||
|
||||
StepVerifier
|
||||
.create(createBranchMono)
|
||||
.assertNext(tuple -> {
|
||||
Application branchedApp = tuple.getT1();
|
||||
Application srcApp = tuple.getT2();
|
||||
assertThat(branchedApp.getUnpublishedNavigationSetting()).isNotNull();
|
||||
assertThat(branchedApp.getUnpublishedNavigationSetting().getLogoAssetId()).isNull();
|
||||
assertThat(srcApp.getUnpublishedNavigationSetting()).isNotNull();
|
||||
assertThat(srcApp.getUnpublishedNavigationSetting().getLogoAssetId()).isNotNull();
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void connectApplicationToGit_cancelledMidway_cloneSuccess() throws IOException {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.appsmith.server.constants.FieldName;
|
|||
import com.appsmith.server.domains.ActionCollection;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.ApplicationPage;
|
||||
import com.appsmith.server.domains.Asset;
|
||||
import com.appsmith.server.domains.GitApplicationMetadata;
|
||||
import com.appsmith.server.domains.GitAuth;
|
||||
import com.appsmith.server.domains.Layout;
|
||||
|
|
@ -40,6 +41,7 @@ import com.appsmith.server.helpers.PolicyUtils;
|
|||
import com.appsmith.server.helpers.TextUtils;
|
||||
import com.appsmith.server.migrations.ApplicationVersion;
|
||||
import com.appsmith.server.repositories.ApplicationRepository;
|
||||
import com.appsmith.server.repositories.AssetRepository;
|
||||
import com.appsmith.server.repositories.NewPageRepository;
|
||||
import com.appsmith.server.repositories.PermissionGroupRepository;
|
||||
import com.appsmith.server.repositories.PluginRepository;
|
||||
|
|
@ -73,9 +75,15 @@ import org.mockito.Mockito;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.multipart.FilePart;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
|
@ -211,6 +219,9 @@ public class ApplicationServiceCETest {
|
|||
@Autowired
|
||||
SessionUserService sessionUserService;
|
||||
|
||||
@Autowired
|
||||
private AssetRepository assetRepository;
|
||||
|
||||
String workspaceId;
|
||||
|
||||
static Plugin testPlugin = new Plugin();
|
||||
|
|
@ -3403,4 +3414,100 @@ public class ApplicationServiceCETest {
|
|||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
private FilePart createMockFilePart() {
|
||||
FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
Flux<DataBuffer> dataBufferFlux = DataBufferUtils
|
||||
.read(new ClassPathResource("test_assets/WorkspaceServiceTest/my_workspace_logo.png"), new DefaultDataBufferFactory(), 4096).cache();
|
||||
Mockito.when(filepart.content()).thenReturn(dataBufferFlux);
|
||||
Mockito.when(filepart.headers().getContentType()).thenReturn(MediaType.IMAGE_PNG);
|
||||
return filepart;
|
||||
}
|
||||
|
||||
private String createTestApplication(String applicationName){
|
||||
Application testApplication = new Application();
|
||||
testApplication.setName(applicationName);
|
||||
Application application = applicationPageService.createApplication(testApplication, workspaceId).block();
|
||||
return application.getId();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void testUploadAndDeleteNavigationLogo_validImage() {
|
||||
FilePart filepart = createMockFilePart();
|
||||
String createdApplicationId = createTestApplication("ApplicationServiceTest Upload/Delete Nav Logo");
|
||||
|
||||
final Mono<Application> saveMono = applicationService.saveAppNavigationLogo(null, createdApplicationId, filepart).cache();
|
||||
|
||||
Mono<Tuple2<Application, Asset>> loadLogoImageMono = applicationService.findById(createdApplicationId)
|
||||
.flatMap(fetchedApplication -> {
|
||||
Mono<Application> fetchedApplicationMono = Mono.just(fetchedApplication);
|
||||
if (StringUtils.isEmpty(fetchedApplication.getUnpublishedNavigationSetting().getLogoAssetId())) {
|
||||
return fetchedApplicationMono.zipWith(Mono.just(new Asset()));
|
||||
} else {
|
||||
return fetchedApplicationMono.zipWith(assetRepository.findById(fetchedApplication.getUnpublishedNavigationSetting().getLogoAssetId()));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
final Mono<Tuple2<Application, Asset>> saveAndGetMono = saveMono.then(loadLogoImageMono);
|
||||
final Mono<Tuple2<Application, Asset>> deleteAndGetMono = saveMono.then(applicationService.deleteAppNavigationLogo(null, createdApplicationId)).then(loadLogoImageMono);
|
||||
|
||||
StepVerifier.create(saveAndGetMono)
|
||||
.assertNext(tuple -> {
|
||||
final Application application1 = tuple.getT1();
|
||||
assertThat(application1.getUnpublishedNavigationSetting().getLogoAssetId()).isNotNull();
|
||||
|
||||
final Asset asset = tuple.getT2();
|
||||
assertThat(asset).isNotNull();
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(deleteAndGetMono)
|
||||
.assertNext(objects -> {
|
||||
assertThat(objects.getT1().getUnpublishedNavigationSetting().getLogoAssetId()).isNull();
|
||||
assertThat(objects.getT2().getId()).isNull();
|
||||
})
|
||||
// Should be empty since the profile photo has been deleted.
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void testUploadNavigationLogo_invalidImageFormat(){
|
||||
FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
Flux<DataBuffer> dataBufferFlux = DataBufferUtils
|
||||
.read(new ClassPathResource("test_assets/WorkspaceServiceTest/my_workspace_logo.png"), new DefaultDataBufferFactory(), 4096)
|
||||
.cache();
|
||||
|
||||
Mockito.when(filepart.content()).thenReturn(dataBufferFlux);
|
||||
Mockito.when(filepart.headers().getContentType()).thenReturn(MediaType.IMAGE_GIF);
|
||||
|
||||
String createdApplicationId = createTestApplication("ApplicationServiceTest Upload Invalid Nav Logo");
|
||||
|
||||
final Mono<Application> saveMono = applicationService.saveAppNavigationLogo(null, createdApplicationId, filepart).cache();
|
||||
StepVerifier.create(saveMono)
|
||||
.expectErrorMatches(error -> error instanceof AppsmithException)
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void testUploadNavigationLogo_invalidImageSize(){
|
||||
FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);
|
||||
Flux<DataBuffer> dataBufferFlux = DataBufferUtils
|
||||
.read(new ClassPathResource("test_assets/WorkspaceServiceTest/my_workspace_logo_large.png"), new DefaultDataBufferFactory(), 4096)
|
||||
.repeat(100) // So the file size looks like it's much larger than what it actually is.
|
||||
.cache();
|
||||
|
||||
Mockito.when(filepart.content()).thenReturn(dataBufferFlux);
|
||||
Mockito.when(filepart.headers().getContentType()).thenReturn(MediaType.IMAGE_PNG);
|
||||
|
||||
String createdApplicationId = createTestApplication("ApplicationServiceTest Upload Invalid Nav Logo Size");
|
||||
|
||||
final Mono<Application> saveMono = applicationService.saveAppNavigationLogo(null, createdApplicationId, filepart).cache();
|
||||
StepVerifier.create(saveMono)
|
||||
.expectErrorMatches(error -> error instanceof AppsmithException)
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3588,4 +3588,30 @@ public class ImportExportApplicationServiceTests {
|
|||
assertThat(fields.getBearerTokenAuth().getBearerToken()).isEqualTo("token_" + randomUUID);
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void exportApplicationTest_WithNavigationSettings() {
|
||||
|
||||
Application application = new Application();
|
||||
application.setName("exportNavigationSettingsApplicationTest");
|
||||
Application.NavigationSetting navSetting = new Application.NavigationSetting();
|
||||
navSetting.setOrientation("top");
|
||||
application.setUnpublishedNavigationSetting(navSetting);
|
||||
Application createdApplication = applicationPageService.createApplication(application, workspaceId).block();
|
||||
|
||||
Mono<ApplicationJson> resultMono =
|
||||
importExportApplicationService.exportApplicationById(createdApplication.getId(), "");
|
||||
|
||||
StepVerifier
|
||||
.create(resultMono)
|
||||
.assertNext(applicationJson -> {
|
||||
Application exportedApplication = applicationJson.getExportedApplication();
|
||||
assertThat(exportedApplication).isNotNull();
|
||||
assertThat(exportedApplication.getUnpublishedNavigationSetting()).isNotNull();
|
||||
assertThat(exportedApplication.getUnpublishedNavigationSetting().getOrientation()).isEqualTo("top");
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user