Implement purge in 2 steps

First: Block the poll (no more modification)
Second: Delete the poll 60 days after the expiration date (configurable)
This commit is contained in:
Olivier PEREZ 2015-02-28 19:18:59 +01:00
parent 6e442e02e3
commit b051dd59f8
14 changed files with 128 additions and 37 deletions

56
admin/purge.php Normal file
View File

@ -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');

View File

@ -364,6 +364,8 @@ $smarty->assign('poll_id', $poll_id);
$smarty->assign('admin_poll_id', $admin_poll_id); $smarty->assign('admin_poll_id', $admin_poll_id);
$smarty->assign('poll', $poll); $smarty->assign('poll', $poll);
$smarty->assign('title', _('Poll') . ' - ' . $poll->title); $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('slots', $poll->format === 'D' ? $pollService->splitSlots($slots) : $slots);
$smarty->assign('votes', $pollService->splitVotes($votes)); $smarty->assign('votes', $pollService->splitVotes($votes));
$smarty->assign('best_choices', $pollService->computeBestChoices($votes)); $smarty->assign('best_choices', $pollService->computeBestChoices($votes));

View File

@ -270,7 +270,7 @@ class FramaDB {
* @return array Array of old polls * @return array Array of old polls
*/ */
public function findOldPolls() { 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([]); $prepared->execute([]);
return $prepared->fetchAll(); return $prepared->fetchAll();

View File

@ -23,7 +23,7 @@ class AdminPollService {
function updatePoll($poll) { function updatePoll($poll) {
global $config; 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); return $this->connect->updatePoll($poll);
} else { } else {
return false; return false;

View File

@ -38,7 +38,7 @@ class PurgeService {
} }
} }
return false; return $count;
} }
/** /**

View File

@ -70,6 +70,9 @@ const USE_REMOTE_USER = true;
// Path to the log file // Path to the log file
const LOG_FILE = 'admin/stdout.log'; const LOG_FILE = 'admin/stdout.log';
// Days (after expiration date) before purge a poll
const PURGE_DELAY = 60;
// Config // Config
$config = [ $config = [
/* general config */ /* general config */

View File

@ -194,6 +194,8 @@ $comments = $pollService->allCommentsByPollId($poll_id);
$smarty->assign('poll_id', $poll_id); $smarty->assign('poll_id', $poll_id);
$smarty->assign('poll', $poll); $smarty->assign('poll', $poll);
$smarty->assign('title', _('Poll') . ' - ' . $poll->title); $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('slots', $poll->format === 'D' ? $pollService->splitSlots($slots) : $slots);
$smarty->assign('votes', $pollService->splitVotes($votes)); $smarty->assign('votes', $pollService->splitVotes($votes));
$smarty->assign('best_choices', $pollService->computeBestChoices($votes)); $smarty->assign('best_choices', $pollService->computeBestChoices($votes));

View File

@ -8,6 +8,9 @@
<div class="col-md-6 col-xs-12"> <div class="col-md-6 col-xs-12">
<a href="./migration.php"><h2>{_('Migration')}</h2></a> <a href="./migration.php"><h2>{_('Migration')}</h2></a>
</div> </div>
<div class="col-md-6 col-xs-12">
<a href="./purge.php"><h2>{_('Purge')}</h2></a>
</div>
{if $logsAreReadable} {if $logsAreReadable}
<div class="col-md-6 col-xs-12"> <div class="col-md-6 col-xs-12">
<a href="./logs.php"><h2>{_('Logs')}</h2></a> <a href="./logs.php"><h2>{_('Logs')}</h2></a>

13
tpl/admin/purge.tpl Normal file
View File

@ -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}

View File

