diff --git a/admin/purge.php b/admin/purge.php new file mode 100644 index 0000000000000000000000000000000000000000..b97dcb2df93d49a6faab9def3b02440d0948eb2c --- /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 2fb5ac9fa28b4bad9dbfa8f4c23fdb6e650b1c18..f8501dda804dbbf391b019ab942ff4636db24edc 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 78b6680dad0a8a0698398204f88fedbec9813e42..6b7c4c37f2b61171903bca8b206364eaa400cb6f 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 a346de2a5ffbd1d00589c6304eca6d083feebcf0..70699bbb62d11a0f4af77a0853fb8adc59ce55a6 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 c9fd7d3a609e9092157d9b16f0b6b54aa9c53841..fc05365ba4eb576dfc335f188d35279fb43df4cc 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 c840737c298d56e907fcf1c1abb45d0492ff3915..0c49704351942694aa96043c35eca051f6d6cd94 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 d0c5798e3adfda4c1059beb64566440dbd07fff0..ddfc2b3410c401ae9518fb6a0756572dd0f68ff7 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 26841f3c30ac71480129d4597e88f354ff9a4eac..a2453d3f52fc8649885cb28168cf29c1358d94b6 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 0000000000000000000000000000000000000000..d36553d2dbadb633ad300256065c2bf68ca71f6a --- /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 87a8be6104ad654ec6841efd1efab4baeedaf155..5923cc9e9862cebd657801521452621649f99db3 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 7c1b220bb84d584075edab0296de03541f5a90d9..360e09aa350a7b3405b92b4a5efbab8f6fb66d16 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 60f2080b61f32c34937802c7afe09fb4001f0a43..c6dc236820dbf4cc35a11129ebfb6c4cbae3a2f0 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 6ae6bdb93ccc1f41c3d34c3ecd39d7747569dd7e..3343243f1fec92896c8886a4d90201935733c867 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 ccd872a1bd610a7e5780c104527012f9eb114a48..c4280fe9e374a7473714a25ae7847aa07b750c4e 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 *}