From de27d3d212e9c5ed965a51bf033d235743e72ffa Mon Sep 17 00:00:00 2001
From: Tom Zhao <tom.zhao@dsv.su.se>
Date: Mon, 28 Oct 2024 14:30:50 +0100
Subject: [PATCH] task/3382: Fixed decision and reviewer_approval and their
 related JPA-mappings

---
 .../se/su/dsv/scipro/reviewing/Decision.java  | 106 +++++++++++-------
 .../scipro/reviewing/ReviewerApproval.java    |  70 ++++++++----
 .../V389__harmonize_table_attribute_name.sql  |  61 +++++++++-
 3 files changed, 174 insertions(+), 63 deletions(-)

diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java b/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java
index cc255a893e..6d3fb25f16 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java
@@ -20,51 +20,73 @@ import se.su.dsv.scipro.system.User;
 
 import java.time.Instant;
 import java.time.LocalDate;
-import java.util.*;
+import java.util.Date;
+import java.util.Optional;
 
 @Entity
-@Table(name = "Decision")
+@Table(name = "decision")
 public class Decision {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
+    @Column(name = "status")
     @Enumerated(EnumType.STRING)
     private Status status = Status.UNDECIDED;
 
-    @OneToOne(optional = false)
-    @JoinColumn(name = "thesis_reference_id")
-    private FileReference thesis;
-
     @Basic
+    @Column(name = "reason")
     private String reason;
 
     @Basic
+    @Column(name = "comment")
     private String comment;
 
-    @OneToOne(optional = true)
-    @JoinColumn(name = "attachment_reference_id")
-    private FileReference attachment;
-
+    @Basic
+    @Column(name = "requested_date")
     @Temporal(TemporalType.TIMESTAMP)
     private Date requested;
 
-    @Temporal(TemporalType.TIMESTAMP)
-    private Date deadline;
-
+    @Basic
+    @Column(name = "decision_date")
     @Temporal(TemporalType.TIMESTAMP)
     private Date decisionDate;
 
-    @ManyToOne(optional = false)
-    private ReviewerApproval reviewerApproval;
-
-    @ManyToOne
-    @JoinColumn(name = "assigned_reviewer_id")
-    private User assignedReviewer;
+    @Basic
+    @Column(name = "deadline")
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date deadline;
 
+    @Basic
     @Column(name = "assigned_reviewer_date")
     private LocalDate reviewerAssignedAt;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (decision) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "assigned_reviewer_id", referencedColumnName = "id")