@ -7,7 +7,7 @@
<h3>{_("Comments of polled people")}</h3> <h3>{_("Comments of polled people")}</h3>
{foreach $comments as $comment} {foreach $comments as $comment}
<div class="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> <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} {/if}
<b>{$comment->name|html}</b>&nbsp; <b>{$comment->name|html}</b>&nbsp;
@ -17,7 +17,7 @@
{/if} {/if}
{* Add comment form *} {* Add comment form *}
{if $active} {if $active && !$expired}
<div class="hidden-print alert alert-info"> <div class="hidden-print alert alert-info">
<div class="col-md-6 col-md-offset-3"> <div class="col-md-6 col-md-offset-3">
<fieldset id="add-comment"><legend>{_("Add a comment to the poll")}</legend> <fieldset id="add-comment"><legend>{_("Add a comment to the poll")}</legend>

View File

@ -4,8 +4,8 @@
<div class="jumbotron{if $admin} bg-danger{/if}"> <div class="jumbotron{if $admin} bg-danger{/if}">
<div class="row"> <div class="row">
<div id="title-form" class="col-md-7"> <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> <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} {if $admin && !$expired}
<div class="hidden js-title"> <div class="hidden js-title">
<label class="sr-only" for="newtitle">{_('Title')}</label> <label class="sr-only" for="newtitle">{_('Title')}</label>
<div class="input-group"> <div class="input-group">
@ -22,7 +22,7 @@
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<button onclick="print(); return false;" class="btn btn-default"><span class="glyphicon glyphicon-print"></span> {_('Print')}</button> <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> <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"> <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> <span class="glyphicon glyphicon-trash"></span> <span class="sr-only">{_("Remove")}</span> <span class="caret"></span>
</button> </button>
@ -39,8 +39,8 @@
<div class="row"> <div class="row">
<div id="name-form" class="form-group col-md-5"> <div id="name-form" class="form-group col-md-5">
<h4 class="control-label">{_('Initiator of the poll')}</h4> <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> <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} {if $admin && !$expired}
<div class="hidden js-name"> <div class="hidden js-name">
<label class="sr-only" for="newname">{_('Initiator of the poll')}</label> <label class="sr-only" for="newname">{_('Initiator of the poll')}</label>
<div class="input-group"> <div class="input-group">
@ -51,12 +51,15 @@
</span> </span>
</div> </div>
</div> </div>
{/if}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
{if $admin}
<div class="form-group col-md-5"> <div class="form-group col-md-5">
<div id="email-form"> <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"> <div class="hidden js-email">
<label class="sr-only" for="admin_mail">{_('Email adress')}</label> <label class="sr-only" for="admin_mail">{_('Email adress')}</label>
<div class="input-group"> <div class="input-group">
@ -67,22 +70,23 @@
</span> </span>
</div> </div>
</div> </div>
</div>
{/if} {/if}
</div> </div>
{if !empty($poll->comment)} </div>
{/if}
<div class="form-group col-md-7" id="description-form"> <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> <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->comment|html}</p> <p class="form-control-static well">{$poll->description|html}</p>
{if $admin && !$expired}
<div class="hidden js-desc text-right"> <div class="hidden js-desc text-right">
<label class="sr-only" for="newdescription">{_('Description')}</label> <label class="sr-only" for="newdescription">{_('Description')}</label>
<textarea class="form-control" id="newdescription" name="comment" rows="2" cols="40">{$poll->comment|html}</textarea> <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 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> <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>
</div>
{/if} {/if}
</div> </div>
</div>
<div class="row"> <div class="row">
<div class="form-group form-group {if $admin}col-md-4{else}col-md-6{/if}"> <div class="form-group form-group {if $admin}col-md-4{else}col-md-6{/if}">
@ -96,8 +100,8 @@
</div> </div>
<div id="expiration-form" class="form-group col-md-4"> <div id="expiration-form" class="form-group col-md-4">
<h4 class="control-label">{_('Expiration\'s date')}</h4> <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> <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 $admin} {if !$expired}
<div class="hidden js-expiration"> <div class="hidden js-expiration">
<label class="sr-only" for="newexpirationdate">{_('Expiration\'s date')}</label> <label class="sr-only" for="newexpirationdate">{_('Expiration\'s date')}</label>
<div class="input-group"> <div class="input-group">
@ -131,7 +135,8 @@
{$rule_icon = '<span class="glyphicon glyphicon-lock"></span>'} {$rule_icon = '<span class="glyphicon glyphicon-lock"></span>'}
{$rule_txt = _('Votes and comments are locked')} {$rule_txt = _('Votes and comments are locked')}
{/if} {/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"> <div class="hidden js-poll-rules">
<label class="sr-only" for="rules">{_('Poll rules')}</label> <label class="sr-only" for="rules">{_('Poll rules')}</label>
<div class="input-group"> <div class="input-group">
@ -146,6 +151,7 @@
</span> </span>
</div> </div>
</div> </div>
{/if}
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,7 +9,7 @@
<table class="results"> <table class="results">
<caption class="sr-only">{_('Votes of the poll')} {$poll->title|html}</caption> <caption class="sr-only">{_('Votes of the poll')} {$poll->title|html}</caption>
<thead> <thead>
{if $admin} {if $admin && !$expired}
<tr class="hidden-print"> <tr class="hidden-print">
<th role="presentation"></th> <th role="presentation"></th>
{foreach $slots as $id=>$slot} {foreach $slots as $id=>$slot}
@ -88,7 +88,7 @@
{/foreach} {/foreach}
{if $active && $poll->editable} {if $active && $poll->editable && !$expired}
<td> <td>
<button type="submit" class="btn btn-link btn-sm" name="edit_vote" value="{$vote->id|html}" title="{_('Edit the line:')} {$vote->name|html}"> <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> <span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span>
@ -108,7 +108,7 @@
{* Line to add a new vote *} {* Line to add a new vote *}
{if $active && $editingVoteId == 0} {if $active && $editingVoteId == 0 && !$expired}
<tr id="vote-form"> <tr id="vote-form">
<td class="bg-info" style="padding:5px"> <td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">

View File

@ -9,7 +9,7 @@
<table class="results"> <table class="results">
<caption class="sr-only">{_('Votes of the poll')} {$poll->title|html}</caption> <caption class="sr-only">{_('Votes of the poll')} {$poll->title|html}</caption>
<thead> <thead>
{if $admin} {if $admin && !$expired}
<tr class="hidden-print"> <tr class="hidden-print">
<th role="presentation"></th> <th role="presentation"></th>
{$headersDCount=0} {$headersDCount=0}
@ -79,7 +79,7 @@
<tr> <tr>
{* Edited line *} {* Edited line *}
{if $editingVoteId == $vote->id} {if $editingVoteId == $vote->id && !$expired}
<td class="bg-info" style="padding:5px"> <td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
@ -132,7 +132,7 @@
{/foreach} {/foreach}
{if $active && $poll->editable} {if $active && $poll->editable && !$expired}
<td> <td>
<button type="submit" class="btn btn-link btn-sm" name="edit_vote" value="{$vote->id|html}" title="{_('Edit the line:')} {$vote->name|html}"> <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> <span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{_('Edit')}</span>
@ -152,7 +152,7 @@
{* Line to add a new vote *} {* Line to add a new vote *}
{if $active && $editingVoteId == 0} {if $active && $editingVoteId == 0 && !$expired}
<tr id="vote-form"> <tr id="vote-form">
<td class="bg-info" style="padding:5px"> <td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">

View File

@ -11,11 +11,17 @@
{include 'part/poll_info.tpl' admin=$admin} {include 'part/poll_info.tpl' admin=$admin}
{* Information about voting *} {* Information about voting *}
{if $expired}
{if $admin} <div class="alert alert-danger">
{include 'part/poll_hint_admin.tpl'} <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} {else}
{if $admin}
{include 'part/poll_hint_admin.tpl'}
{else}
{include 'part/poll_hint.tpl' active=$poll->active} {include 'part/poll_hint.tpl' active=$poll->active}
{/if}
{/if} {/if}
{* Scroll left and right *} {* Scroll left and right *}