diff --git a/src/main/java/org/example/vet1177/entities/Attachment.java b/src/main/java/org/example/vet1177/entities/Attachment.java new file mode 100644 index 0000000..079267b --- /dev/null +++ b/src/main/java/org/example/vet1177/entities/Attachment.java @@ -0,0 +1,98 @@ +package org.example.vet1177.entities; + +import jakarta.persistence.*; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "attachment") +public class Attachment { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "record_id", nullable = false) + @OnDelete(action = OnDeleteAction.CASCADE) + private MedicalRecord medicalRecord; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "uploaded_by", nullable = true) + @OnDelete(action = OnDeleteAction.SET_NULL) + private User uploadedBy; + + @Column(name = "file_name", nullable = false, length = 500) + private String fileName; + + // Den unika nyckeln/sökvägen i S3-bucket + @Column(name = "s3_key", nullable = false, unique = true, length = 1000) + private String s3Key; + + @Column(name = "s3_bucket", nullable = false, length = 255) + private String s3Bucket; + + @Column(name = "file_type", length = 100) + private String fileType; + + @Column(name = "file_size_bytes") + private Long fileSizeBytes; + + @Column(name = "uploaded_at", nullable = false, updatable = false) + private Instant uploadedAt; + + public Attachment() { + } + + @PrePersist + protected void onCreate() { + this.uploadedAt = Instant.now(); + } + + // Getters och Setters + public UUID getId() { return id; } + + public MedicalRecord getMedicalRecord() { return medicalRecord; } + + public void setMedicalRecord(MedicalRecord medicalRecord) { + this.medicalRecord = medicalRecord; } + + public User getUploadedBy() { + return uploadedBy; } + + public void setUploadedBy(User uploadedBy) { + this.uploadedBy = uploadedBy; } + + public String getFileName() { + return fileName; } + + public void setFileName(String fileName) { + this.fileName = fileName; } + + public String getS3Key() { + return s3Key; } + + public void setS3Key(String s3Key) { + this.s3Key = s3Key; } + + public String getS3Bucket() { + return s3Bucket; } + + public void setS3Bucket(String s3Bucket) { + this.s3Bucket = s3Bucket; } + + public String getFileType() { return fileType; } + public void setFileType(String fileType) { this.fileType = fileType; } + + public Long getFileSizeBytes() { + return fileSizeBytes; } + + public void setFileSizeBytes(Long fileSizeBytes) { + this.fileSizeBytes = fileSizeBytes; } + + public Instant getUploadedAt() { + return uploadedAt; } +} \ No newline at end of file diff --git a/src/main/java/org/example/vet1177/entities/MedicalRecord.java b/src/main/java/org/example/vet1177/entities/MedicalRecord.java index 7ade838..6699567 100644 --- a/src/main/java/org/example/vet1177/entities/MedicalRecord.java +++ b/src/main/java/org/example/vet1177/entities/MedicalRecord.java @@ -2,6 +2,8 @@ import jakarta.persistence.*; import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; @Entity @@ -47,6 +49,9 @@ public class MedicalRecord { @JoinColumn(name = "updated_by") private User updatedBy; + @OneToMany(mappedBy = "medicalRecord", cascade = CascadeType.ALL, orphanRemoval = true) + private java.util.List attachments = new ArrayList<>(); + // Timestamps @Column(name = "created_at", updatable = false) private Instant createdAt; @@ -109,6 +114,42 @@ public MedicalRecord() {} public User getUpdatedBy() { return updatedBy; } public void setUpdatedBy(User updatedBy) { this.updatedBy = updatedBy; } + + public List getAttachments() { + return java.util.Collections.unmodifiableList(attachments); + } + + public void setAttachments(List newAttachments) { + List currentAttachments = new ArrayList<>(this.attachments); + + for (Attachment attachment : currentAttachments) { + this.removeAttachment(attachment); + } + + if (newAttachments != null) { + for (Attachment attachment : newAttachments) { + this.addAttachment(attachment); + } + } + } + + public void addAttachment(Attachment attachment) { + if (attachment != null) { + this.attachments.add(attachment); + // Sätt baksidan av relationen om den inte redan är satt + if (attachment.getMedicalRecord() != this) { + attachment.setMedicalRecord(this); + } + } + } + + public void removeAttachment(Attachment attachment) { + if (attachment != null) { + this.attachments.remove(attachment); + attachment.setMedicalRecord(null); + } + } + public Instant getCreatedAt() { return createdAt; } public Instant getUpdatedAt() { return updatedAt; } public Instant getClosedAt() { return closedAt; } diff --git a/src/main/java/org/example/vet1177/entities/User.java b/src/main/java/org/example/vet1177/entities/User.java index fdf1330..6c1c993 100644 --- a/src/main/java/org/example/vet1177/entities/User.java +++ b/src/main/java/org/example/vet1177/entities/User.java @@ -2,6 +2,9 @@ import jakarta.persistence.*; import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.UUID; @Entity @@ -26,22 +29,22 @@ public class User { @Column(nullable = false, length = 20) private Role role; - // Relation till clinic @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "clinic_id") private Clinic clinic; - // FIX: primitive boolean istället för Boolean @Column(name = "is_active", nullable = false) private boolean isActive = true; - //Timestamps @Column(name = "created_at", updatable = false) private Instant createdAt; @Column(name = "updated_at") private Instant updatedAt; + @OneToMany(mappedBy = "uploadedBy", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + private List uploadedAttachments = new ArrayList<>(); + @PrePersist protected void onCreate() { createdAt = Instant.now(); @@ -53,10 +56,8 @@ protected void onUpdate() { updatedAt = Instant.now(); } - // Tom konstruktor krävs av JPA - public User() {} + public User() {} - // Konstruktor utan clinic — för OWNER public User(String name, String email, String passwordHash, Role role) { this.name = name; this.email = email; @@ -64,7 +65,6 @@ public User(String name, String email, String passwordHash, Role role) { this.role = role; } - // Konstruktor med clinic — för VET och ADMIN public User(String name, String email, String passwordHash, Role role, Clinic clinic) { this.name = name; this.email = email; @@ -91,10 +91,36 @@ public User(String name, String email, String passwordHash, Role role, Clinic cl public void setClinic(Clinic clinic) { this.clinic = clinic; } public boolean isActive() { return isActive; } - + public void setActive(boolean active) { isActive = active; } public Instant getCreatedAt() { return createdAt; } public Instant getUpdatedAt() { return updatedAt; } -} + public List getUploadedAttachments() { + return Collections.unmodifiableList(uploadedAttachments); + } + + public void setUploadedAttachments(List attachments) { + this.uploadedAttachments.clear(); + if (attachments != null) { + attachments.forEach(this::addAttachment); + } + } + + public void addAttachment(Attachment attachment) { + if (attachment != null) { + this.uploadedAttachments.add(attachment); + if (attachment.getUploadedBy() != this) { + attachment.setUploadedBy(this); + } + } + } + + public void removeAttachment(Attachment attachment) { + if (attachment != null) { + this.uploadedAttachments.remove(attachment); + attachment.setUploadedBy(null); + } + } +} diff --git a/src/main/java/org/example/vet1177/repository/AttachmentRepository.java b/src/main/java/org/example/vet1177/repository/AttachmentRepository.java new file mode 100644 index 0000000..7c5e46f --- /dev/null +++ b/src/main/java/org/example/vet1177/repository/AttachmentRepository.java @@ -0,0 +1,19 @@ +package org.example.vet1177.repository; + +import org.example.vet1177.entities.Attachment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface AttachmentRepository extends JpaRepository { + + List findByMedicalRecordId(UUID recordId); + + List findByUploadedById(UUID userId); + + Optional findByS3Key(String s3Key); +} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index b04a579..c7714a8 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -69,8 +69,8 @@ CREATE TABLE IF NOT EXISTS comment ( CREATE TABLE IF NOT EXISTS attachment ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - record_id UUID NOT NULL REFERENCES medical_record(id), - uploaded_by UUID NOT NULL REFERENCES users(id), + record_id UUID NOT NULL REFERENCES medical_record(id) ON DELETE CASCADE, + uploaded_by UUID REFERENCES users(id) ON DELETE SET NULL, file_name VARCHAR(500) NOT NULL, s3_key VARCHAR(1000) NOT NULL UNIQUE, s3_bucket VARCHAR(255) NOT NULL,