From b051dd59f866c67106b29db0855d7696d557c8ec Mon Sep 17 00:00:00 2001
From: Olivier PEREZ <olivier@olivierperez.fr>
Date: Sat, 28 Feb 2015 19:18:59 +0100
Subject: [PATCH] Implement purge in 2 steps

First: Block the poll (no more modification)
Second: Delete the poll 60 days after the expiration date (configurable)
---
 admin/purge.php                               | 56 +++++++++++++++++++
 adminstuds.php                                |  2 +
 app/classes/Framadate/FramaDB.php             |  2 +-
 .../Framadate/Services/AdminPollService.php   |  2 +-
 .../Framadate/Services/PurgeService.php       |  2 +-
 app/inc/config.template.php                   |  3 +
 studs.php                                     |  2 +
 tpl/admin/index.tpl                           |  3 +
 tpl/admin/purge.tpl                           | 13 +++++
 tpl/part/comments.tpl                         |  4 +-
 tpl/part/poll_info.tpl                        | 48 +++++++++-------
 tpl/part/vote_table_classic.tpl               |  6 +-
 tpl/part/vote_table_date.tpl                  |  8 +--
 tpl/studs.tpl                                 | 14 +++--
 14 files changed, 128 insertions(+), 37 deletions(-)
 create mode 100644 admin/purge.php
 create mode 100644 tpl/admin/purge.tpl

diff --git a/admin/purge.php b/admin/purge.php
new file mode 100644
index 00000000..b97dcb2d
--- /dev/null
+++ b/admin/purge.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondate: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+
+use Framadate\Services\LogService;
+use Framadate\Services\PurgeService;
+use Framadate\Services\SecurityService;
+use Framadate\Utils;
+
+include_once __DIR__ . '/../app/inc/init.php';
+include_once __DIR__ . '/../bandeaux.php';
+
+/* Variables */
+/* --------- */
+
+$message = null;
+
+/* Services */
+/*----------*/
+
+$logService = new LogService();
+$purgeService = new PurgeService($connect, $logService);
+$securityService = new SecurityService();
+
+/* POST */
+/*-----*/
+$action = filter_input(INPUT_POST, 'action', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => NAME_REGEX]]);
+
+/* PAGE */
+/* ---- */
+
+if ($action === 'purge' && $securityService->checkCsrf('admin', $_POST['csrf'])) {
+    $count = $purgeService->purgeOldPolls();
+    $message = _('Purged:') . ' ' . $count;
+}
+
+// Assign data to template
+$smarty->assign('message', $message);
+$smarty->assign('crsf', $securityService->getToken('admin'));
+
+$smarty->display('admin/purge.tpl');
\ No newline at end of file
diff --git a/adminstuds.php b/adminstuds.php
index 2fb5ac9f..f8501dda 100644
--- a/adminstuds.php
+++ b/adminstuds.php
@@ -364,6 +364,8 @@ $smarty->assign('poll_id', $poll_id);
 $smarty->assign('admin_poll_id', $admin_poll_id);
 $smarty->assign('poll', $poll);
 $smarty->assign('title', _('Poll') . ' - ' . $poll->title);
+$smarty->assign('expired', strtotime($poll->end_date) < time());
+$smarty->assign('deletion_date', $poll->end_date + PURGE_DELAY * 86400);
 $smarty->assign('slots', $poll->format === 'D' ? $pollService->splitSlots($slots) : $slots);
 $smarty->assign('votes', $pollService->splitVotes($votes));
 $smarty->assign('best_choices', $pollService->computeBestChoices($votes));
