Skip to content

Commit 82bebf6

Browse files
authored
Stash & restore elements (#116)
Signed-off-by: Seddik Yengui <[email protected]>
1 parent 93ceb72 commit 82bebf6

File tree

8 files changed

+444
-17
lines changed

8 files changed

+444
-17
lines changed

src/main/java/org/gridsuite/directory/server/DirectoryController.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.swagger.v3.oas.annotations.tags.Tag;
1414
import org.gridsuite.directory.server.dto.ElementAttributes;
1515
import org.gridsuite.directory.server.dto.RootDirectoryAttributes;
16+
import org.springframework.data.util.Pair;
1617
import org.springframework.http.HttpStatus;
1718
import org.springframework.http.MediaType;
1819
import org.springframework.http.ResponseEntity;
@@ -76,6 +77,33 @@ public ResponseEntity<List<ElementAttributes>> getPath(@PathVariable("elementUui
7677
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(service.getPath(elementUuid, userId));
7778
}
7879

80+
@PostMapping(value = "/elements/stash")
81+
@Operation(summary = "Stash elements")
82+
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "elements were stashed")})
83+
public ResponseEntity<Void> stashElements(@Parameter(description = "elements UUIDs") @RequestParam("ids") List<UUID> elementsUuid,
84+
@RequestHeader("userId") String userId) {
85+
service.stashElements(elementsUuid, userId);
86+
return ResponseEntity.ok().build();
87+
}
88+
89+
@PostMapping(value = "/elements/{parentUuid}/restore")
90+
@Operation(summary = "Restore elements")
91+
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "elements were restored ")})
92+
public ResponseEntity<Void> restoreElements(@RequestBody List<UUID> elementsUuid,
93+
@PathVariable("parentUuid") UUID parentUuid,
94+
@RequestHeader("userId") String userId) {
95+
service.restoreElements(elementsUuid, parentUuid, userId);
96+
return ResponseEntity.ok().build();
97+
}
98+
99+
@GetMapping(value = "/elements/stash")
100+
@Operation(summary = "Get the list of elements in the trash")
101+
@ApiResponses(value = {
102+
@ApiResponse(responseCode = "200", description = "the list of elements in the trash")})
103+
public ResponseEntity<List<Pair<ElementAttributes, Long>>> getStashedElements(@RequestHeader("userId") String userId) {
104+
return ResponseEntity.ok().body(service.getStashedElements(userId));
105+
}
106+
79107
@DeleteMapping(value = "/elements/{elementUuid}")
80108
@Operation(summary = "Remove directory/element")
81109
@ApiResponses(value = {
@@ -88,6 +116,15 @@ public ResponseEntity<Void> deleteElement(@PathVariable("elementUuid") UUID elem
88116
return ResponseEntity.ok().build();
89117
}
90118

119+
@DeleteMapping(value = "/elements")
120+
@Operation(summary = "Remove directories/elements")
121+
@ApiResponses(@ApiResponse(responseCode = "200", description = "Directory/element was successfully removed"))
122+
public ResponseEntity<Void> deleteElements(@Parameter(description = "elements UUIDs") @RequestParam("ids") List<UUID> elementsUuid,
123+
@RequestHeader("userId") String userId) {
124+
service.deleteElements(elementsUuid, userId);
125+
return ResponseEntity.ok().build();
126+
}
127+
91128
@GetMapping(value = "/root-directories", produces = MediaType.APPLICATION_JSON_VALUE)
92129
@Operation(summary = "Get root directories")
93130
@ApiResponses(@ApiResponse(responseCode = "200", description = "The root directories"))

src/main/java/org/gridsuite/directory/server/DirectoryService.java

Lines changed: 176 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.slf4j.LoggerFactory;
1919
import org.springframework.beans.factory.annotation.Autowired;
2020
import org.springframework.context.annotation.Bean;
21+
import org.springframework.data.util.Pair;
2122
import org.springframework.messaging.Message;
2223
import org.springframework.stereotype.Service;
2324
import org.springframework.transaction.annotation.Transactional;
@@ -160,7 +161,9 @@ private ElementAttributes insertElement(ElementAttributes elementAttributes, UUI
160161
elementAttributes.getDescription(),
161162
now,
162163
now,
163-
elementAttributes.getOwner()
164+
elementAttributes.getOwner(),
165+
false,
166+
null
164167
)
165168
)
166169
);
@@ -257,7 +260,7 @@ private Stream<ElementAttributes> getDirectoryElementsStream(UUID directoryUuid,
257260
}
258261

