From 213d2cd222471efd0693391fdaff3983310df2c8 Mon Sep 17 00:00:00 2001
From: Alexis POYEN <apoyen@grandlyon.com>
Date: Fri, 17 Jul 2020 15:30:53 +0200
Subject: [PATCH] Resolve "Import candidateLists"

---
 .gitlab-ci.yml                               |   3 +
 web/components/management/candidate-lists.js | 149 ++++++++++++++++++-
 web/components/management/round.js           |   1 +
 3 files changed, 151 insertions(+), 2 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d20084f..c00ec92 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,6 +14,9 @@ variables:
   DOCKER_DRIVER: overlay2
   DOCKER_TLS_CERTDIR: ""
   SONAR_URL: https://sonarqube.forge.grandlyon.com
+  GIT_STRATEGY: clone
+  GIT_DEPTH: 0
+
 
 stages:
   - sonar-analysis
diff --git a/web/components/management/candidate-lists.js b/web/components/management/candidate-lists.js
index b8d33f8..1f77a2d 100644
--- a/web/components/management/candidate-lists.js
+++ b/web/components/management/candidate-lists.js
@@ -6,6 +6,8 @@ import * as AreaModel from "/services/model/area-model.js";
 import * as PartyModel from "/services/model/party-model.js";
 import * as CandidateListModel from "/services/model/candidateList-model.js";
 import * as CandidateModel from "/services/model/candidate-model.js";
+import * as ElectionModel from "/services/model/election-model.js";
+import * as RoundModel from "/services/model/round-model.js";
 import { Delete } from "/services/common/delete.js";
 
 // DOM elements