diff --git a/app/classes/Framadate/FramaDB.php b/app/classes/Framadate/FramaDB.php
index 78b6680d..6b7c4c37 100644
--- a/app/classes/Framadate/FramaDB.php
+++ b/app/classes/Framadate/FramaDB.php
@@ -270,7 +270,7 @@ class FramaDB {
      * @return array Array of old polls
      */
     public function findOldPolls() {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE end_date < NOW() AND end_date != 0 LIMIT 20');
+        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE DATE_ADD(`end_date`, INTERVAL ' . PURGE_DELAY . ' DAY) < NOW() AND `end_date` != 0 LIMIT 20');
         $prepared->execute([]);
 
         return $prepared->fetchAll();
diff --git a/app/classes/Framadate/Services/AdminPollService.php b/app/classes/Framadate/Services/AdminPollService.php
index a346de2a..70699bbb 100644
--- a/app/classes/Framadate/Services/AdminPollService.php
+++ b/app/classes/Framadate/Services/AdminPollService.php
@@ -23,7 +23,7 @@ class AdminPollService {
 
     function updatePoll($poll) {
         global $config;
-        if ($poll->end_date <= strtotime($poll->creation_date) + (86400 * $config['default_poll_duration'])) {
+        if ($poll->end_date > $poll->creation_date && $poll->end_date <= strtotime($poll->creation_date) + (86400 * $config['default_poll_duration'])) {
             return $this->connect->updatePoll($poll);
         } else {
             return false;
diff --git a/app/classes/Framadate/Services/PurgeService.php b/app/classes/Framadate/Services/PurgeService.php
index c9fd7d3a..fc05365b 100644
--- a/app/classes/Framadate/Services/PurgeService.php
+++ b/app/classes/Framadate/Services/PurgeService.php
@@ -38,7 +38,7 @@ class PurgeService {
             }
         }
 
-        return false;
+        return $count;
     }
 
     /**
diff --git a/app/inc/config.template.php b/app/inc/config.template.php
index c840737c..0c497043 100644
--- a/app/inc/config.template.php
+++ b/app/inc/config.template.php
@@ -70,6 +70,9 @@ const USE_REMOTE_USER =  true;
 // Path to the log file
 const LOG_FILE = 'admin/stdout.log';
 
+// Days (after expiration date) before purge a poll
+const PURGE_DELAY = 60;
+
 // Config
 $config = [
     /* general config */
diff --git a/studs.php b/studs.php
index d0c5798e..ddfc2b34 100644
--- a/studs.php
+++ b/studs.php
@@ -194,6 +194,8 @@ $comments = $pollService->allCommentsByPollId($poll_id);
 $smarty->assign('poll_id', $poll_id);
 $smarty->assign('poll', $poll);
 $smarty->assign('title', _('Poll') . ' - ' . $poll->title);
+$smarty->assign('expired', $poll->end_date < time());
+$smarty->assign('deletion_date', $poll->end_date + PURGE_DELAY * 86400);
 $smarty->assign('slots', $poll->format === 'D' ? $pollService->splitSlots($slots) : $slots);
 $smarty->assign('votes', $pollService->splitVotes($votes));
 $smarty->assign('best_choices', $pollService->computeBestChoices($votes));
diff --git a/tpl/admin/index.tpl b/tpl/admin/index.tpl
index 26841f3c..a2453d3f 100644
--- a/tpl/admin/index.tpl
+++ b/tpl/admin/index.tpl
@@ -8,6 +8,9 @@
     <div class="col-md-6 col-xs-12">
         <a href="./migration.php"><h2>{_('Migration')}</h2></a>
     </div>
+    <div class="col-md-6 col-xs-12">
+        <a href="./purge.php"><h2>{_('Purge')}</h2></a>
+    </div>
     {if $logsAreReadable}
         <div class="col-md-6 col-xs-12">
             <a href="./logs.php"><h2>{_('Logs')}</h2></a>
diff --git a/tpl/admin/purge.tpl b/tpl/admin/purge.tpl
new file mode 100644
index 00000000..d36553d2
--- /dev/null
+++ b/tpl/admin/purge.tpl
@@ -0,0 +1,13 @@
+{extends 'admin/admin_page.tpl'}
+
+{block 'admin_main'}
+    {if $message}
+        <div class="alert alert-dismissible alert-info" role="alert">{$message|html}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>
+    {/if}
+    <form action="" method="POST">
+        <input type="hidden" name="csrf" value="{$crsf}"/>
+        <div class="text-center">
+            <button type="submit" name="action" value="purge" class="btn btn-warning">{_('Purge all polls')} <span class="glyphicon glyphicon-trash text-danger"></span><span class="sr-only">{_('Purge all polls')}</span></button>
+        </div>
+    </form>
+{/block}
\ No newline at end of file
diff --git a/tpl/part/comments.tpl b/tpl/part/comments.tpl
index 87a8be61..5923cc9e 100644
--- a/tpl/part/comments.tpl
+++ b/tpl/part/comments.tpl
@@ -7,7 +7,7 @@
         <h3>{_("Comments of polled people")}</h3>
         {foreach $comments as $comment}
             <div class="comment">
-                {if $admin}
+                {if $admin && !$expired}
                     <button type="submit" name="delete_comment" value="{$comment->id|html}" class="btn btn-link" title="{_('Remove the comment')}"><span class="glyphicon glyphicon-remove text-danger"></span><span class="sr-only">{_('Remove')}</span></button>
                 {/if}
                 <b>{$comment->name|html}</b>&nbsp;
@@ -17,7 +17,7 @@
     {/if}
 
     {* Add comment form *}
-    {if $active}
+    {if $active && !$expired}
         <div class="hidden-print alert alert-info">
             <div class="col-md-6 col-md-offset-3">
                 <fieldset id="add-comment"><legend>{_("Add a comment to the poll")}</legend>
diff --git a/tpl/part/poll_info.tpl b/tpl/part/poll_info.tpl
index 7c1b220b..360e09aa 100644
--- a/tpl/part/poll_info.tpl
+++ b/tpl/part/poll_info.tpl
@@ -4,8 +4,8 @@
     <div class="jumbotron{if $admin} bg-danger{/if}">
         <div class="row">
             <div id="title-form" class="col-md-7">
-                <h3>{$poll->title|html}{if $admin} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the title')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</h3>
-                {if $admin}
+                <h3>{$poll->title|html}{if $admin && !$expired} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the title')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</h3>
+                {if $admin && !$expired}
                     <div class="hidden js-title">
                         <label class="sr-only" for="newtitle">{_('Title')}</label>
                         <div class="input-group">
@@ -22,7 +22,7 @@
                 <div class="btn-group pull-right">
                     <button onclick="print(); return false;" class="btn btn-default"><span class="glyphicon glyphicon-print"></span> {_('Print')}</button>
                     <a href="{$SERVER_URL|html}exportcsv.php?poll={$poll_id|html}" class="btn btn-default"><span class="glyphicon glyphicon-download-alt"></span> {_('Export to CSV')}</a>
-                    {if $admin}
+                    {if $admin && !$expired}
                         <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
                             <span class="glyphicon glyphicon-trash"></span> <span class="sr-only">{_("Remove")}</span> <span class="caret"></span>
                         </button>
@@ -39,8 +39,8 @@
         <div class="row">
             <div id="name-form" class="form-group col-md-5">
                 <h4 class="control-label">{_('Initiator of the poll')}</h4>
-                <p class="form-control-static">{$poll->admin_name|html}{if $admin} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the initiator')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</p>
-                {if $admin}
+                <p class="form-control-static">{$poll->admin_name|html}{if $admin && !$expired} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the initiator')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</p>
+                {if $admin && !$expired}
                 <div class="hidden js-name">
                     <label class="sr-only" for="newname">{_('Initiator of the poll')}</label>
                     <div class="input-group">
@@ -51,12 +51,15 @@
                         </span>
                     </div>
                 </div>
+                {/if}
             </div>
         </div>
         <div class="row">
+            {if $admin}
             <div class="form-group col-md-5">
                 <div id="email-form">
-                    <p>{$poll->admin_mail|html} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the email adress')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button></p>
+                    <p>{$poll->admin_mail|html}{if !$expired} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the email adress')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</p>
+                    {if !$expired}
                     <div class="hidden js-email">
                         <label class="sr-only" for="admin_mail">{_('Email adress')}</label>
                         <div class="input-group">
@@ -67,21 +70,22 @@
                             </span>
                         </div>
                     </div>
+                    {/if}
                 </div>
-                {/if}
             </div>
-            {if !empty($poll->comment)}
-                <div class="form-group col-md-7" id="description-form">
-                    <h4 class="control-label">{_("Description")}{if $admin}<button class="btn btn-link btn-sm btn-edit" title="{_('Edit the description')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</h4>
-                    <p class="form-control-static well">{$poll->comment|html}</p>
-                    <div class="hidden js-desc text-right">
-                        <label class="sr-only" for="newdescription">{_('Description')}</label>
-                        <textarea class="form-control" id="newdescription" name="comment" rows="2" cols="40">{$poll->comment|html}</textarea>
-                        <button type="submit" id="btn-new-desc" name="update_poll_info" value="comment" class="btn btn-sm btn-success" title="{_('Save the description')}"><span class="glyphicon glyphicon-ok"></span><span class="sr-only">{_('Save')}</span></button>
-                        <button class="btn btn-default btn-sm btn-cancel" title="{_('Cancel the description edit')}"><span class="glyphicon glyphicon-remove"></span><span class="sr-only">{_('Cancel')}</span></button>
-                    </div>
-                </div>
             {/if}
+            <div class="form-group col-md-7" id="description-form">
+                <h4 class="control-label">{_("Description")}{if $admin && !$expired} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the description')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</h4>
+                <p class="form-control-static well">{$poll->description|html}</p>
+                {if $admin && !$expired}
+                <div class="hidden js-desc text-right">
+                    <label class="sr-only" for="newdescription">{_('Description')}</label>
+                    <textarea class="form-control" id="newdescription" name="comment" rows="2" cols="40">{$poll->description|html}</textarea>
+                    <button type="submit" id="btn-new-desc" name="update_poll_info" value="comment" class="btn btn-sm btn-success" title="{_('Save the description')}"><span class="glyphicon glyphicon-ok"></span><span class="sr-only">{_('Save')}</span></button>
+                    <button class="btn btn-default btn-sm btn-cancel" title="{_('Cancel the description edit')}"><span class="glyphicon glyphicon-remove"></span><span class="sr-only">{_('Cancel')}</span></button>
+                </div>
+                {/if}
+            </div>
         </div>
 
         <div class="row">
@@ -96,8 +100,8 @@
                 </div>
                 <div id="expiration-form" class="form-group col-md-4">
                     <h4 class="control-label">{_('Expiration\'s date')}</h4>
-                    <p>{$poll->end_date|date_format:$date_format['txt_date']|html}{if $admin} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the expiration\'s date')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</p>
-                    {if $admin}
+                    <p>{$poll->end_date|date_format:$date_format['txt_date']|html}{if !$expired} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the expiration\'s date')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</p>
+                    {if !$expired}
                         <div class="hidden js-expiration">
                             <label class="sr-only" for="newexpirationdate">{_('Expiration\'s date')}</label>
                             <div class="input-group">
@@ -131,7 +135,8 @@
                             {$rule_icon = '<span class="glyphicon glyphicon-lock"></span>'}
                             {$rule_txt = _('Votes and comments are locked')}
                         {/if}
-                        <p class="">{$rule_icon} {$rule_txt|html}<button class="btn btn-link btn-sm btn-edit" title="{_('Edit the poll rules')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button></p>
+                        <p class="">{$rule_icon} {$rule_txt|html}{if !$expired} <button class="btn btn-link btn-sm btn-edit" title="{_('Edit the poll rules')}"><span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span></button>{/if}</p>
+                        {if !$expired}
                         <div class="hidden js-poll-rules">
                             <label class="sr-only" for="rules">{_('Poll rules')}</label>
                             <div class="input-group">
@@ -146,6 +151,7 @@
                                 </span>
                             </div>
                         </div>
+                        {/if}
                     </div>
                 </div>
             </div>
diff --git a/tpl/part/vote_table_classic.tpl b/tpl/part/vote_table_classic.tpl
index 60f2080b..c6dc2368 100644
--- a/tpl/part/vote_table_classic.tpl
+++ b/tpl/part/vote_table_classic.tpl
@@ -9,7 +9,7 @@
         <table class="results">
             <caption class="sr-only">{_('Votes of the poll')} {$poll->title|html}</caption>
             <thead>
-            {if $admin}
+            {if $admin && !$expired}
                 <tr class="hidden-print">
                     <th role="presentation"></th>
                     {foreach $slots as $id=>$slot}
@@ -88,7 +88,7 @@
 
                         {/foreach}
 
-                        {if $active && $poll->editable}
+                        {if $active && $poll->editable && !$expired}
                             <td>
                                 <button type="submit" class="btn btn-link btn-sm" name="edit_vote" value="{$vote->id|html}" title="{_('Edit the line:')} {$vote->name|html}">
                                     <span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span>
@@ -108,7 +108,7 @@
 
             {* Line to add a new vote *}
 
-            {if $active && $editingVoteId == 0}
+            {if $active && $editingVoteId == 0 && !$expired}
                 <tr id="vote-form">
                     <td class="bg-info" style="padding:5px">
                         <div class="input-group input-group-sm">
diff --git a/tpl/part/vote_table_date.tpl b/tpl/part/vote_table_date.tpl
index 6ae6bdb9..3343243f 100644
--- a/tpl/part/vote_table_date.tpl
+++ b/tpl/part/vote_table_date.tpl
@@ -9,7 +9,7 @@
         <table class="results">
             <caption class="sr-only">{_('Votes of the poll')} {$poll->title|html}</caption>
             <thead>
-            {if $admin}
+            {if $admin && !$expired}
                 <tr class="hidden-print">
                     <th role="presentation"></th>
                     {$headersDCount=0}
@@ -79,7 +79,7 @@
                 <tr>
                     {* Edited line *}
 
-                    {if $editingVoteId == $vote->id}
+                    {if $editingVoteId == $vote->id && !$expired}
 
                         <td class="bg-info" style="padding:5px">
                             <div class="input-group input-group-sm">
@@ -132,7 +132,7 @@
 
                         {/foreach}
 
-                        {if $active && $poll->editable}
+                        {if $active && $poll->editable && !$expired}
                             <td>
                                 <button type="submit" class="btn btn-link btn-sm" name="edit_vote" value="{$vote->id|html}" title="{_('Edit the line:')} {$vote->name|html}">
                                     <span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span>
@@ -152,7 +152,7 @@
 
             {* Line to add a new vote *}
 
-            {if $active && $editingVoteId == 0}
+            {if $active && $editingVoteId == 0 && !$expired}
                 <tr id="vote-form">
                     <td class="bg-info" style="padding:5px">
                         <div class="input-group input-group-sm">
diff --git a/tpl/studs.tpl b/tpl/studs.tpl
index ccd872a1..c4280fe9 100644
--- a/tpl/studs.tpl
+++ b/tpl/studs.tpl
@@ -11,11 +11,17 @@
 {include 'part/poll_info.tpl' admin=$admin}
 
 {* Information about voting *}
-
-{if $admin}
-    {include 'part/poll_hint_admin.tpl'}
+{if $expired}
+    <div class="alert alert-danger">
+        <p>{_('The poll is expired, it will be deleted soon.')}</p>
+        <p>{_('Deletion date:')} {$deletion_date|date_format:$date_format['txt_short']|html}</p>
+    </div>
 {else}
-    {include 'part/poll_hint.tpl' active=$poll->active}
+    {if $admin}
+        {include 'part/poll_hint_admin.tpl'}
+    {else}
+        {include 'part/poll_hint.tpl' active=$poll->active}
+    {/if}
 {/if}
 
 {* Scroll left and right *}
-- 
GitLab