diff --git a/src/main/java/fr/recia/collabsoft/db/entities/File.java b/src/main/java/fr/recia/collabsoft/db/entities/File.java index 521d6f52..1f5d18b0 100644 --- a/src/main/java/fr/recia/collabsoft/db/entities/File.java +++ b/src/main/java/fr/recia/collabsoft/db/entities/File.java @@ -80,6 +80,9 @@ public class File { @JoinColumn(name = "associated_app_id") private AssociatedApp associatedApp; + @Column(name = "public", nullable = false) + private Boolean pub; + @PrePersist public void prePersist() { Date d = new Date(); diff --git a/src/main/java/fr/recia/collabsoft/db/entities/Metadata.java b/src/main/java/fr/recia/collabsoft/db/entities/Metadata.java new file mode 100644 index 00000000..ef7b73d9 --- /dev/null +++ b/src/main/java/fr/recia/collabsoft/db/entities/Metadata.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2023 GIP-RECIA, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fr.recia.collabsoft.db.entities; + +import fr.recia.collabsoft.db.entities.ids.MetadataId; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.proxy.HibernateProxy; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import java.util.Objects; + +@Entity +@IdClass(MetadataId.class) +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Metadata { + + @Id + @ManyToOne + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @Id + @ManyToOne + @JoinColumn(name = "file_id", nullable = false) + private File file; + + @Column(name = "starred") + private Boolean starred; + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + Class oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass(); + Class thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass(); + if (thisEffectiveClass != oEffectiveClass) return false; + Metadata that = (Metadata) o; + return getUser() != null && Objects.equals(getUser(), that.getUser()) + && getFile() != null && Objects.equals(getFile(), that.getFile()); + } + + @Override + public final int hashCode() { + return Objects.hash(user, file); + } + +} diff --git a/src/main/java/fr/recia/collabsoft/db/entities/ids/MetadataId.java b/src/main/java/fr/recia/collabsoft/db/entities/ids/MetadataId.java new file mode 100644 index 00000000..e2e6636c --- /dev/null +++ b/src/main/java/fr/recia/collabsoft/db/entities/ids/MetadataId.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 GIP-RECIA, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fr.recia.collabsoft.db.entities.ids; + +import fr.recia.collabsoft.db.entities.File; +import fr.recia.collabsoft.db.entities.User; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +public class MetadataId implements Serializable { + + private User user; + private File file; + +} diff --git a/src/main/java/fr/recia/collabsoft/db/repositories/MetadataRepository.java b/src/main/java/fr/recia/collabsoft/db/repositories/MetadataRepository.java new file mode 100644 index 00000000..b261ec85 --- /dev/null +++ b/src/main/java/fr/recia/collabsoft/db/repositories/MetadataRepository.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 GIP-RECIA, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fr.recia.collabsoft.db.repositories; + +import fr.recia.collabsoft.db.entities.Metadata; +import fr.recia.collabsoft.db.entities.ids.MetadataId; + +public interface MetadataRepository extends AbstractRepository { +} diff --git a/src/main/java/fr/recia/collabsoft/pojo/JsonFileBody.java b/src/main/java/fr/recia/collabsoft/pojo/JsonFileBody.java index 8f1599c4..06f583aa 100644 --- a/src/main/java/fr/recia/collabsoft/pojo/JsonFileBody.java +++ b/src/main/java/fr/recia/collabsoft/pojo/JsonFileBody.java @@ -24,13 +24,14 @@ public class JsonFileBody { private String description; private byte[] blob; private Long associatedAppId; + private Boolean pub; public boolean postDataOk() { - return (title != null && blob != null && associatedAppId != null); + return (title != null && blob != null && associatedAppId != null && pub != null); } public boolean putDataOk() { - return (title != null || description != null || blob != null); + return (title != null || description != null || blob != null || pub != null); } } diff --git a/src/main/java/fr/recia/collabsoft/pojo/JsonMetadataBody.java b/src/main/java/fr/recia/collabsoft/pojo/JsonMetadataBody.java new file mode 100644 index 00000000..267485f1 --- /dev/null +++ b/src/main/java/fr/recia/collabsoft/pojo/JsonMetadataBody.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 GIP-RECIA, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fr.recia.collabsoft.pojo; + +import lombok.Data; + +@Data +public class JsonMetadataBody { + + private Boolean starred; + + public boolean putDataOk() { + return (starred != null); + } + +} diff --git a/src/main/java/fr/recia/collabsoft/web/rest/FileController.java b/src/main/java/fr/recia/collabsoft/web/rest/FileController.java index e324e6f6..c85865dd 100644 --- a/src/main/java/fr/recia/collabsoft/web/rest/FileController.java +++ b/src/main/java/fr/recia/collabsoft/web/rest/FileController.java @@ -16,25 +16,28 @@ package fr.recia.collabsoft.web.rest; import com.querydsl.jpa.JPAExpressions; -import fr.recia.collabsoft.db.dto.FileDto; import fr.recia.collabsoft.db.entities.AssociatedApp; import fr.recia.collabsoft.db.entities.Collaboration; import fr.recia.collabsoft.db.entities.File; import fr.recia.collabsoft.db.entities.FileHistory; +import fr.recia.collabsoft.db.entities.Metadata; import fr.recia.collabsoft.db.entities.QAssociatedApp; import fr.recia.collabsoft.db.entities.QCollaboration; import fr.recia.collabsoft.db.entities.QFile; import fr.recia.collabsoft.db.entities.QFileHistory; +import fr.recia.collabsoft.db.entities.QMetadata; import fr.recia.collabsoft.db.entities.QUser; import fr.recia.collabsoft.db.entities.User; import fr.recia.collabsoft.db.repositories.AssociatedAppRepository; import fr.recia.collabsoft.db.repositories.CollaborationRepository; import fr.recia.collabsoft.db.repositories.FileHistoryRepository; import fr.recia.collabsoft.db.repositories.FileRepository; +import fr.recia.collabsoft.db.repositories.MetadataRepository; import fr.recia.collabsoft.db.repositories.UserRepository; import fr.recia.collabsoft.pojo.JsonCollaborationBody; import fr.recia.collabsoft.pojo.JsonFileBody; import fr.recia.collabsoft.pojo.JsonHistoryBody; +import fr.recia.collabsoft.pojo.JsonMetadataBody; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.IteratorUtils; @@ -66,6 +69,8 @@ public class FileController { @Inject private FileHistoryRepository fileHistoryRepository; @Inject + private MetadataRepository metadataRepository; + @Inject private UserRepository userRepository; // TODO: only for tests @@ -95,6 +100,26 @@ public ResponseEntity> getFiles() { return new ResponseEntity<>(files, HttpStatus.OK); } + /** + * List files starred + * @return + */ + @GetMapping(value = "/starred") + public ResponseEntity> getStarredFiles() { + final List files = IteratorUtils.toList( + fileRepository.findAll( + QFile.file.id.in( + JPAExpressions.select(QMetadata.metadata.file.id) + .from(QMetadata.metadata) + .where(QMetadata.metadata.starred.eq(true)) + ) + ).iterator() + ); + if (files.isEmpty()) return new ResponseEntity<>(HttpStatus.NOT_FOUND); + + return new ResponseEntity<>(files, HttpStatus.OK); + } + /** * List files shared with me * @return @@ -115,6 +140,22 @@ public ResponseEntity> getSharedFiles() { return new ResponseEntity<>(files, HttpStatus.OK); } + /** + * List files public + * @return + */ + @GetMapping(value = "/public") + public ResponseEntity> getPublicFiles() { + final List files = IteratorUtils.toList( + fileRepository.findAll( + QFile.file.pub.eq(true) + ).iterator() + ); + if (files.isEmpty()) return new ResponseEntity<>(HttpStatus.NOT_FOUND); + + return new ResponseEntity<>(files, HttpStatus.OK); + } + /** * Save file * @param body @@ -135,6 +176,7 @@ public ResponseEntity postFile(@NonNull @RequestBody JsonFileBody body) file.setCreator(user); file.setLastEditor(user); file.setAssociatedApp(associatedApp); + file.setPub(body.getPub()); fileRepository.saveAndFlush(file); return new ResponseEntity<>(HttpStatus.CREATED); @@ -177,6 +219,8 @@ public ResponseEntity putFile(@PathVariable Long id, @NonNull @RequestBo file.setBlob(body.getBlob()); if (user != file.getLastEditor()) file.setLastEditor(user); + if (body.getPub() != null) + file.setPub(body.getPub()); fileRepository.saveAndFlush(file); return new ResponseEntity<>(HttpStatus.OK); @@ -198,6 +242,38 @@ public ResponseEntity deleteFile(@PathVariable Long id) { return new ResponseEntity<>(HttpStatus.OK); } + /* + * Metadata + */ + + /** + * Update metadata + * @param id File id + */ + @PutMapping(value = "/{id}/metadata") + public ResponseEntity> putMetadata(@PathVariable Long id, @NonNull @RequestBody JsonMetadataBody body) { + if (!body.putDataOk()) return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + User user = getCurrentUser(); + Metadata metadata = metadataRepository.findOne( + QMetadata.metadata.file.id.eq(id).and(QMetadata.metadata.user.id.eq(myId)) + ).orElse(null); + if (metadata == null) { + final File file = fileRepository.findOne( + QFile.file.id.eq(id) + ).orElse(null); + if (file == null) return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + metadata = new Metadata(); + metadata.setUser(user); + metadata.setFile(file); + } + + if (body.getStarred() != null) + metadata.setStarred(body.getStarred()); + metadataRepository.saveAndFlush(metadata); + + return new ResponseEntity<>(HttpStatus.OK); + } + /* * Share */ @@ -374,7 +450,7 @@ public ResponseEntity deleteHistory(@PathVariable Long id, @PathVariable * @param historyId FileHistory id */ @PostMapping(value = "/{id}/history/{historyId}/revert") - public ResponseEntity revertHistory(@PathVariable Long id, @PathVariable Long historyId) { + public ResponseEntity revertHistory(@PathVariable Long id, @PathVariable Long historyId) { final FileHistory fileHistory = fileHistoryRepository.findOne( QFileHistory.fileHistory.file.id.eq(id).and(QFileHistory.fileHistory.id.eq(historyId)) ).orElse(null);