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">×</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> @@ -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