+    private User assignedReviewer;
+
+    @OneToOne(optional = true)
+    @JoinColumn(name = "attachment_reference_id", referencedColumnName = "id")
+    private FileReference attachment;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "reviewer_approval_id", referencedColumnName = "id")
+    private ReviewerApproval reviewerApproval;
+
+    @OneToOne(optional = false)
+    @JoinColumn(name = "thesis_reference_id", referencedColumnName = "id")
+    private FileReference thesis;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected Decision() {} // JPA
 
     Decision(ReviewerApproval reviewerApproval, final FileReference thesis, final String comment, final Date deadline) {
@@ -79,6 +101,9 @@ public class Decision {
         this.comment = comment;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -87,14 +112,6 @@ public class Decision {
         this.id = id;
     }
 
-    public FileReference getThesis() {
-        return thesis;
-    }
-
-    public ReviewerApproval getReviewerApproval() {
-        return reviewerApproval;
-    }
-
     public Status getStatus() {
         return status;
     }
@@ -107,10 +124,6 @@ public class Decision {
         return comment;
     }
 
-    public Optional<FileReference> getAttachment() {
-        return Optional.ofNullable(attachment);
-    }
-
     public Date getRequested() {
         return requested;
     }
@@ -127,14 +140,6 @@ public class Decision {
         this.deadline = deadline;
     }
 
-    public User getAssignedReviewer() {
-        return assignedReviewer;
-    }
-
-    public void setAssignedReviewer(User assignedReviewer) {
-        this.assignedReviewer = assignedReviewer;
-    }
-
     public LocalDate getReviewerAssignedAt() {
         return reviewerAssignedAt;
     }
@@ -143,6 +148,29 @@ public class Decision {
         this.reviewerAssignedAt = reviewerAssignedAt;
     }
 
+    public User getAssignedReviewer() {
+        return assignedReviewer;
+    }
+
+    public void setAssignedReviewer(User assignedReviewer) {
+        this.assignedReviewer = assignedReviewer;
+    }
+
+    public Optional<FileReference> getAttachment() {
+        return Optional.ofNullable(attachment);
+    }
+
+    public ReviewerApproval getReviewerApproval() {
+        return reviewerApproval;
+    }
+
+    public FileReference getThesis() {
+        return thesis;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
     void approve(final String reason, final Optional<FileReference> attachment) {
         decide(Status.APPROVED, reason, attachment);
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java
index 25c63338aa..cdad680797 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java
@@ -1,6 +1,8 @@
 package se.su.dsv.scipro.reviewing;
 
 import jakarta.persistence.GenerationType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
@@ -13,31 +15,61 @@ import jakarta.persistence.Id;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.OneToOne;
 import jakarta.persistence.OrderBy;
-import java.util.*;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
 
 @Entity
+@Table(name = "reviewer_approval")
 @DiscriminatorColumn(name = "type", length = 64)
 public abstract class ReviewerApproval extends DomainObject {
-    @OneToOne(optional = false)
-    protected Project project;
-
-    @OneToMany(mappedBy = "reviewerApproval", cascade = CascadeType.ALL)
-    @OrderBy("requested desc")
-    protected List<Decision> decisions = new LinkedList<>();
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    public abstract Step getStep();
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (reviewer_approval) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    protected Project project;
 
-    public FileReference getCurrentThesis() {
-        return getCurrentDecision().getThesis();
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "reviewer_approval"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "reviewerApproval", cascade = CascadeType.ALL)
+    @OrderBy("requested desc")
+    protected List<Decision> decisions = new LinkedList<>();
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
     }
 
     public Project getProject(){return this.project;}
 
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    public abstract Step getStep();
 
+    public Decision getCurrentDecision() {
+        return decisions.get(0);
+    }
+
+    public FileReference getCurrentThesis() {
+        return getCurrentDecision().getThesis();
+    }
 
     public Status getCurrentStatus() {
         return getCurrentDecision().getStatus();
@@ -63,10 +95,6 @@ public abstract class ReviewerApproval extends DomainObject {
         getCurrentDecision().reject(reason, attachment);
     }
 
-    public Decision getCurrentDecision() {
-        return decisions.get(0);
-    }
-
     public void addNewThesis(final FileReference thesis, final String comment, final Date deadline) {
         if (getCurrentStatus() != Status.REJECTED) {
             throw new IllegalStateException();
@@ -86,17 +114,15 @@ public abstract class ReviewerApproval extends DomainObject {
         return getCurrentStatus() == Status.APPROVED;
     }
 
-    @Override
-    public Long getId() {
-        return this.id;
+    public Date getCurrentDeadline() {
+        return getCurrentDecision().getDeadline();
     }
 
+    // ----------------------------------------------------------------------------------
+    // Nested types.
+    // ----------------------------------------------------------------------------------
     public enum Step {
         ROUGH_DRAFT_APPROVAL,
         FINAL_SEMINAR_APPROVAL
     }
-
-    public Date getCurrentDeadline() {
-        return getCurrentDecision().getDeadline();
-    }
 }
diff --git a/core/src/main/resources/db/migration/V389__harmonize_table_attribute_name.sql b/core/src/main/resources/db/migration/V389__harmonize_table_attribute_name.sql
index 6a115da106..a4a7654105 100644
--- a/core/src/main/resources/db/migration/V389__harmonize_table_attribute_name.sql
+++ b/core/src/main/resources/db/migration/V389__harmonize_table_attribute_name.sql
@@ -2709,9 +2709,66 @@ alter table `project_file`
  * Step 18: Decision & ReviewerApproval
  */
 
--- todo: table: Decision
+-- table: Decision
 
--- todo: table: ReviewerApproval
+alter table `Decision` drop foreign key `fk_Decision_ReviewerApproval`;
+alter table `Decision` drop foreign key `FK_decision_reviewer`;
+alter table `Decision` drop foreign key `FK_Decision_thesis`;
+alter table `Decision` drop foreign key `FK_Decision_attachment`;
+
+alter table `Decision` drop key `FK_decision_reviewer`;
+alter table `Decision` drop key `FK_Decision_attachment`;
+alter table `Decision` drop key `FK_Decision_thesis`;
+alter table `Decision` drop key `fk_ReviewerApproval_Decision_idx`;
+
+rename table `Decision` to `decision`;
+
+alter table `decision` change `status` `status` varchar(255) default null after `id`;
+alter table `decision` change `requested` `requested_date` datetime not null;
+alter table `decision` change `decisionDate` `decision_date` datetime default null;
+alter table `decision` change `deadline` `deadline` datetime default null after `decision_date`;
+alter table `decision` change `assigned_reviewer_date` `assigned_reviewer_date` date default null after `deadline`;
+alter table `decision` change `assigned_reviewer_id` `assigned_reviewer_id` bigint(20) default null after `assigned_reviewer_date`;
+alter table `decision` change `attachment_reference_id` `attachment_reference_id` bigint(20) default null after `assigned_reviewer_id`;
+alter table `decision` change `reviewerApproval_id` `reviewer_approval_id` bigint(20) not null;
+
+alter table `decision`
+    add constraint fk_decision_assigned_reviewer_id
+        foreign key (assigned_reviewer_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `decision`
+    add constraint fk_decision_attachment_reference_id
+        foreign key (attachment_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `decision`
+    add constraint fk_decision_thesis_reference_id
+        foreign key (thesis_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+-- table: ReviewerApproval
+
+alter table `ReviewerApproval` drop foreign key `FK_9lr1dn8boyfc5a0477ld4q8rw`;
+
+alter table `ReviewerApproval` drop key `FK_9lr1dn8boyfc5a0477ld4q8rw`;
+
+rename table `ReviewerApproval` to `reviewer_approval`;
+
+alter table `reviewer_approval` change `type` `type` varchar(64) not null after `version`;
+alter table `reviewer_approval` change `project_id` `project_id` bigint(20) not null after `type`;
+
+alter table `reviewer_approval`
+    add constraint fk_reviewer_approval_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- add foreign key from decision to reviewer_approval
+
+alter table `decision`
+    add constraint fk_decision_reviewer_approval_id
+        foreign key (reviewer_approval_id) references reviewer_approval (id)
+            on delete cascade on update cascade;
 
 /* Useful SQL