259262
private Stream<ElementAttributes> getAllDirectoryElementsStream(UUID directoryUuid, List<String> types, String userId) {
260-
List<DirectoryElementEntity> directoryElements = directoryElementRepository.findAllByParentId(directoryUuid);
263+
List<DirectoryElementEntity> directoryElements = directoryElementRepository.findAllByParentIdAndStashed(directoryUuid, false);
261264
Map<UUID, Long> subdirectoriesCountsMap = getSubDirectoriesCountMap(userId, types, directoryElements);
262265
return directoryElements
263266
.stream()
@@ -517,7 +520,7 @@ private Boolean isRootDirectoryExist(String rootName) {
517520
}
518521

519522
private Boolean isElementExists(UUID parentDirectoryUuid, String elementName, String type) {
520-
return !directoryElementRepository.findByNameAndParentIdAndType(elementName, parentDirectoryUuid, type).isEmpty();
523+
return !directoryElementRepository.findByNameAndParentIdAndTypeAndStashed(elementName, parentDirectoryUuid, type, false).isEmpty();
521524
}
522525

523526
public UUID getDirectoryUuid(String directoryName, UUID parentDirectoryUuid) {
@@ -535,11 +538,11 @@ public UUID getDirectoryUuid(String directoryName, UUID parentDirectoryUuid) {
535538
}
536539

537540
public boolean elementExists(UUID parentDirectoryUuid, String elementName, String type) {
538-
return !directoryElementRepository.findByNameAndParentIdAndType(elementName, parentDirectoryUuid, type).isEmpty();
541+
return !directoryElementRepository.findByNameAndParentIdAndTypeAndStashed(elementName, parentDirectoryUuid, type, false).isEmpty();
539542
}
540543

541544
public List<ElementAttributes> getElements(List<UUID> ids, boolean strictMode, List<String> types) {
542-
List<DirectoryElementEntity> elementEntities = directoryElementRepository.findAllById(ids);
545+
List<DirectoryElementEntity> elementEntities = directoryElementRepository.findAllByIdInAndStashed(ids, false);
543546

544547
if (strictMode && elementEntities.size() != ids.stream().distinct().count()) {
545548
throw new DirectoryException(NOT_FOUND);
@@ -613,4 +616,172 @@ public String getDuplicateNameCandidate(UUID directoryUuid, String elementName,
613616
}
614617
return nameCandidate(elementName, i);
615618
}
619+
620+
private List<DirectoryElementEntity> getEntitiesToRestore(List<DirectoryElementEntity> entities,
621+
List<DirectoryElementEntity> rejectedEntities,
622+
String userId,
623+
boolean isParentPrivate) {
624+
if (isParentPrivate) {
625+
return getEntitiesCreatedBySameUser(entities, rejectedEntities, userId);
626+
}
627+
628+
return entities.stream()
629+
.filter(entity -> {
630+
boolean isUpdatable = Objects.equals(userId, entity.getOwner()) || !entity.getIsPrivate();
631+
if (!isUpdatable) {
632+
rejectedEntities.add(entity);
633+
}
634+
return isUpdatable;
635+
})
636+
.toList();
637+
}
638+
639+
public void restoreElements(List<UUID> elementsUuid, UUID parentUuid, String userId) {
640+
// Get parent directory
641+
ElementAttributes parent = getElement(parentUuid);
642+
643+
// Get all updatable entities. Entities should be public or created by the user, so it can be restored
644+
List<DirectoryElementEntity> notUpdatableEntities = new ArrayList<>();
645+
List<DirectoryElementEntity> allStashedElements = directoryElementRepository.findAllStashedElements(elementsUuid, true, userId);
646+
List<DirectoryElementEntity> updatableEntities = getEntitiesToRestore(allStashedElements, notUpdatableEntities, userId, parent.getAccessRights().isPrivate());
647+
648+
List<DirectoryElementEntity> entities = updatableEntities
649+
.stream()
650+
.flatMap(entity -> {
651+
entity.setParentId(parentUuid);
652+
entity.setName(getDuplicateNameCandidate(parentUuid, entity.getName(), entity.getType(), userId));
653+
654+
// Retrieve descendants of the current entity
655+
List<DirectoryElementEntity> descendants = getEntitiesToRestore(
656+
directoryElementRepository.findAllDescendantsWithSameStashDate(entity.getId(), userId),
657+
notUpdatableEntities,
658+
userId,
659+
parent.getAccessRights().isPrivate());
660+
661+
// Combine parent and descendants into a single list
662+
List<DirectoryElementEntity> result = new ArrayList<>();
663+
result.add(entity);
664+
result.addAll(descendants);
665+
666+
return result.stream().map(e -> e.stashElement(false, null));
667+
})
668+
.toList();
669+
670+
directoryElementRepository.saveAll(entities);
671+
notificationService.emitDirectoryChanged(
672+
parentUuid,
673+
parent.getElementName(),
674+
userId,
675+
null,
676+
parent.getAccessRights().isPrivate(),
677+
parentUuid == null,
678+
NotificationType.UPDATE_DIRECTORY
679+
);
680+
emitDirectoryChangedNotification(parentUuid, userId);
681+
if (!notUpdatableEntities.isEmpty()) {
682+
throw new DirectoryException(NOT_ALLOWED);
683+
}
684+
}
685+
686+
public void stashElements(List<UUID> elementsUuid, String userId) {
687+
// we add the same stash date to all the elements that are deleted together
688+
LocalDateTime stashDate = LocalDateTime.now();
689+
List<DirectoryElementEntity> entities = directoryElementRepository.findAllByIdInAndStashed(elementsUuid, false);
690+
List<DirectoryElementEntity> notUpdatableEntities = new ArrayList<>();
691+
List<DirectoryElementEntity> updatableEntities = getEntitiesCreatedBySameUser(entities, notUpdatableEntities, userId);
692+
693+
directoryElementRepository.saveAll(updatableEntities.stream()
694+
.flatMap(entity -> {
695+
List<DirectoryElementEntity> descendants = directoryElementRepository.findAllDescendants(entity.getId(), userId);
696+
// Combine parent and descendants into a single list
697+
List<DirectoryElementEntity> result = new ArrayList<>();
698+
result.add(entity);
699+
result.addAll(descendants);
700+
return result.stream().map(e -> {
701+
DirectoryElementEntity stashedElement = e.stashElement(true, stashDate);
702+
if (Objects.equals(e.getType(), STUDY)) {
703+
notificationService.emitDeletedStudy(entity.getId(), userId);
704+
}
705+
return stashedElement;
706+
});
707+
})
708+
.toList());
709+
710+
updatableEntities.forEach(entity -> {
711+
UUID parentUuid = getParentUuid(entity.getId());
712+
notificationService.emitDirectoryChanged(
713+
parentUuid == null ? entity.getId() : parentUuid,
714+
entity.getName(),
715+
userId,
716+
null,
717+
entity.getIsPrivate(),
718+
parentUuid == null,
719+
parentUuid == null ? NotificationType.DELETE_DIRECTORY : NotificationType.UPDATE_DIRECTORY
720+
);
721+
});
722+
723+
if (!notUpdatableEntities.isEmpty()) {
724+
throw new DirectoryException(NOT_ALLOWED,
725+
String.format("Some or all of the elements can not be deleted : %s",
726+
String.join(", ", notUpdatableEntities.stream().map(DirectoryElementEntity::getName).toList())));
727+
}
728+
}
729+
730+
public List<Pair<ElementAttributes, Long>> getStashedElements(String userId) {
731+
List<DirectoryElementEntity> entities = directoryElementRepository.getElementsStashed(userId);
732+
return entities.stream()
733+
.map(entity -> Pair.of(toElementAttributes(entity), directoryElementRepository.countDescendants(entity.getId(), userId) - 1))
734+
.toList();
735+
}
736+
737+
public void deleteElements(List<UUID> elementsUuid, String userId) {
738+
// Get all updatable entities
739+
List<DirectoryElementEntity> notUpdatableEntities = new ArrayList<>();
740+
List<DirectoryElementEntity> updatableEntities = getEntitiesCreatedBySameUser(directoryElementRepository.findAllByIdInAndStashed(elementsUuid, true), notUpdatableEntities, userId);
741+
742+
// Collect all entities with their descendents in one list
743+
List<DirectoryElementEntity> allEntities = updatableEntities.stream()
744+
.flatMap(entity -> Stream.concat(directoryElementRepository.findAllDescendantsWithSameStashDate(entity.getId(), userId).stream(),
745+
Stream.of(entity)))
746+
.toList();
747+
748+
// Delete all entities
749+
directoryElementRepository.deleteAllById(allEntities.stream().map(DirectoryElementEntity::getId).toList());
750+
751+
// Send notification for all deleted elements
752+
allEntities.forEach(entity -> {
753+
UUID parentUuid = entity.getParentId();
754+
notificationService.emitDirectoryChanged(
755+
parentUuid == null ? entity.getId() : parentUuid,
756+
entity.getName(),
757+
userId,
758+
null,
759+
entity.getIsPrivate(),
760+
parentUuid == null,
761+
parentUuid == null ? NotificationType.DELETE_DIRECTORY : NotificationType.UPDATE_DIRECTORY
762+
);
763+
if (STUDY.equals(entity.getType())) {
764+
notificationService.emitDeletedStudy(entity.getId(), userId);
765+
}
766+
});
767+
if (!notUpdatableEntities.isEmpty()) {
768+
throw new DirectoryException(NOT_ALLOWED,
769+
String.format("Some or all of the elements can not be deleted : %s",
770+
String.join(", ", notUpdatableEntities.stream().map(DirectoryElementEntity::getName).toList())));
771+
}
772+
}
773+
774+
private List<DirectoryElementEntity> getEntitiesCreatedBySameUser(List<DirectoryElementEntity> entities,
775+
List<DirectoryElementEntity> notUpdatableEntities,
776+
String userId) {
777+
return entities.stream()
778+
.filter(entity -> {
779+
boolean isUpdatable = Objects.equals(userId, entity.getOwner());
780+
if (!isUpdatable) {
781+
notUpdatableEntities.add(entity);
782+
}
783+
return isUpdatable;
784+
})
785+
.toList();
786+
}
616787
}

src/main/java/org/gridsuite/directory/server/repository/DirectoryElementEntity.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ public class DirectoryElementEntity {
5959
@Column(name = "lastModifiedBy")
6060
private String lastModifiedBy;
6161

62+
@Column(name = "stashed")
63+
private boolean stashed;
64+
65+
@Column(name = "stash_date")
66+
private LocalDateTime stashDate;
67+
6268
public DirectoryElementEntity update(@NonNull ElementAttributes newElementAttributes) {
6369
if (StringUtils.isNotBlank(newElementAttributes.getElementName())) {
6470
this.name = newElementAttributes.getElementName();
@@ -90,4 +96,10 @@ public boolean isAttributesUpdatable(@NonNull ElementAttributes newElementAttrib
9096
Objects.isNull(newElementAttributes.getLastModificationDate()) &&
9197
Objects.isNull(newElementAttributes.getLastModifiedBy());
9298
}
99+
100+
public DirectoryElementEntity stashElement(boolean stashed, LocalDateTime stashDate) {
101+
this.stashDate = stashDate;
102+
this.stashed = stashed;
103+
return this;
104+
}
93105
}

0 commit comments

Comments
 (0)