Skip to content

Commit c557b84

Browse files
committed
Merge branch 'release/7.3' into ENG-5473
2 parents 5baf728 + a723240 commit c557b84

File tree

23 files changed

+551
-91
lines changed

23 files changed

+551
-91
lines changed

cds-plugin/src/main/java/org/entando/entando/plugins/jpcds/aps/system/storage/CdsStorageManager.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,30 @@ public boolean exists(String subPath, boolean isProtectedResource) {
201201
return (null != filenames && isSubPathPresent(filenames,subPathParsed.getFileName()));
202202
}
203203

204+
@Override
205+
public boolean move(String subPathSource, boolean isProtectedResourceSource, String subPathDest, boolean isProtectedResourceDest) throws EntException {
206+
if (!this.exists(subPathSource, isProtectedResourceSource)) {
207+
log.error(String.format(
208+
"Source File does not exists - path '%s' protected '%s'",
209+
subPathSource, isProtectedResourceSource));
210+
return false;
211+
}
212+
if (this.exists(subPathDest, isProtectedResourceDest)) {
213+
log.error(String.format(
214+
"Destination already exists - path '%s' protected '%s'",
215+
subPathDest, isProtectedResourceDest));
216+
return false;
217+
}
218+
try {
219+
InputStream stream = this.getStream(subPathSource, isProtectedResourceSource);
220+
this.saveFile(subPathDest, isProtectedResourceDest, stream);
221+
this.deleteFile(subPathSource, isProtectedResourceSource);
222+
} catch (Exception e) {
223+
throw new EntException("Error moving file", e);
224+
}
225+
return true;
226+
}
227+
204228
// when frontend wants to retrieve public or protected folder contents it gets request with an empty subpath
205229
private boolean isSubPathPresent(String[] filenames, String subPath){
206230
if (StringUtils.isEmpty(subPath)) {

cds-plugin/src/test/java/org/entando/entando/plugins/jpcds/aps/system/storage/CdsStorageManagerTest.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,74 @@ void shouldEditFile() throws Exception {
582582
eq(false));
583583

584584
}
585-
585+
586+
@Test
587+
void shouldMoveFile() throws Exception {
588+
this.initTenantForMovement();
589+
this.setExistingFileForMovement("source_file.txt", false, "test", false);
590+
this.setExistingFileForMovement("dest_file.txt", true, "test_dest", true);
591+
CdsCreateResponseDto ret = new CdsCreateResponseDto();
592+
ret.setStatusOk(true);
593+
Mockito.when(cdsRemoteCaller.executePostCall(any(),
594+
eq("test_dest/dest_file.txt"),
595+
eq(true),
596+
any(),
597+
any(),
598+
eq(false))).thenReturn(ret);
599+
boolean result = this.cdsStorageManager.move("test/source_file.txt", false, "test_dest/dest_file.txt", true);
600+
Assertions.assertThat(result).isTrue();
601+
Mockito.verify(this.cdsRemoteCaller, Mockito.times(3)).getFileAttributeView(Mockito.any(URI.class), Mockito.any());
602+
Mockito.verify(this.cdsRemoteCaller, Mockito.times(1)).getFile(Mockito.any(URI.class), Mockito.any(), Mockito.anyBoolean());
603+
}
604+
605+
@Test
606+
void shouldFailMovementDueMissingSource() throws Exception {
607+
this.initTenantForMovement();
608+
boolean result = this.cdsStorageManager.move("test/source_file.txt", false, "test_dest/dest_file.txt", false);
609+
Assertions.assertThat(result).isFalse();
610+
Mockito.verify(this.cdsRemoteCaller, Mockito.times(1)).getFileAttributeView(Mockito.any(URI.class), Mockito.any());
611+
Mockito.verify(this.cdsRemoteCaller, Mockito.times(0)).getFile(Mockito.any(URI.class), Mockito.any(), Mockito.anyBoolean());
612+
}
613+
614+
@Test
615+
void shouldFailMovementDueExistingDestination() throws Exception {
616+
this.initTenantForMovement();
617+
this.setExistingFileForMovement("source_file.txt", false, "test", false);
618+
this.setExistingFileForMovement("dest_file.txt", true, "test_dest", false);
619+
boolean result = this.cdsStorageManager.move("test/source_file.txt", false, "test_dest/dest_file.txt", true);
620+
Assertions.assertThat(result).isFalse();
621+
Mockito.verify(this.cdsRemoteCaller, Mockito.times(2)).getFileAttributeView(Mockito.any(URI.class), Mockito.any());
622+
Mockito.verify(this.cdsRemoteCaller, Mockito.times(0)).getFile(Mockito.any(URI.class), Mockito.any(), Mockito.anyBoolean());
623+
}
624+
625+
private void initTenantForMovement() {
626+
Map<String,String> configMap = Map.of("cdsPublicUrl","http://my-server/tenant1/cms-resources",
627+
"cdsPrivateUrl","http://cds-kube-service:8081/",
628+
"cdsPath","/mytenant/api/v1/");
629+
TenantConfig tc = new TenantConfig(configMap);
630+
Mockito.when(tenantManager.getConfig("my-tenant")).thenReturn(Optional.ofNullable(tc));
631+
ApsTenantApplicationUtils.setTenant("my-tenant");
632+
}
633+
634+
private void setExistingFileForMovement(String existingFileName, boolean isProtected, String path, boolean returnEmpty) {
635+
String subPath = ((isProtected) ? "protected/" : "") + path;
636+
if (returnEmpty) {
637+
Mockito.when(cdsRemoteCaller.getFileAttributeView(eq(URI.create(
638+
"http://cds-kube-service:8081/mytenant/api/v1/list/" + subPath)),
639+
any())).thenReturn(Optional.empty());
640+
return;
641+
}
642+
CdsFileAttributeViewDto file = new CdsFileAttributeViewDto();
643+
file.setName(existingFileName);
644+
file.setDirectory(false);
645+
CdsFileAttributeViewDto dir = new CdsFileAttributeViewDto();
646+
dir.setName("test-folder");
647+
dir.setDirectory(true);
648+
Mockito.when(cdsRemoteCaller.getFileAttributeView(eq(URI.create(
649+
"http://cds-kube-service:8081/mytenant/api/v1/list/" + subPath)),
650+
any())).thenReturn(Optional.ofNullable(new CdsFileAttributeViewDto[]{file, dir}));
651+
}
652+
586653
//@Test
587654
void testListAttributes() throws Throwable {
588655
Map<String,String> configMap = Map.of("cdsPublicUrl","http://my-server/tenant1/cms-resources",

cms-plugin/src/main/java/com/agiletec/plugins/jacms/aps/system/services/resource/ResourceManager.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -262,29 +262,27 @@ protected void generateAndSetResourceId(ResourceInterface resource, String id) t
262262
resource.setId(String.valueOf(newId));
263263
}
264264
}
265-
265+
266266
@Override
267267
public void updateResource(ResourceDataBean bean) throws EntException {
268-
ResourceInterface oldResource = this.loadResource(bean.getResourceId());
269268
try {
270-
if (null == bean.getInputStream()) {
269+
ResourceInterface oldResource = this.loadResource(bean.getResourceId());
270+
ResourceInterface updatedResource = null;
271+
if (null != bean.getInputStream()) {
272+
updatedResource = this.createResource(bean);
273+
oldResource.moveInstances("todelete");
274+
updatedResource.saveResourceInstances(bean, getIgnoreMetadataKeysForResourceType(bean.getResourceType()));
275+
oldResource.deleteResourceInstances();
276+
} else {
271277
oldResource.setDescription(bean.getDescr());
272278
oldResource.setCategories(bean.getCategories());
273279
oldResource.setMetadata(bean.getMetadata());
274280
oldResource.setMainGroup(bean.getMainGroup());
275281
oldResource.setFolderPath(bean.getFolderPath());
276-
this.getResourceDAO().updateResource(oldResource);
277-
this.notifyResourceChanging(oldResource, ResourceChangedEvent.UPDATE_OPERATION_CODE);
278-
} else {
279-
ResourceInterface updatedResource = this.createResource(bean);
280-
updatedResource
281-
.saveResourceInstances(bean, getIgnoreMetadataKeysForResourceType(bean.getResourceType()));
282-
this.getResourceDAO().updateResource(updatedResource);
283-
if (!updatedResource.getMasterFileName().equals(oldResource.getMasterFileName())) {
284-
oldResource.deleteResourceInstances();
285-
}
286-
this.notifyResourceChanging(updatedResource, ResourceChangedEvent.UPDATE_OPERATION_CODE);
282+
updatedResource = oldResource;
287283
}
284+
this.getResourceDAO().updateResource(updatedResource);
285+
this.notifyResourceChanging(updatedResource, ResourceChangedEvent.UPDATE_OPERATION_CODE);
288286
} catch (Throwable t) {
289287
logger.error("Error updating resource", t);
290288
throw new EntException("Error updating resource", t);

cms-plugin/src/main/java/com/agiletec/plugins/jacms/aps/system/services/resource/model/AbstractMonoInstanceResource.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import org.apache.commons.lang.StringUtils;
2020

2121
import java.io.InputStream;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Optional;
2225
import org.entando.entando.ent.exception.EntResourceNotFoundException;
2326
import org.entando.entando.ent.exception.EntResourceNotFoundRuntimeException;
2427
import org.entando.entando.ent.exception.EntRuntimeException;
@@ -45,6 +48,12 @@ public abstract class AbstractMonoInstanceResource extends AbstractResource {
4548
public boolean isMultiInstance() {
4649
return false;
4750
}
51+
52+
@Override
53+
public List<ResourceInstance> getInstanceList() {
54+
return Optional.ofNullable(this.getInstance())
55+
.map(i -> new ArrayList<>(List.of(i))).orElse(new ArrayList<>());
56+
}
4857

4958
@Override
5059
public InputStream getResourceStream(int size, String langCode) {

cms-plugin/src/main/java/com/agiletec/plugins/jacms/aps/system/services/resource/model/AbstractMultiInstanceResource.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ public AbstractMultiInstanceResource() {
3838
instances = new HashMap<>();
3939
}
4040

41+
@Override
42+
public List<ResourceInstance> getInstanceList() {
43+
return new ArrayList<>(this.getInstances().values());
44+
}
45+
4146
@Override
4247
public void deleteResourceInstances() throws EntException {
4348
try {
44-
Collection<ResourceInstance> resources = this.getInstances().values();
49+
Collection<ResourceInstance> resources = this.getInstanceList();
4550
for (ResourceInstance currentInstance : resources) {
4651
String fileName = currentInstance.getFileName();
4752
String subPath = this.getDiskSubFolder() + fileName;
@@ -73,7 +78,7 @@ public boolean isMultiInstance() {
7378
@Override
7479
public String getXML() {
7580
ResourceDOM resourceDom = getResourceDOM();
76-
List<ResourceInstance> resources = new ArrayList<>(this.getInstances().values());
81+
List<ResourceInstance> resources = this.getInstanceList();
7782
for (ResourceInstance currentInstance : resources) {
7883
resourceDom.addInstance(currentInstance.getJDOMElement());
7984
}

cms-plugin/src/main/java/com/agiletec/plugins/jacms/aps/system/services/resource/model/AbstractResource.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import java.io.*;
2727
import java.util.*;
28+
import org.apache.commons.lang3.StringUtils;
2829

2930
public abstract class AbstractResource implements ResourceInterface, Serializable {
3031

@@ -365,9 +366,16 @@ protected ResourceDOM getNewResourceDOM() {
365366
}
366367

367368
protected String getDiskSubFolder() {
368-
StringBuilder diskFolder = new StringBuilder(folder);
369+
return this.getDiskSubFolder(this.getFolderPath());
370+
}
371+
372+
protected String getDiskSubFolder(String folderPath) {
373+
StringBuilder diskFolder = new StringBuilder(this.folder);
374+
if (!StringUtils.isBlank(folderPath)) {
375+
diskFolder.append(folderPath).append(File.separator);
376+
}
369377
if (this.isProtectedResource()) {
370-
diskFolder.append(mainGroup).append("/");
378+
diskFolder.append(mainGroup).append(File.separator);
371379
}
372380
return diskFolder.toString();
373381
}
@@ -420,6 +428,12 @@ protected String getUrlPath(ResourceInstance instance) {
420428
if (!subFolder.toString().endsWith("/")) {
421429
subFolder.append("/");
422430
}
431+
if (!StringUtils.isBlank(this.getFolderPath())) {
432+
subFolder.append(this.getFolderPath());
433+
if (!this.getFolderPath().endsWith("/")) {
434+
subFolder.append("/");
435+
}
436+
}
423437
subFolder.append(instance.getFileName());
424438
String path = this.getStorageManager().getResourceUrl(subFolder.toString(), false);
425439
urlPath.append(path);
@@ -504,6 +518,33 @@ protected boolean exists(String instanceFileName) {
504518
}
505519
}
506520

521+
@Override
522+
public void moveInstances(String newFolderPath) throws EntException {
523+
Map<String, String> movements = new HashMap<>();
524+
try {
525+
for (ResourceInstance resourceInstance : this.getInstanceList()) {
526+
String internalPath = this.getDiskSubFolder() + resourceInstance.getFileName();
527+
String destInternalPath = this.getDiskSubFolder(newFolderPath) + resourceInstance.getFileName();
528+
boolean result = this.getStorageManager().move(internalPath, this.isProtectedResource(), destInternalPath, this.isProtectedResource());
529+
if (!result) {
530+
throw new EntException(String.format("Error moving File '%s' to '%s', protected '%s'", internalPath, destInternalPath, this.isProtectedResource()));
531+
}
532+
movements.put(internalPath, destInternalPath);
533+
}
534+
logger.warn("Move resource instances from '{}' to '{}' has no effect on the database, protected '{}'", this.getDiskSubFolder(), newFolderPath, this.isProtectedResource());
535+
this.setFolderPath(newFolderPath);
536+
} catch (Exception e) {
537+
for (ResourceInstance resourceInstance : this.getInstanceList()) {
538+
String internalPath = this.getDiskSubFolder() + resourceInstance.getFileName();
539+
String dest = movements.get(internalPath);
540+
if (null != dest) {
541+
this.getStorageManager().move(dest, this.isProtectedResource(), internalPath, this.isProtectedResource());
542+
}
543+
}
544+
throw new EntException("Error moving resource instances", e);
545+
}
546+
}
547+
507548
public IStorageManager getStorageManager() {
508549
return storageManager;
509550
}

cms-plugin/src/main/java/com/agiletec/plugins/jacms/aps/system/services/resource/model/ResourceInterface.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ default void saveResourceInstances(ResourceDataBean bean, List<String> ignoreMet
229229
*/
230230
void saveResourceInstances(ResourceDataBean bean, List<String> ignoreMetadataKeys,
231231
boolean instancesAlreadySaved) throws EntException;
232+
233+
public List<ResourceInstance> getInstanceList();
232234

233235
/**
234236
* Cancella tutte le istanze associate alla risorsa.
@@ -239,7 +241,8 @@ void saveResourceInstances(ResourceDataBean bean, List<String> ignoreMetadataKey
239241

240242
public void reloadResourceInstances() throws EntException;
241243

242-
//public boolean exists(String masterFormFileName) throws EntException;
244+
public void moveInstances(String newFolderPath) throws EntException;
245+
243246
public ResourceInstance getDefaultInstance();
244247

245248
/**

cms-plugin/src/main/java/com/agiletec/plugins/jacms/apsadmin/resource/MultipleResourceAction.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
*/
1414
package com.agiletec.plugins.jacms.apsadmin.resource;
1515

16+
import com.agiletec.aps.system.common.FieldSearchFilter;
1617
import com.agiletec.aps.system.common.entity.model.FieldError;
1718
import org.entando.entando.ent.exception.EntException;
1819
import com.agiletec.aps.system.services.category.Category;
1920
import com.agiletec.apsadmin.system.ApsAdminSystemConstants;
21+
import com.agiletec.plugins.jacms.aps.system.services.resource.IResourceManager;
2022
import com.agiletec.plugins.jacms.aps.system.services.resource.model.BaseResourceDataBean;
2123
import com.agiletec.plugins.jacms.aps.system.services.resource.model.ResourceInterface;
2224
import org.apache.commons.lang.StringUtils;
@@ -47,7 +49,9 @@ public class MultipleResourceAction extends ResourceAction {
4749
public void validate() {
4850
logger.debug("MultipleResourceAction validate");
4951
savedId.clear();
52+
5053
if (ApsAdminSystemConstants.EDIT == this.getStrutsAction()) {
54+
this.fetchFileUploadFileNames();
5155
this.fetchFileDescriptions();
5256
addFieldErrors(validateFileDescriptions());
5357
} else {
@@ -57,6 +61,7 @@ public void validate() {
5761
addFieldErrors(validateFileUploadNames());
5862
addFieldErrors(validateFileUploadContentType());
5963
}
64+
addFieldErrors(validateCheckDuplicateFile());
6065
}
6166

6267
private void addFieldErrors(List<FieldError> fieldErrors) {
@@ -148,6 +153,36 @@ private List<FieldError> validateFileUploadContentType() {
148153
}
149154
return errors;
150155
}
156+
157+
private List<FieldError> validateCheckDuplicateFile() {
158+
List<FieldError> errors = new ArrayList<>();
159+
try {
160+
if (StringUtils.isBlank(this.getMainGroup())) {
161+
return errors;
162+
}
163+
FieldSearchFilter<String> groupFilter = new FieldSearchFilter<>(IResourceManager.RESOURCE_MAIN_GROUP_FILTER_KEY, this.getMainGroup(), false);
164+
for (int i = 0; i < getFileUploadFileName().size(); i++) {
165+
String formFileName = this.getFileUploadFileName(i);
166+
if (formFileName.isEmpty()){
167+
continue;
168+
}
169+
FieldSearchFilter<String> fileNameFilter = new FieldSearchFilter<>(IResourceManager.RESOURCE_FILENAME_FILTER_KEY, formFileName, false);
170+
FieldSearchFilter[] filters = new FieldSearchFilter[]{groupFilter, fileNameFilter};
171+
List<String> resourcesId = this.getResourceManager().searchResourcesId(filters, List.of());
172+
if (resourcesId.isEmpty()) {
173+
continue;
174+
}
175+
if ((this.getStrutsAction() == ApsAdminSystemConstants.ADD) ||
176+
(this.getStrutsAction() == ApsAdminSystemConstants.EDIT && !resourcesId.contains(this.getResourceId()))) {
177+
String[] args = {formFileName};
178+
errors.add(new FieldError(FILE_NAME_FIELD + i, getText("error.resource.file.alreadyPresent", args)));
179+
}
180+
}
181+
} catch (EntException e) {
182+
logger.error("Error on check duplicated files", e);
183+
}
184+
return errors;
185+
}
151186

152187
@Override
153188
public String edit() {

0 commit comments

Comments
 (0)