@@ -24,6 +26,8 @@ class CandidateList {
     this.PartyModel = PartyModel.getPartyModel();
     this.CandidateListModel = CandidateListModel.getCandidateListModel();
     this.CandidateModel = CandidateModel.getCandidateModel();
+    this.ElectionModel = ElectionModel.getElectionModel();
+    this.RoundModel = RoundModel.getRoundModel();
   }
 
   async mount(where) {
@@ -31,6 +35,8 @@ class CandidateList {
     this.PartyModel.current_user = await Auth.GetUser();
     this.CandidateListModel.current_user = await Auth.GetUser();
     this.CandidateModel.current_user = await Auth.GetUser();
+    this.ElectionModel.current_user = await Auth.GetUser();
+    this.RoundModel.current_user = await Auth.GetUser();
     const mountpoint = where;
     document.getElementById(mountpoint).innerHTML = /* HTML */ `
       <header id="dropdown-candidate-lists" class="card-header clickable">
@@ -56,6 +62,7 @@ class CandidateList {
       </div>
     `;
     this.mountModal("candidateList-modal");
+    this.mountModalClone("candidateList-clone-modal");
     this.handleDom();
   }
 
@@ -113,6 +120,26 @@ class CandidateList {
     </div>`;
   }
 
+  candidateListToCloneTemplate(candidateList) {
+    return /* HTML */ `<div class="card card-list">
+      <div
+        id="candidateLists-candidateListToClone-${candidateList.ID}"
+        class="card-content clickable"
+      >
+        <div class="content">
+          <nav class="level">
+            <div
+              id="candidateLists-candidateList-desc-${candidateList.ID}"
+              class="level-left"
+            >
+              ${candidateList.Name}
+            </div>
+          </nav>
+        </div>
+      </div>
+    </div>`;
+  }
+
   mountModal(where) {
     const mountpoint = where;
     document.getElementById(mountpoint).innerHTML = /* HTML */ `
@@ -147,7 +174,10 @@ class CandidateList {
           <div class="field">
             <label>Parti</label><br />
             <div class="control select">
-              <select name="party" id="candidateList-modal-party"></select>
+              <select
+                name="party"
+                id="candclone-cardidateList-modal-party"
+              ></select>
             </div>
           </div>
         </section>
@@ -163,6 +193,24 @@ class CandidateList {
     `;
   }
 
+  mountModalClone(where) {
+    const mountpoint = where;
+    document.getElementById(mountpoint).innerHTML = /* HTML */ `
+      <div class="modal-background"></div>
+      <div class="modal-card" id="candidateList-clone-modal-card">
+        <header class="modal-card-head">
+          <p class="modal-card-title">Importer une liste</p>
+          <button
+            class="delete"
+            aria-label="close"
+            id="candidateList-clone-modal-close"
+          ></button>
+        </header>
+        <section id="candidateLists-toclone" class="modal-card-body"></section>
+      </div>
+    `;
+  }
+
   async displayCandidates() {
     document.getElementById("candidate-list").innerHTML = /* HTML */ `<div
       class="table-container"
@@ -339,6 +387,14 @@ class CandidateList {
       .addEventListener("click", function () {
         Common.toggleModal("candidateList-modal", "candidateList-modal-card");
       });
+    document
+      .getElementById(`candidateList-clone-modal-close`)
+      .addEventListener("click", function () {
+        Common.toggleModal(
+          "candidateList-clone-modal",
+          "candidateList-clone-modal-card"
+        );
+      });
     document
       .getElementById(`candidateList-modal-save`)
       .addEventListener("click", async function () {
@@ -421,10 +477,23 @@ class CandidateList {
       >
         Listes
       </h5>
-      <button id="candidate-list-new" class="button large-button is-success">
+      <button
+        id="candidate-list-new"
+        class="button large-button is-success"
+        title="Ajouter une liste"
+      >
         <span class="icon is-small">
           <i class="fas fa-plus"></i>
         </span>
+      </button>
+      <button
+        id="candidate-list-clone"
+        class="button large-button is-primary"
+        title="Importer une liste"
+      >
+        <span class="icon is-small">
+          <i class="fas fa-download"></i>
+        </span>
       </button>`;
     const markup = candidateLists
       .map((candidateList) => this.candidateListTemplate(candidateList))
@@ -463,6 +532,12 @@ class CandidateList {
       .addEventListener("click", function () {
         candidateListHandler.newCandidateList();
       });
+
+    document
+      .getElementById(`candidate-list-clone`)
+      .addEventListener("click", function () {
+        candidateListHandler.cloneCandidateListModal();
+      });
   }
 
   async updateCandidateLists() {
@@ -493,6 +568,45 @@ class CandidateList {
     Common.toggleModal("candidateList-modal", "candidateList-modal-card");
   }
 
+  async cloneCandidateListModal() {
+    let election = await this.ElectionModel.getElection(this.area.ID);
+    let rounds = await this.RoundModel.getRounds();
+    rounds = rounds.filter((round) => round.ElectionID == election.ID);
+    let roundsID = [];
+    rounds.forEach((round) => {
+      if (this.round.ID !== round.ID) roundsID.push(round.ID);
+    });
+    let candidateLists = await this.CandidateListModel.getCandidateLists();
+    candidateLists = candidateLists.filter(
+      (candidateList) =>
+        candidateList.AreaID == this.area.ID &&
+        roundsID.includes(candidateList.RoundID)
+    );
+    Common.toggleModal(
+      "candidateList-clone-modal",
+      "candidateList-clone-modal-card"
+    );
+
+    const markup = candidateLists
+      .map((candidateList) => this.candidateListToCloneTemplate(candidateList))
+      .join("");
+    document.getElementById("candidateLists-toclone").innerHTML = markup;
+
+    candidateLists.map((candidateList) => {
+      document
+        .getElementById(
+          `candidateLists-candidateListToClone-${candidateList.ID}`
+        )
+        .addEventListener("click", async () => {
+          this.cloneCandidateList(candidateList);
+          Common.toggleModal(
+            "candidateList-clone-modal",
+            "candidateList-clone-modal-card"
+          );
+        });
+    });
+  }
+
   async editCandidateList(candidateList) {
     this.method = "PUT";
     await this.refreshParties();
@@ -573,6 +687,37 @@ class CandidateList {
     await this.displayCandidates();
   }
 
+  async cloneCandidateList(candidateList) {
+    console.log(candidateList);
+
+    let candidateListCloned = await this.CandidateListModel.saveCandidateList(
+      "POST",
+      null,
+      candidateList.Name,
+      candidateList.PartyID,
+      this.round.ID,
+      this.area.ID
+    );
+
+    for (let i in candidateList.Candidates) {
+      await this.CandidateModel.saveCandidate(
+        "POST",
+        null,
+        candidateListCloned.ID,
+        candidateList.Candidates[i].FullName,
+        candidateList.Candidates[i].Rank,
+        candidateList.Candidates[i].CommunityCounseller,
+        candidateList.Candidates[i].Birthdate,
+        candidateList.Candidates[i].PotentialIncompatibility,
+        candidateList.Candidates[i].Refused,
+        candidateList.Candidates[i].Removed
+      );
+    }
+    await this.displayCandidateLists();
+    this.activateCandidateList(candidateListCloned);
+    return candidateListCloned;
+  }
+
   emptyCandidateList() {
     this.area = null;
     document.getElementById("candidate-lists-list").innerHTML = "";
diff --git a/web/components/management/round.js b/web/components/management/round.js
index 2cbfbdf..8303612 100644
--- a/web/components/management/round.js
+++ b/web/components/management/round.js
@@ -35,6 +35,7 @@ class Round {
       <div class="modal" id="round-modal"></div>
       <div class="modal" id="capturers-modal"></div>
       <div class="modal" id="candidateList-modal"></div>
+      <div class="modal" id="candidateList-clone-modal"></div>
     `;
     this.roundsHandler = await RoundsCard.mount("rounds-list", this);
     this.deskRoundsHandler = await RoundDesks.mount("round-desks", this);
-- 
GitLab