Merge branch 'release/0.9' into develop

This commit is contained in:
Olivier PEREZ 2015-06-09 11:18:43 +02:00
commit 9ef15cc4e7
44 changed files with 1464 additions and 281 deletions

View File

@ -18,6 +18,7 @@
- Amélioration : Mise à jour des fichiers .md pour faciliter la collaboration
- Amélioration : Le nom de l'auteur et la date d'expiration sont modifiables
- Amélioration : Le nom de vote est modifiable
- Amélioration : Affichage du comptage des "Si nécessaire" entre parenthèses
- Fix : Purge en 2 étapes → 1. Verrouillage du sondage → 2. 60 jours plus tard suppression du sondage
- Fix : Date d'expiration qui devient nulle quand on ajoute une colonne
- Fix : clic/focus sur oui/non/si nécessaire → retour à gauche de la barre de scroll sur Chromium

View File

@ -21,7 +21,6 @@ use Framadate\Services\InputService;
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';

View File

@ -16,15 +16,22 @@
* 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\PollService;
use Framadate\Editable;
use Framadate\Message;
use Framadate\Services\AdminPollService;
use Framadate\Services\InputService;
use Framadate\Services\LogService;
use Framadate\Message;
use Framadate\Editable;
use Framadate\Services\MailService;
use Framadate\Services\PollService;
use Framadate\Utils;
include_once __DIR__ . '/app/inc/init.php';
/* Constants */
/* --------- */
const UPDATE_POLL = 1;
const DELETED_POLL = 2;
/* Variables */
/* --------- */
@ -41,6 +48,41 @@ $logService = new LogService();
$pollService = new PollService($connect, $logService);
$adminPollService = new AdminPollService($connect, $pollService, $logService);
$inputService = new InputService();
$mailService = new MailService($config['use_smtp']);
/* Functions */
/*-----------*/
/**
* Send a notification to the poll admin to notify him about an update.
*
* @param stdClass $poll The poll
* @param MailService $mailService The mail service
* @param int $type cf: Constants on the top of this page
*/
function sendUpdateNotification($poll, $mailService, $type) {
if (!isset($_SESSION['mail_sent'])) {
$_SESSION['mail_sent'] = [];
}
if ($poll->receiveNewVotes) {
$subject = '[' . NOMAPPLICATION . '] ' . __('Mail', 'Notification of poll') . ' : ' . $poll->title;
$message = '';
switch ($type) {
case UPDATE_POLL:
$message = __f('Mail', 'Someone just change your poll available at the following link %s.', Utils::getUrlSondage($poll->admin_id, true)) . "\n\n";
break;
case DELETED_POLL:
$message = __f('Mail', 'Someone just delete your poll %s.', Utils::htmlEscape($poll->title)) . "\n\n";
break;
}
$messageTypeKey = $type . '-' . $poll->id;
$mailService->send($poll->admin_mail, $subject, $message, $messageTypeKey);
}
}
/* PAGE */
/* ---- */
@ -111,7 +153,8 @@ if (isset($_POST['update_poll_info'])) {
break;
}
} elseif ($field == 'expiration_date') {
$expiration_date = filter_input(INPUT_POST, 'expiration_date', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '#^[0-9]+[-/][0-9]+[-/][0-9]+#']]);
$expiration_date = filter_input(INPUT_POST, 'expiration_date', FILTER_VALIDATE_REGEXP,
['options' => ['regexp' => '#^[0-9]{4}-[0-9]{2}-[0-9]{2}$#']]);
if ($expiration_date) {
$poll->end_date = $expiration_date;
$updated = true;
@ -133,6 +176,7 @@ if (isset($_POST['update_poll_info'])) {
// Update poll in database
if ($updated && $adminPollService->updatePoll($poll)) {
$message = new Message('success', __('adminstuds', 'Poll saved'));
sendUpdateNotification($poll, $mailService, UPDATE_POLL);
} else {
$message = new Message('danger', __('Error', 'Failed to save poll'));
$poll = $pollService->findById($poll_id);
@ -297,6 +341,7 @@ if (isset($_POST['delete_poll'])) {
if (isset($_POST['confirm_delete_poll'])) {
if ($adminPollService->deleteEntirePoll($poll_id)) {
$message = new Message('success', __('adminstuds', 'Poll fully deleted'));
sendUpdateNotification($poll, $mailService, DELETED_POLL);
} else {
$message = new Message('danger', __('Error', 'Failed to delete the poll'));
}
@ -322,15 +367,15 @@ if (!empty($_GET['delete_column'])) {
$slot->title = $ex[0];
$slot->moment = $ex[1];
$result = $adminPollService->deleteDateSlot($poll_id, $slot);
$result = $adminPollService->deleteDateSlot($poll, $slot);
} else {
$result = $adminPollService->deleteClassicSlot($poll_id, $column);
$result = $adminPollService->deleteClassicSlot($poll, $column);
}
if ($result) {
$message = new Message('success', __('adminstuds', 'Column removed'));
} else {
$message = new Message('danger', __('Error', 'Failed to delete the column'));
$message = new Message('danger', __('Error', 'Failed to delete column'));
}
}
@ -352,10 +397,10 @@ if (isset($_POST['confirm_add_slot'])) {
$newmoment = strip_tags($_POST['newmoment']);
$ex = explode('/', $newdate);
$result = $adminPollService->addSlot($poll_id, mktime(0, 0, 0, $ex[1], $ex[0], $ex[2]), $newmoment);
$result = $adminPollService->addDateSlot($poll_id, mktime(0, 0, 0, $ex[1], $ex[0], $ex[2]), $newmoment);
} else {
$newslot = strip_tags($_POST['choice']);
$result = $adminPollService->addSlot($poll_id, $newslot, null);
$result = $adminPollService->addClassicSlot($poll_id, $newslot);
}
if ($result) {
@ -366,7 +411,7 @@ if (isset($_POST['confirm_add_slot'])) {
}
// Retrieve data
$slots = $pollService->allSlotsByPollId($poll_id);
$slots = $pollService->allSlotsByPoll($poll);
$votes = $pollService->allVotesByPollId($poll_id);
$comments = $pollService->allCommentsByPollId($poll_id);
@ -377,7 +422,7 @@ $smarty->assign('admin_poll_id', $admin_poll_id);
$smarty->assign('poll', $poll);
$smarty->assign('title', __('Generic', 'Poll') . ' - ' . $poll->title);
$smarty->assign('expired', strtotime($poll->end_date) < time());
$smarty->assign('deletion_date', $poll->end_date + PURGE_DELAY * 86400);
$smarty->assign('deletion_date', strtotime($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));

View File

@ -18,8 +18,6 @@
*/
namespace Framadate;
use Framadate\Editable;
class Form
{

View File

@ -61,7 +61,7 @@ class SlotRepository extends AbstractRepository {
}
function listByPollId($poll_id) {
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('slot') . '` WHERE poll_id = ? ORDER BY title');
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('slot') . '` WHERE poll_id = ? ORDER BY id');
$prepared->execute(array($poll_id));
return $prepared->fetchAll();

View File

@ -105,17 +105,21 @@ class AdminPollService {
/**
* Delete a slot from a poll.
*
* @param $poll_id int The ID of the poll
* @param $slot object The slot informations (datetime + moment)
* @param object $poll The ID of the poll
* @param object $slot The slot informations (datetime + moment)
* @return bool true if action succeeded
*/
public function deleteDateSlot($poll_id, $slot) {
$this->logService->log('DELETE_SLOT', 'id:' . $poll_id . ', slot:' . json_encode($slot));
public function deleteDateSlot($poll, $slot) {
$this->logService->log('DELETE_SLOT', 'id:' . $poll->id . ', slot:' . json_encode($slot));
$datetime = $slot->title;
$moment = $slot->moment;
$slots = $this->pollService->allSlotsByPollId($poll_id);
$slots = $this->pollService->allSlotsByPoll($poll);
if (count($slots) === 1) {
return false;
}
$index = 0;
$indexToDelete = -1;
@ -139,21 +143,25 @@ class AdminPollService {
// Remove votes
$this->connect->beginTransaction();
$this->voteRepository->deleteByIndex($poll_id, $indexToDelete);
$this->voteRepository->deleteByIndex($poll->id, $indexToDelete);
if (count($newMoments) > 0) {
$this->slotRepository->update($poll_id, $datetime, implode(',', $newMoments));
$this->slotRepository->update($poll->id, $datetime, implode(',', $newMoments));
} else {
$this->slotRepository->deleteByDateTime($poll_id, $datetime);
$this->slotRepository->deleteByDateTime($poll->id, $datetime);
}
$this->connect->commit();
return true;
}
public function deleteClassicSlot($poll_id, $slot_title) {
$this->logService->log('DELETE_SLOT', 'id:' . $poll_id . ', slot:' . $slot_title);
public function deleteClassicSlot($poll, $slot_title) {
$this->logService->log('DELETE_SLOT', 'id:' . $poll->id . ', slot:' . $slot_title);
$slots = $this->pollService->allSlotsByPollId($poll_id);
$slots = $this->pollService->allSlotsByPoll($poll);
if (count($slots) === 1) {
return false;
}
$index = 0;
$indexToDelete = -1;
@ -168,15 +176,15 @@ class AdminPollService {
// Remove votes
$this->connect->beginTransaction();
$this->voteRepository->deleteByIndex($poll_id, $indexToDelete);
$this->slotRepository->deleteByDateTime($poll_id, $slot_title);
$this->voteRepository->deleteByIndex($poll->id, $indexToDelete);
$this->slotRepository->deleteByDateTime($poll->id, $slot_title);
$this->connect->commit();
return true;
}
/**
* Add a new slot to the poll. And insert default values for user's votes.
* Add a new slot to a date poll. And insert default values for user's votes.
* <ul>
* <li>Create a new slot if no one exists for the given date</li>
* <li>Create a new moment if a slot already exists for the given date</li>
@ -187,7 +195,7 @@ class AdminPollService {
* @param $new_moment string The moment's name
* @return bool true if added
*/
public function addSlot($poll_id, $datetime, $new_moment) {
public function addDateSlot($poll_id, $datetime, $new_moment) {
$slots = $this->slotRepository->listByPollId($poll_id);
$result = $this->findInsertPosition($slots, $datetime, $new_moment);
@ -224,6 +232,44 @@ class AdminPollService {
}
/**
* Add a new slot to a classic poll. And insert default values for user's votes.
* <ul>
* <li>Create a new slot if no one exists for the given title</li>
* </ul>
*
* @param $poll_id int The ID of the poll
* @param $title int The title
* @return bool true if added
*/
public function addClassicSlot($poll_id, $title) {
$slots = $this->slotRepository->listByPollId($poll_id);
// Check if slot already exists
$titles = array_map(function ($slot) {
return $slot->title;
}, $slots);
if (in_array($title, $titles)) {
// The moment already exists
return false;
}
// Begin transaction
$this->connect->beginTransaction();
// New slot
$this->slotRepository->insert($poll_id, $title, null);
// Set default votes
$this->voteRepository->insertDefault($poll_id, count($slots));
// Commit transaction
$this->connect->commit();
return true;
}
/**
* This method find where to insert a datatime+moment into a list of slots.<br/>
* Return the {insert:X}, where X is the index of the moment into the whole poll (ex: X=0 => Insert to the first column).

View File

@ -51,8 +51,7 @@ class InputService {
}
public function filterTitle($title) {
$filtered = filter_var($title, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => TITLE_REGEX]]);
return $this->returnIfNotBlank($filtered);
return $this->returnIfNotBlank($title);
}
public function filterName($name) {
@ -66,7 +65,7 @@ class InputService {
public function filterDescription($description) {
$description = str_replace("\r\n", "\n", $description);
return filter_var($description, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => DESCRIPTION_REGEX]]);
return $description;
}
public function filterBoolean($boolean) {
@ -79,8 +78,7 @@ class InputService {
public function filterComment($comment) {
$comment = str_replace("\r\n", "\n", $comment);
$filtered = filter_var($comment, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => COMMENT_REGEX]]);
return $this->returnIfNotBlank($filtered);
return $this->returnIfNotBlank($comment);
}
/**

View File

@ -5,7 +5,14 @@ class MailService {
private $smtp_allowed;
const DELAY_BEFORE_RESEND = 300;
const MAILSERVICE_KEY = 'mailservice';
private $logService;
function __construct($smtp_allowed) {
$this->logService = new LogService();
$this->smtp_allowed = $smtp_allowed;
}
@ -13,10 +20,12 @@ class MailService {
return filter_var($email, FILTER_VALIDATE_EMAIL);
}
function send($to, $subject, $body, $param = '') {
if ($this->smtp_allowed == true) {
function send($to, $subject, $body, $msgKey = null) {
if ($this->smtp_allowed == true && $this->canSendMsg($msgKey)) {
mb_internal_encoding('UTF-8');
// Build headers
$subject = mb_encode_mimeheader(html_entity_decode($subject, ENT_QUOTES, 'UTF-8'), 'UTF-8', 'B', "\n", 9);
$encoded_app = mb_encode_mimeheader(NOMAPPLICATION, 'UTF-8', 'B', "\n", 6);
@ -39,11 +48,38 @@ class MailService {
$headers .= "Auto-Submitted:auto-generated\n";
$headers .= 'Return-Path: <>';
// Build body
$body = $body . '<br/><br/>' . __('Mail', 'Thanks for your trust.') . '<br/>' . NOMAPPLICATION . '<hr/>' . __('Mail', 'FOOTER');
mail($to, $subject, $body, $headers, $param);
// Send mail
$this->sendMail($to, $subject, $body, $msgKey, $headers);
}
}
function canSendMsg($msgKey) {
if ($msgKey == null) {
return true;
}
if (!isset($_SESSION[self::MAILSERVICE_KEY])) {
$_SESSION[self::MAILSERVICE_KEY] = [];
}
return !isset($_SESSION[self::MAILSERVICE_KEY][$msgKey]) || time() - $_SESSION[self::MAILSERVICE_KEY][$msgKey] > self::DELAY_BEFORE_RESEND;
}
private function sendMail($to, $subject, $body, $msgKey, $headers) {
mail($to, $subject, $body, $headers, '');
// Log
$this->logService->log('MAIL', 'Mail sent to: ' . $to . ', key: ' . $msgKey);
// Store the mail sending date
$_SESSION[self::MAILSERVICE_KEY][$msgKey] = time();
}
}

View File

@ -64,8 +64,16 @@ class PollService {
return $this->voteRepository->allUserVotesByPollId($poll_id);
}
function allSlotsByPollId($poll_id) {
return $this->slotRepository->listByPollId($poll_id);
function allSlotsByPoll($poll) {
$slots = $this->slotRepository->listByPollId($poll->id);
if ($poll->format == 'D') {
uasort($slots, function ($a, $b) {
return $a->title > $b->title;
});
return $slots;
} else {
return $slots;
}
}
public function updateVote($poll_id, $vote_id, $name, $choices) {

View File

@ -24,9 +24,6 @@ const VERSION = '0.9';
const POLL_REGEX = '/^[a-z0-9]+$/i';
const CHOICE_REGEX = '/^[012]$/';
const NAME_REGEX = '/^[áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœa-z0-9_ -]+$/i';
const TITLE_REGEX = '/^[áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœa-z0-9\\/ &"\'(_)=~#{|`^@}$[\\]\\\\,;:!?.*-]+$/i';
const DESCRIPTION_REGEX = "/^[áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœa-z0-9\\/ &\"'(_)=~#{|`^@}$[\\]\\\\,;:!?.*\n-]*$/i";
const COMMENT_REGEX = "/^[áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœa-z0-9\\/ &\"'(_)=~#{|`^@}$[\\]\\\\,;:!?.*\n-]+$/i";
const BOOLEAN_REGEX = '/^(on|off|true|false|1|0)$/i';
const BOOLEAN_TRUE_REGEX = '/^(on|true|1)$/i';
const EDITABLE_CHOICE_REGEX = '/^[0-2]$/';

View File

@ -28,7 +28,7 @@ if (isset($_POST['lang']) && is_string($_POST['lang']) && in_array($_POST['lang'
}
/* <html lang="$locale"> */
$i18n->get('Something, just to load the dictionary');
$i18n->get('', 'Something, just to load the dictionary');
$locale = $i18n->getLoadedLang();
/* Date Format */

View File

@ -0,0 +1,23 @@
<?php
namespace Framadate;
abstract class FramaTestCase extends \PHPUnit_Framework_TestCase {
protected function getTestResourcePath($resourcepath) {
return __DIR__ . '/../resources/'.$resourcepath;
}
protected function readTestResource($resourcepath) {
return file_get_contents($this->getTestResourcePath($resourcepath));
}
protected function invoke(&$object, $methodName) {
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); // get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Framadate\Services;
use Framadate\FramaTestCase;
class MailServiceUnitTest extends FramaTestCase {
const MSG_KEY = '666';
/**
* @test
*/
function should_send_a_2nd_mail_after_a_good_interval() {
// Given
$mailService = new MailService(true);
$_SESSION[MailService::MAILSERVICE_KEY] = [self::MSG_KEY => time() - 1000];
// When
$canSendMsg = $mailService->canSendMsg(self::MSG_KEY);
// Then
$this->assertEquals(true, $canSendMsg);
}
/**
* @test
*/
function should_not_send_2_mails_in_a_short_interval() {
// Given
$mailService = new MailService(true);
$_SESSION[MailService::MAILSERVICE_KEY] = [self::MSG_KEY => time()];
// When
$canSendMsg = $mailService->canSendMsg(self::MSG_KEY);
// Then
$this->assertEquals(false, $canSendMsg);
}
}

3
app/tests/bootstrap.php Normal file
View File

@ -0,0 +1,3 @@
<?php
$loader = require __DIR__ . '/../../vendor/autoload.php';
$loader->addPsr4('Framadate\\', __DIR__.'/Framadate');

View File

@ -14,6 +14,10 @@
"o80/i18n": "dev-develop"
},
"require-dev": {
"phpunit/phpunit": "^4.5"
},
"autoload": {
"psr-4": {
"Framadate\\": "app/classes/Framadate/"

972
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -41,13 +41,13 @@ if (file_exists('bandeaux_local.php')) {
// Step 1/4 : error if $_SESSION from info_sondage are not valid
if (empty($_SESSION['form']->title) || empty($_SESSION['form']->admin_name) || (($config['use_smtp']) ? empty($_SESSION['form']->admin_mail) : false)) {
Utils::print_header(__("Error!"));
bandeau_titre(__("Error!"));
Utils::print_header(__('Error', 'Error!'));
bandeau_titre(__('Error', 'Error!'));
echo '
<div class="alert alert-danger">
<h3>' . __('You haven\'t filled the first section of the poll creation.') . ' !</h3>
<p>' . __('Back to the homepage of') . ' <a href="' . Utils::get_server_name() . '"> ' . NOMAPPLICATION . '</a></p>
<h3>' . __('Error', 'You haven\'t filled the first section of the poll creation.') . ' !</h3>
<p>' . __('Generic', 'Back to the homepage of') . ' <a href="' . Utils::get_server_name() . '"> ' . NOMAPPLICATION . '</a></p>
</div>' . "\n";
bandeau_pied();
@ -149,7 +149,7 @@ if (empty($_SESSION['form']->title) || empty($_SESSION['form']->admin_name) || (
// Summary
$summary = '<ol>';
foreach ($_SESSION['form']->getChoices() as $choice) {
foreach ($_SESSION['form']->getChoices() as $i=>$choice) {
preg_match_all('/\[!\[(.*?)\]\((.*?)\)\]\((.*?)\)/', $choice->getName(), $md_a_img); // Markdown [![alt](src)](href)
preg_match_all('/!\[(.*?)\]\((.*?)\)/', $choice->getName(), $md_img); // Markdown ![alt](src)
@ -198,7 +198,7 @@ if (empty($_SESSION['form']->title) || empty($_SESSION['form']->admin_name) || (
<div class="col-sm-6">
<div class="input-group date">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar text-info"></i></span>
<input type="text" class="form-control" id="enddate" data-date-format="' . __('Date', 'dd/mm/yyyy') . '" aria-describedby="dateformat" name="enddate" value="' . $end_date_str . '" size="10" maxlength="10" placeholder="' . __("dd/mm/yyyy") . '" />
<input type="text" class="form-control" id="enddate" data-date-format="' . __('Date', 'dd/mm/yyyy') . '" aria-describedby="dateformat" name="enddate" value="' . $end_date_str . '" size="10" maxlength="10" placeholder="' . __('Date', 'dd/mm/yyyy') . '" />
</div>
</div>
<span id="dateformat" class="sr-only">' . __('Date', 'dd/mm/yyyy') . '</span>

View File

@ -194,7 +194,7 @@ if (!isset($_SESSION['form']->title) || !isset($_SESSION['form']->admin_name) ||
<div class="col-sm-6">
<div class="input-group date">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar text-info"></i></span>
<input type="text" class="form-control" id="enddate" data-date-format="'. __('Date', 'dd/mm/yyyy') .'" aria-describedby="dateformat" name="enddate" value="'.$end_date_str.'" size="10" maxlength="10" placeholder="'. __('dd/mm/yyyy') .'" />
<input type="text" class="form-control" id="enddate" data-date-format="'. __('Date', 'dd/mm/yyyy') .'" aria-describedby="dateformat" name="enddate" value="'.$end_date_str.'" size="10" maxlength="10" placeholder="'. __('Date', 'dd/mm/yyyy') .'" />
</div>
</div>
<span id="dateformat" class="sr-only">('. __('Date', 'dd/mm/yyyy') .')</span>
@ -221,17 +221,15 @@ if (!isset($_SESSION['form']->title) || !isset($_SESSION['form']->admin_name) ||
} else {
// Prefill form->choices
if (count($_SESSION['form']->getChoices()) == 0) {
$c = new Choice('');
$c->addSlot('');
$c->addSlot('');
$c->addSlot('');
$_SESSION['form']->addChoice($c);
$c = new Choice('');
$c->addSlot('');
$c->addSlot('');
$c->addSlot('');
$_SESSION['form']->addChoice($c);
foreach ($_SESSION['form']->getChoices() as $c) {
$count = 3 - count($c->getSlots());
for($i=0; $i< $count; $i++) {
$c->addSlot('');
}
}
$count = 3 - count($_SESSION['form']->getChoices());
for($i=0; $i< $count; $i++) {
$c = new Choice('');
$c->addSlot('');
$c->addSlot('');

View File

@ -90,7 +90,7 @@ if ($goToStep2) {
$error_on_name = true;
}
if ($description !== $_POST['description']) {
if ($description === false) {
$error_on_description = true;
}

View File

@ -18,9 +18,6 @@
*/
use Framadate\Services\LogService;
use Framadate\Services\PollService;
use Framadate\Services\InputService;
use Framadate\Services\MailService;
use Framadate\Message;
use Framadate\Utils;
include_once __DIR__ . '/app/inc/init.php';
@ -54,7 +51,7 @@ if (!$poll) {
}
$slots = $pollService->allSlotsByPollId($poll_id);
$slots = $pollService->allSlotsByPoll($poll);
$votes = $pollService->allVotesByPollId($poll_id);
// CSV header

View File

@ -43,7 +43,7 @@ if (!empty($_POST['mail'])) {
$smarty->assign('polls', $polls);
$body = $smarty->fetch('mail/find_polls.tpl');
$mailService->send($mail, __('Homepage', 'Where are my polls'), $body);
$mailService->send($mail, __('Homepage', 'Where are my polls'), $body, 'SEND_POLLS');
$message = new Message('success', __('FindPolls', 'Polls sent'));
} else {
$message = new Message('warning', __('Error', 'No polls found'));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -17,9 +17,7 @@
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
use Framadate\Services\LogService;
use Framadate\Services\PollService;
use Framadate\Utils;
include_once __DIR__ . '/app/inc/init.php';

View File

@ -28,11 +28,21 @@
});
if (nb_filled_choices >= 1) {
$('button[name="fin_sondage_autre"]').removeClass('disabled');
return true;
} else {
$('button[name="fin_sondage_autre"]').addClass('disabled');
return false;
}
};
// Handle form submission
$(document.formulaire).on('submit', function (e) {
if (!submitChoicesAvalaible()) {
e.preventDefault();
e.stopPropagation();
}
});
// Button "Add a choice"
$('#add-a-choice').on('click', function () {

View File

@ -42,11 +42,21 @@ $(document).ready(function () {
if (nb_filled_days >= 1 && nb_filled_hours >= 1) {
$('button[name="choixheures"]').removeClass('disabled');
return true;
} else {
$('button[name="choixheures"]').addClass('disabled');
return false;
}
};
// Handle form submission
$(document.formulaire).on('submit', function (e) {
if (!submitDaysAvalaible()) {
e.preventDefault();
e.stopPropagation();
}
});
// Button "Remove all hours"
$(document).on('click', '#resethours', function () {

View File

@ -47,7 +47,7 @@ $(document).ready(function () {
});
};
$(document).on('click', '.input-group.date .input-group-addon', function () {
$(document).on('click', '.input-group.date .input-group-addon, .input-group.date input', function () {
// Re-init datepicker config before displaying
init_datepicker();
$(this).parent().datepicker('show');

View File

@ -189,7 +189,6 @@
"Remove the comments": "Entfernen Sie die Kommentare",
"Comment deleted": "Kommentar gelöscht",
"All comments deleted": "Alle Kommentare gelöscht",
"The poll has been deleted": "Die Umfrage wurde gelöscht",
"Keep votes": "Halten Stimmen",
"Keep comments": "Halten Sie Kommentare",
"Keep this poll": "Halten Sie diese Umfrage"
@ -200,11 +199,11 @@
"Required fields cannot be left blank.": "Mit * markierte Felder müssen ausgefüllt sein.",
"Poll title": "Umfragetitel",
"Votes cannot be modified.": "DE_Aucun vote ne peut être modifié",
"All voters can modify any vote.": "DE_Tous les sondés peuvent modifier tous les votes",
"Voters can modify their vote themselves.": "Teilnehmer können ihre Antworten verändern",
"To receive an email for each new vote.": "Bei jeder neuen Abstimmung eine E-Mail erhalten.",
"To receive an email for each new comment.": "Um eine E-Mail für jede neue Kommentar zu empfangen.",
"Only the poll maker can see the poll's results.": "DE_Seul le créateur du sondage peut voir les résultats.",
"All voters can modify any vote": "DE_Tous les sondés peuvent modifier tous les votes",
"Voters can modify their vote themselves": "Teilnehmer können ihre Antworten verändern",
"To receive an email for each new vote": "Bei jeder neuen Abstimmung eine E-Mail erhalten",
"To receive an email for each new comment": "Um eine E-Mail für jede neue Kommentar zu empfangen",
"Only the poll maker can see the poll's results": "DE_Seul le créateur du sondage peut voir les résultats",
"Go to step 2": "Weiter zum 2. Schritt"
},
"Step 2": {
@ -289,9 +288,12 @@
},
"Mail": {
"Poll's participation": "Beteiligung an der Umfrage",
"Notification of poll": "Mitteilung bezüglich der Umfrage",
"filled a vote.\nYou can find your poll at the link": "füllte eine Stimme.<br/>Sie können Ihre Umfrage unter dem Link zu finden",
"updated a vote.\nYou can find your poll at the link": "eine Abstimmung regelmäßig aktualisiert.<br/>Sie können Ihre Umfrage unter dem Link zu finden",
"wrote a comment.\nYou can find your poll at the link": "hat einen Kommentar.<br/>Sie können Ihre Umfrage unter dem Link zu finden",
"Someone just change your poll available at the following link %s.": "Jemand ändern Sie einfach Ihre Umfrage finden Sie unter dem folgenden Link <a href=\"%1$s\">%1$s</a>.",
"Someone just delete your poll %s.": "Jemand hat gerade Ihre Umfrage löschen \"%s\".",
"Thanks for your trust.": "Danke für Ihr Vertrauen.",
"FOOTER": "",
"[ADMINISTRATOR] New settings for your poll": "[ADMINISTRATOR] Neue Einstellungen für Ihre Umfrage ",
@ -326,6 +328,7 @@
"Update vote failed": "Update vote failed",
"Adding vote failed": "Adding vote failed",
"Comment failed": "Kommentar gescheitert",
"You can't create a poll with hidden results with the following edition option:": "Sie können nicht eine Umfrage erstellen mit versteckten Ergebnisse mit der folgenden Ausgabe-Option:"
"You can't create a poll with hidden results with the following edition option:": "Sie können nicht eine Umfrage erstellen mit versteckten Ergebnisse mit der folgenden Ausgabe-Option:",
"Failed to delete column": "Fehler beim Spalte löschen"
}
}

View File

@ -189,7 +189,6 @@
"All comments deleted": "All comments deleted",
"Keep the comments": "Keep the comments",
"Remove the comments": "Remove the comments",
"The poll has been deleted": "The poll has been deleted",
"Keep votes": "Keep votes",
"Keep comments": "Keep comments",
"Keep this poll": "Keep this poll"
@ -200,11 +199,11 @@
"Required fields cannot be left blank.": "Required fields cannot be left blank.",
"Poll title": "Poll title",
"Votes cannot be modified.": "Votes cannot be modified",
"All voters can modify any vote.": "All voters can modify any vote.",
"Voters can modify their vote themselves.": "Voters can modify their vote themselves.",
"To receive an email for each new vote.": "To receive an email for each new vote.",
"To receive an email for each new comment.": "To receive an email for each new comment.",
"Only the poll maker can see the poll's results.": "Only the poll maker can see the poll's results.",
"All voters can modify any vote": "All voters can modify any vote",
"Voters can modify their vote themselves": "Voters can modify their vote themselves",
"To receive an email for each new vote": "To receive an email for each new vote",
"To receive an email for each new comment": "To receive an email for each new comment",
"Only the poll maker can see the poll's results": "Only the poll maker can see the poll's results",
"Go to step 2": "Go to step 2"
},
"Step 2": {
@ -289,9 +288,12 @@
},
"Mail" : {
"Poll's participation": "Poll's participation",
"Notification of poll": "Notification of poll",
"filled a vote.\nYou can find your poll at the link": "filled a vote.<br/>You can find your poll at the link",
"updated a vote.\nYou can find your poll at the link": "updated a vote.<br/>You can find your poll at the link",
"wrote a comment.\nYou can find your poll at the link": "wrote a comment.<br/>You can find your poll at the link",
"Someone just change your poll available at the following link %s.": "Someone just change your poll available at the following link <a href=\"%1$s\">%1$s</a>.",
"Someone just delete your poll %s.": "Someone just delete your poll \"%s\".",
"Thanks for your trust.": "Thanks for your trust.",
"FOOTER": "",
"[ADMINISTRATOR] New settings for your poll": "[ADMINISTRATOR] New settings for your poll",
@ -326,6 +328,7 @@
"Update vote failed": "Update vote failed",
"Adding vote failed": "Adding vote failed",
"Comment failed": "Comment failed",
"You can't create a poll with hidden results with the following edition option:": "You can't create a poll with hidden results with the following edition option: "
"You can't create a poll with hidden results with the following edition option:": "You can't create a poll with hidden results with the following edition option: ",
"Failed to delete column": "Failed to delete column"
}
}

View File

@ -189,7 +189,6 @@
"Remove the comments": "ES_Supprimer les commentaires",
"Comment deleted": "ES_Commentaire supprimé",
"All comments deleted": "ES_Tous les commentaires ont été supprimés",
"The poll has been deleted": "ES_Le sondage a été supprimé",
"Keep votes": "ES_Garder les votes",
"Keep comments": "ES_Garder les commentaires",
"Keep this poll": "Dejar este encuesta!"
@ -200,11 +199,11 @@
"Required fields cannot be left blank.": "Gracias por completar los campos con una *.",
"Poll title": "ES_Titre du sondage",
"Votes cannot be modified.": "ES_Aucun vote ne peut être modifié",
"All voters can modify any vote.": "ES_Tous les sondés peuvent modifier tous les votes",
"Voters can modify their vote themselves.": "Los encuentados pueden cambiar su línea ellos mismos.",
"To receive an email for each new vote.": "Usted quiere recibir un correo electónico cada vez que alguien participe a la encuesta.",
"To receive an email for each new comment.": "ES_Recevoir un courriel à chaque commentaire.",
"Only the poll maker can see the poll's results.": "ES_Seul le créateur du sondage peut voir les résultats.",
"All voters can modify any vote": "ES_Tous les sondés peuvent modifier tous les votes",
"Voters can modify their vote themselves": "Los encuentados pueden cambiar su línea ellos mismos",
"To receive an email for each new vote": "Usted quiere recibir un correo electónico cada vez que alguien participe a la encuesta",
"To receive an email for each new comment": "ES_Recevoir un courriel à chaque commentaire",
"Only the poll maker can see the poll's results": "ES_Seul le créateur du sondage peut voir les résultats",
"Go to step 2": "ES_Aller à l'étape 2"
},
"Step 2": {
@ -244,7 +243,7 @@
"Confirm the creation of your poll": "ES_Confirmez la création de votre sondage",
"List of your choices": "ES_Liste de vos choix",
"Once you have confirmed the creation of your poll, you will be automatically redirected on the administration page of your poll.": "ES_Une fois que vous aurez confirmé la création du sondage, vous serez redirigé automatiquement vers la page d'administration de votre sondage.",
"Then, you will receive quickly two emails: one contening the link of your poll for sending it to the voters, the other contening the link to the administration page of your poll.": "ES_En même temps, vous recevrez deux courriels : l'un contenant le lien vers votre sondage pour le faire suivre aux futurs sondés, l'autre contenant le lien vers la page d'administraion du sondage.",
"Then, you will receive quickly two emails: one contening the link of your poll for sending it to the voters, the other contening the link to the administration page of your poll.": "ES_En même temps, vous recevrez deux courriels : l'un contenant le lien vers votre sondage pour le faire suivre aux futurs sondés, l'autre contenant le lien vers la page d'administration du sondage.",
"Create the poll": "Crear la encuesta",
"Your poll will automatically be archived": "ES_Votre sondage sera automatiquement archivé",
"after the last date of your poll.": "ES_après la date la plus tardive.",
@ -288,10 +287,13 @@
"Polls sent": "ES_Sondages envoyés"
},
"Mail": {
"Poll's participation": "ES_Participation au sondage",
"Poll's participation": "Participación Encuesta",
"Notification of poll": "Notificación de la encuesta",
"filled a vote.\nYou can find your poll at the link": "ES_vient de voter.<br/>Vous pouvez retrouver votre sondage avec le lien suivant",
"updated a vote.\nYou can find your poll at the link": "ES_vient de mettre à jour un vote.<br/>Vous pouvez retrouver votre sondage avec le lien suivant",
"wrote a comment.\nYou can find your poll at the link": "ES_vient de rédiger un commentaire.<br/>Vous pouvez retrouver votre sondage avec le lien suivant",
"Someone just change your poll available at the following link %s.": "Alguien acaba de cambiar su encuesta disponible en el siguiente enlace <a href=\"%1$s\">%1$s</a>.",
"Someone just delete your poll %s.": "Alguien acaba de borrar tu encuesta \"%s\".",
"Thanks for your trust.": "ES_Merci de votre confiance.",
"FOOTER": "",
"[ADMINISTRATOR] New settings for your poll": "ES_[ADMINISTRATEUR] Changement de configuration du sondage",
@ -306,8 +308,8 @@
"Error": {
"Error!": "Error!",
"Enter a title": "Introducza un título",
"Something is going wrong...": "ES_Quelque chose ne va pas...",
"Something is wrong with the format": "Something is wrong with the format",
"Something is going wrong...": "Algo va mal...",
"Something is wrong with the format": "Algo está mal con el formato",
"Enter an email address": "Introduzca una dirección electrónica",
"The address is not correct! You should enter a valid email address (like r.stallman@outlock.com) in order to receive the link to your poll.": "ES_L'adresse saisie n'est pas correcte ! Il faut une adresse électronique valide (par exemple r.stallman@outlock.com) pour recevoir le lien vers le sondage.",
"No polls found": "ES_Aucun sondage n'a été trouvé",
@ -322,10 +324,11 @@
"Enter a name and a comment!": "Introduzca su nombre y un comentario!",
"Failed to insert the comment!": "ES_Échec à l'insertion du commentaire !",
"Framadate is not properly installed, please check the \"INSTALL\" to setup the database before continuing.": "ES_Framadate n'est pas installé correctement, lisez le fichier INSTALL pour configurer la base de données avant de continuer.",
"Failed to save poll": "ES_Echèc de la sauvegarde du sondage",
"Failed to save poll": "ES_Echec de la sauvegarde du sondage",
"Update vote failed": "ES_Mise à jour du vote échoué",
"Adding vote failed": "ES_Ajout d'un vote échoué",
"Comment failed": "ES_Commentaire échoué",
"You can't create a poll with hidden results with the following edition option:": "ES_Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : "
"You can't create a poll with hidden results with the following edition option:": "ES_Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : ",
"Failed to delete column": "Error al eliminar la columna"
}
}

View File

@ -189,7 +189,6 @@
"Remove the comments": "Supprimer les commentaires",
"Comment deleted": "Commentaire supprimé",
"All comments deleted": "Tous les commentaires ont été supprimés",
"The poll has been deleted": "Le sondage a été supprimé",
"Keep votes": "Garder les votes",
"Keep comments": "Garder les commentaires",
"Keep this poll": "Garder ce sondage"
@ -200,11 +199,11 @@
"Required fields cannot be left blank.": "Merci de remplir les champs obligatoires, marqués d'une *.",
"Poll title": "Titre du sondage",
"Votes cannot be modified.": "Aucun vote ne peut être modifié",
"All voters can modify any vote.": "Tous les sondés peuvent modifier tous les votes",
"Voters can modify their vote themselves.": "Chaque sondé peut modifier son propre vote.",
"To receive an email for each new vote.": "Recevoir un courriel à chaque participation d'un sondé.",
"To receive an email for each new comment.": "Recevoir un courriel à chaque commentaire.",
"Only the poll maker can see the poll's results.": "Seul le créateur du sondage peut voir les résultats.",
"All voters can modify any vote": "Tous les sondés peuvent modifier tous les votes",
"Voters can modify their vote themselves": "Chaque sondé peut modifier son propre vote",
"To receive an email for each new vote": "Recevoir un courriel à chaque participation d'un sondé",
"To receive an email for each new comment": "Recevoir un courriel à chaque commentaire",
"Only the poll maker can see the poll's results": "Seul le créateur du sondage peut voir les résultats",
"Go to step 2": "Aller à l'étape 2"
},
"Step 2": {
@ -244,7 +243,7 @@
"Confirm the creation of your poll": "Confirmez la création de votre sondage",
"List of your choices": "Liste de vos choix",
"Once you have confirmed the creation of your poll, you will be automatically redirected on the administration page of your poll.": "Une fois que vous aurez confirmé la création du sondage, vous serez redirigé automatiquement vers la page d'administration de votre sondage.",
"Then, you will receive quickly two emails: one contening the link of your poll for sending it to the voters, the other contening the link to the administration page of your poll.": "En même temps, vous recevrez deux courriels : l'un contenant le lien vers votre sondage pour le faire suivre aux futurs sondés, l'autre contenant le lien vers la page d'administraion du sondage.",
"Then, you will receive quickly two emails: one contening the link of your poll for sending it to the voters, the other contening the link to the administration page of your poll.": "En même temps, vous recevrez deux courriels : l'un contenant le lien vers votre sondage pour le faire suivre aux futurs sondés, l'autre contenant le lien vers la page d'administration du sondage.",
"Create the poll": "Créer le sondage",
"Your poll will automatically be archived": "Votre sondage sera automatiquement archivé",
"after the last date of your poll.": "après la date la plus tardive.",
@ -289,9 +288,12 @@
},
"Mail": {
"Poll's participation": "Participation au sondage",
"Notification of poll": "Notification d'un sondage",
"filled a vote.\nYou can find your poll at the link": "vient de voter.<br/>Vous pouvez retrouver votre sondage avec le lien suivant",
"updated a vote.\nYou can find your poll at the link": "vient de mettre à jour un vote.<br/>Vous pouvez retrouver votre sondage avec le lien suivant",
"wrote a comment.\nYou can find your poll at the link": "vient de rédiger un commentaire.<br/>Vous pouvez retrouver votre sondage avec le lien suivant",
"Someone just change your poll available at the following link %s.": "Quelqu'un vient de modifier votre sondage accessible au lien suivant <a href=\"%1$s\">%1$s</a>.",
"Someone just delete your poll %s.": "Quelqu'un vient de supprimer votre sondage \"%s\".",
"Thanks for your trust.": "Merci de votre confiance.",
"FOOTER": "« La route est longue, mais la voie est libre… »<br/>Framasoft ne vit que par vos dons (déductibles des impôts).<br/>Merci d'avance pour votre soutien http://soutenir.framasoft.org.",
"[ADMINISTRATOR] New settings for your poll": "[ADMINISTRATEUR] Changement de configuration du sondage",
@ -322,10 +324,11 @@
"Enter a name and a comment!": "Merci de remplir les deux champs !",
"Failed to insert the comment!": "Échec à l'insertion du commentaire !",
"Framadate is not properly installed, please check the \"INSTALL\" to setup the database before continuing.": "Framadate n'est pas installé correctement, lisez le fichier INSTALL pour configurer la base de données avant de continuer.",
"Failed to save poll": "Echèc de la sauvegarde du sondage",
"Failed to save poll": "Echec de la sauvegarde du sondage",
"Update vote failed": "Mise à jour du vote échoué",
"Adding vote failed": "Ajout d'un vote échoué",
"Comment failed": "Commentaire échoué",
"You can't create a poll with hidden results with the following edition option:": "Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : "
"You can't create a poll with hidden results with the following edition option:": "Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : ",
"Failed to delete column": "Échec de la suppression de colonne"
}
}

View File

@ -189,7 +189,6 @@
"Remove the comments": "Eliminare i commenti",
"Comment deleted": "Commento rimosso",
"All comments deleted": "Tutti i commenti sono stati cancellati",
"The poll has been deleted": "Il sondaggio è stato eliminato",
"Keep votes": "Tenere voti",
"Keep comments": "Tenere commenti",
"Keep this poll": "Mantengo questo sondaggio !"
@ -200,11 +199,11 @@
"Required fields cannot be left blank.": "Riempire i campi obbligatori, segnati con *.",
"Poll title": "Titolo del sondaggio",
"Votes cannot be modified.": "No voto non può essere modificato",
"All voters can modify any vote.": "Tutti i sondaggi possono cambiare tutti i voti",
"Voters can modify their vote themselves.": "I partecipanti possono modificare il loro voto in autonomia.",
"To receive an email for each new vote.": "Per ricevere un'email per ogni voto nuovo",
"To receive an email for each new comment.": "Ricevi una e-mail ogni commento.",
"Only the poll maker can see the poll's results.": "Solo il creatore sondaggio possono vedere i risultati.",
"All voters can modify any vote": "Tutti i sondaggi possono cambiare tutti i voti",
"Voters can modify their vote themselves": "I partecipanti possono modificare il loro voto in autonomia",
"To receive an email for each new vote": "Per ricevere un'email per ogni voto nuovo",
"To receive an email for each new comment": "Ricevi una e-mail ogni commento",
"Only the poll maker can see the poll's results": "Solo il creatore sondaggio possono vedere i risultati",
"Go to step 2": "Andare al punto 2"
},
"Step 2": {
@ -245,7 +244,7 @@
"List of your choices": "Liste delle vostre scelte",
"Once you have confirmed the creation of your poll, you will be automatically redirected on the administration page of your poll.": "Un volta che avrete confermato la creazione del sondaggio, sarete rediretti automaticamente sulla pagina di amministrazione del vostro sondaggio.",
"Then, you will receive quickly two emails: one contening the link of your poll for sending it to the voters, the other contening the link to the administration page of your poll.": "Nello stesso momento, riceverete 2 email : una con il Link verso il vostro sondaggio da inoltrare ai partecipanti, l'altra con il Link verso la pagina di amministrazione del sondaggio.",
"Create the poll": "Creare le sondaggio",
"Create the poll": "Creare il sondaggio",
"Your poll will automatically be archived": "La vostra indagine verrà archiviata automaticamente",
"after the last date of your poll.": "dopo l'ultima data.",
"You can set a closer archiving date for it.": "Si può decidere su una data più vicina di archiviazione.",
@ -289,9 +288,12 @@
},
"Mail": {
"Poll's participation": "Partecipazione al sondaggio",
"Notification of poll": "Notifica di sondaggio",
"filled a vote.\nYou can find your poll at the link": "IT_vient de voter.\nVous pouvez retrouver votre sondage avec le lien suivant",
"updated a vote.\nYou can find your poll at the link": "IT_vient de mettre à jour un vote.\nVous pouvez retrouver votre sondage avec le lien suivant",
"wrote a comment.\nYou can find your poll at the link": "IT_vient de rédiger un commentaire.\nVous pouvez retrouver votre sondage avec le lien suivant",
"Someone just change your poll available at the following link %s.": "Qualcuno basta cambiare il vostro sondaggio disponibile al seguente link <a href=\"%1$s\">%1$s</a>.",
"Someone just delete your poll %s.": "Qualcuno ha appena cancellare il tuo sondaggio \"%s\".",
"Thanks for your trust.": "Grazie per la vostra fiducia.",
"FOOTER": "IT_« La route est longue, mais la voie est libre… »\nFramasoft ne vit que par vos dons (déductibles des impôts).\nMerci d'avance pour votre soutien http://soutenir.framasoft.org.",
"[ADMINISTRATOR] New settings for your poll": "[AMMINISTRATORE] Modifica di configurazione del sondaggio",
@ -322,10 +324,11 @@
"Enter a name and a comment!": "Inserire un nome e un commento!",
"Failed to insert the comment!": "Errore nell'inserimento del commento !",
"Framadate is not properly installed, please check the \"INSTALL\" to setup the database before continuing.": "IT_Framadate n'est pas installé correctement, lisez le fichier INSTALL pour configurer la base de données avant de continuer.",
"Failed to save poll": "IT_Echèc de la sauvegarde du sondage",
"Failed to save poll": "IT_Echec de la sauvegarde du sondage",
"Update vote failed": "IT_Mise à jour du vote échoué",
"Adding vote failed": "IT_Ajout d'un vote échoué",
"Comment failed": "IT_Commentaire échoué",
"You can't create a poll with hidden results with the following edition option:": "IT_Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : "
"You can't create a poll with hidden results with the following edition option:": "IT_Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : ",
"Failed to delete column": "Impossibile eliminare colonna"
}
}

1
phpunit.bat Normal file
View File

@ -0,0 +1 @@
vendor\bin\phpunit.bat --bootstrap app\tests\bootstrap.php app/tests

1
phpunit.sh Normal file
View File

@ -0,0 +1 @@
vendor\bin\phpunit --bootstrap app\tests\bootstrap.php app/tests

View File

@ -64,7 +64,7 @@ function sendUpdateNotification($poll, $mailService, $name, $type) {
$_SESSION['mail_sent'] = [];
}
if ($poll->receiveNewVotes && (!isset($_SESSION['mail_sent'][$poll->id]) || $_SESSION['mail_sent'][$poll->id] !== true)) {
if ($poll->receiveNewVotes) {
$subject = '[' . NOMAPPLICATION . '] ' . __('Mail', 'Poll\'s participation') . ' : ' . $poll->title;
@ -82,9 +82,8 @@ function sendUpdateNotification($poll, $mailService, $name, $type) {
}
$message .= Utils::getUrlSondage($poll->admin_id, true) . "\n\n";
$mailService->send($poll->admin_mail, $subject, $message);
$_SESSION['mail_sent'][$poll->id] = true;
$messageTypeKey = $type . '-' . $poll->id;
$mailService->send($poll->admin_mail, $subject, $message, $messageTypeKey);
}
}
@ -152,7 +151,7 @@ if (!empty($_POST['save'])) { // Save edition of an old vote
$message = new Message('danger', __('Error', 'The name is invalid.'));
}
if (count($choices) != count($_POST['choices'])) {
$message = new Message('danger', __('There is a problem with your choices'));
$message = new Message('danger', __('Error', 'There is a problem with your choices'));
}
if ($message == null) {
@ -198,7 +197,7 @@ if (isset($_POST['add_comment'])) {
}
// Retrieve data
$slots = $pollService->allSlotsByPollId($poll_id);
$slots = $pollService->allSlotsByPoll($poll);
$votes = $pollService->allVotesByPollId($poll_id);
$comments = $pollService->allCommentsByPollId($poll_id);
@ -207,7 +206,7 @@ $smarty->assign('poll_id', $poll_id);
$smarty->assign('poll', $poll);
$smarty->assign('title', __('Generic', 'Poll') . ' - ' . $poll->title);
$smarty->assign('expired', strtotime($poll->end_date) < time());
$smarty->assign('deletion_date', $poll->end_date + PURGE_DELAY * 86400);
$smarty->assign('deletion_date', strtotime($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));

View File

@ -2,12 +2,12 @@
{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>
<div class="alert alert-dismissible alert-info" role="alert">{$message|html}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', '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">{__('Admin', 'Purge the polls')} <span class="glyphicon glyphicon-trash text-danger"></span></button>
<button type="submit" name="action" value="purge" class="btn btn-danger">{__('Admin', 'Purge the polls')} <span class="glyphicon glyphicon-trash"></span></button>
</div>
</form>
{/block}

View File

@ -102,11 +102,11 @@
</label>
<label>
<input type="radio" name="editable" id="editableByAll" {if $poll_editable==constant("Framadate\Editable::EDITABLE_BY_ALL")}checked{/if} value="{constant("Framadate\Editable::EDITABLE_BY_ALL")}">
{__('Step 1', 'All voters can modify any vote.')}
{__('Step 1', 'All voters can modify any vote')}
</label>
<label>
<input type="radio" name="editable" {if $poll_editable==constant("Framadate\Editable::EDITABLE_BY_OWN")}checked{/if} value="{constant("Framadate\Editable::EDITABLE_BY_OWN")}">
{__('Step 1', 'Voters can modify their vote themselves.')}
{__('Step 1', 'Voters can modify their vote themselves')}
</label>
</div>
</div>
@ -120,7 +120,7 @@
<label>
<input type="checkbox" name="receiveNewVotes" {if $poll_receiveNewVotes}checked{/if}
id="receiveNewVotes">
{__('Step 1', 'To receive an email for each new vote.')}
{__('Step 1', 'To receive an email for each new vote')}
</label>
</div>
</div>
@ -131,7 +131,7 @@
<label>
<input type="checkbox" name="receiveNewComments" {if $poll_receiveNewComments}checked{/if}
id="receiveNewComments">
{__('Step 1', 'To receive an email for each new comment.')}
{__('Step 1', 'To receive an email for each new comment')}
</label>
</div>
</div>
@ -142,12 +142,12 @@
<label>
<input type="checkbox" name="hidden" {if $poll_hidden}checked{/if}
id="hidden">
{__('Step 1', "Only the poll maker can see the poll's results.")}
{__('Step 1', 'Only the poll maker can see the poll\'s results')}
</label>
</div>
<div id="hiddenWithBadEditionModeError" class="alert alert-danger hidden">
<p>
{__('Error', "You can't create a poll with hidden results with the following edition option:")}"{__('Step 1', 'All voters can modify any vote.')}"
{__('Error', 'You can\'t create a poll with hidden results with the following edition option:')}"{__('Step 1', 'All voters can modify any vote')}"
</p>
</div>
</div>

View File

@ -2,7 +2,7 @@
{block name=main}
{if !empty($message)}
<div class="alert alert-dismissible alert-{$message->type|html}" role="alert">{$message->message|html}{if $message->link != null}<br/><a href="{$message->link}">{$message->link}</a>{/if}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>
<div class="alert alert-dismissible alert-{$message->type|html}" role="alert">{$message->message|html}{if $message->link != null}<br/><a href="{$message->link}">{$message->link}</a>{/if}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'CLose')}"><span aria-hidden="true">&times;</span></button></div>
{/if}
<form action="" method="post">
<div class="row">
@ -15,10 +15,7 @@
</div>
</div>
<div class="col-md-6 col-md-offset-3 text-center">
<button type="submit" class="btn btn-warning btn-lg">
<span class="glyphicon glyphicon-search"></span>
{__('FindPolls', 'Send me my polls')}
</button>
<button type="submit" class="btn btn-success">{__('FindPolls', 'Send me my polls')}</button>
</div>
</div>
</form>

View File

@ -29,8 +29,6 @@
<div class="col-md-6 col-md-offset-3 text-center">
<p class="home-choice">
<a href="{$SERVER_URL}find_polls.php" class="opacity" role="button">
<img alt="" class="img-responsive center-block" src="{'images/question.png'|resource}"/>
<br/>
<span class="btn btn-warning btn-lg">
<span class="glyphicon glyphicon-search"></span>
{__('Homepage', 'Where are my polls')}

View File

@ -20,7 +20,7 @@
<script type="text/javascript" src="{"js/locales/bootstrap-datepicker.$locale.js"|resource}"></script>
<script type="text/javascript" src="{'js/core.js'|resource}"></script>
{if !empty($nav_js)}
{if $use_nav_js}
<script src="{'nav/nav.js'|resource}" id="nav_js" type="text/javascript" charset="utf-8"></script><!-- /Framanav -->
{/if}

View File

@ -11,7 +11,7 @@
<button type="submit" name="delete_comment" value="{$comment->id|html}" class="btn btn-link" title="{__('Comments', 'Remove the comment')}"><span class="glyphicon glyphicon-remove text-danger"></span><span class="sr-only">{__('Generic', 'Remove')}</span></button>
{/if}
<b>{$comment->name|html}</b>&nbsp;
<span class="comment">{nl2br($comment->comment|html)}</span>
<span class="comment">{$comment->comment|escape|nl2br}</span>
</div>
{/foreach}
{/if}
@ -22,8 +22,8 @@
<div class="col-md-6 col-md-offset-3">
<fieldset id="add-comment"><legend>{__('Comments', 'Add a comment to the poll')}</legend>
<div class="form-group">
<label for="name" class="control-label">{__('Generic', 'Your name')}</label>
<input type="text" name="name" id="name" class="form-control" />
<label for="comment_name" class="control-label">{__('Generic', 'Your name')}</label>
<input type="text" name="name" id="comment_name" class="form-control" />
</div>
<div class="form-group">
<label for="comment" class="control-label">{__('Comments', 'Your comment')}</label>

View File

@ -38,85 +38,86 @@
</thead>
<tbody>
{foreach $votes as $vote}
<tr>
{* Edited line *}
{if $editingVoteId === $vote->uniqId}
<td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm" id="edit">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="hidden" name="edited_vote" value="{$vote->uniqId}"/>
<input type="text" id="name" name="name" value="{$vote->name|html}" class="form-control" title="{__('Genric', 'Your name')}" placeholder="{__('Genric', 'Your name')}" />
</div>
{if $editingVoteId === $vote->uniqId} {* Edited line *}
<tr class="hidden-print">
<td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm" id="edit">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="hidden" name="edited_vote" value="{$vote->uniqId}"/>
<input type="text" id="name" name="name" value="{$vote->name|html}" class="form-control" title="{__('Genric', 'Your name')}" placeholder="{__('Genric', 'Your name')}" />
</div>
</td>
{foreach $vote->choices as $id=>$choice}
<td class="bg-info" headers="C{$id}">
<ul class="list-unstyled choice">
<li class="yes">
<input type="radio" id="y-choice-{$id}" name="choices[{$id}]" value="2" {if $choice==2}checked {/if}/>
<label class="btn btn-default btn-xs" for="y-choice-{$id}" title="{__('Poll results', 'Vote yes for')|html} {$slots[$id]->title|html}">
<span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Genric', 'Yes')}</span>
</label>
</li>
<li class="ifneedbe">
<input type="radio" id="i-choice-{$id}" name="choices[{$id}]" value="1" {if $choice==1}checked {/if}/>
<label class="btn btn-default btn-xs" for="i-choice-{$id}" title="{__('Poll results', 'Vote ifneedbe for')|html} {$slots[$id]->title|html}">
(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Genric', 'Ifneedbe')}</span>
</label>
</li>
<li class="no">
<input type="radio" id="n-choice-{$id}" name="choices[{$id}]" value="0" {if $choice==0}checked {/if}/>
<label class="btn btn-default btn-xs" for="n-choice-{$id}" title="{__('Poll results', 'Vote no for')|html} {$slots[$id]->title|html}">
<span class="glyphicon glyphicon-ban-circle"></span><span class="sr-only">{__('Genric', 'No')}</span>
</label>
</li>
</ul>
</td>
{/foreach}
<td style="padding:5px"><button type="submit" class="btn btn-success btn-xs" name="save" value="{$vote->id|html}" title="{__('Poll results', 'Save the choices')} {$vote->name|html}">{__('Generic', 'Save')}</button></td>
</tr>
{elseif !$hidden} {* Voted line *}
<tr>
{foreach $vote->choices as $id=>$choice}
<th class="bg-info">{$vote->name|html}</th>
<td class="bg-info" headers="C{$id}">
<ul class="list-unstyled choice">
<li class="yes">
<input type="radio" id="y-choice-{$id}" name="choices[{$id}]" value="2" {if $choice==2}checked {/if}/>
<label class="btn btn-default btn-xs" for="y-choice-{$id}" title="{__('Poll results', 'Vote yes for')|html} {$slots[$id]->title|html}">
<span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Genric', 'Yes')}</span>
</label>
</li>
<li class="ifneedbe">
<input type="radio" id="i-choice-{$id}" name="choices[{$id}]" value="1" {if $choice==1}checked {/if}/>
<label class="btn btn-default btn-xs" for="i-choice-{$id}" title="{__('Poll results', 'Vote ifneedbe for')|html} {$slots[$id]->title|html}">
(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Genric', 'Ifneedbe')}</span>
</label>
</li>
<li class="no">
<input type="radio" id="n-choice-{$id}" name="choices[{$id}]" value="0" {if $choice==0}checked {/if}/>
<label class="btn btn-default btn-xs" for="n-choice-{$id}" title="{__('Poll results', 'Vote no for')|html} {$slots[$id]->title|html}">
<span class="glyphicon glyphicon-ban-circle"></span><span class="sr-only">{__('Genric', 'No')}</span>
</label>
</li>
</ul>
</td>
{/foreach}
<td style="padding:5px"><button type="submit" class="btn btn-success btn-xs" name="save" value="{$vote->id|html}" title="{__('Poll results', 'Save the choices')} {$vote->name|html}">{__('Generic', 'Save')}</button></td>
{elseif !$hidden}
{* Voted line *}
{foreach $vote->choices as $id=>$choice}
<th class="bg-info">{$vote->name|html}</th>
{foreach $vote->choices as $id=>$choice}
{if $choice==2}
<td class="bg-success text-success" headers="C{$id}"><span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Generic', 'Yes')}</span></td>
{elseif $choice==1}
<td class="bg-warning text-warning" headers="C{$id}">(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Generic', 'Ifneedbe')}</span></td>
{else}
<td class="bg-danger" headers="C{$id}"><span class="sr-only">{__('Generic', 'No')}</span></td>
{/if}
{/foreach}
{if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin)}
<td>
<a href="{if $admin}{poll_url id=$poll->admin_id vote_id=$vote->uniqId admin=true}{else}{poll_url id=$poll->id vote_id=$vote->uniqId}{/if}" class="btn btn-default btn-sm" title="{__('Poll results', 'Edit the line:')|html} {$vote->name|html}">
<span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{__('Generic', 'Edit')}</span>
</a>
{if $admin}
<a href="{poll_url id=$admin_poll_id admin=true action='delete_vote' action_value=$vote->id}"
class="btn btn-default btn-sm"
title="{__('Poll results', 'Remove the line:')} {$vote->name|html}">
<span class="glyphicon glyphicon-remove text-danger"></span><span class="sr-only">{__('Generic', 'Remove')}</span>
</a>
{/if}
</td>
{if $choice==2}
<td class="bg-success text-success" headers="C{$id}"><span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Generic', 'Yes')}</span></td>
{elseif $choice==1}
<td class="bg-warning text-warning" headers="C{$id}">(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Generic', 'Ifneedbe')}</span></td>
{else}
<td></td>
<td class="bg-danger" headers="C{$id}"><span class="sr-only">{__('Generic', 'No')}</span></td>
{/if}
{/foreach}
{if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin)}
<td class="hidden-print">
<a href="{if $admin}{poll_url id=$poll->admin_id vote_id=$vote->uniqId admin=true}{else}{poll_url id=$poll->id vote_id=$vote->uniqId}{/if}" class="btn btn-default btn-sm" title="{__('Poll results', 'Edit the line:')|html} {$vote->name|html}">
<span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{__('Generic', 'Edit')}</span>
</a>
{if $admin}
<a href="{poll_url id=$admin_poll_id admin=true action='delete_vote' action_value=$vote->id}"
class="btn btn-default btn-sm"
title="{__('Poll results', 'Remove the line:')} {$vote->name|html}">
<span class="glyphicon glyphicon-remove text-danger"></span><span class="sr-only">{__('Generic', 'Remove')}</span>
</a>
{/if}
</td>
{else}
<td></td>
{/if}
</tr>
{/if}
{/foreach}
{* Line to add a new vote *}
{if $active && $editingVoteId === 0 && !$expired}
<tr id="vote-form">
<tr id="vote-form" class="hidden-print">
<td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>

View File

@ -86,86 +86,89 @@
</thead>
<tbody>
{foreach $votes as $vote}
<tr>
{* Edited line *}
{* Edited line *}
{if $editingVoteId === $vote->uniqId && !$expired}
<td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm" id="edit">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="hidden" name="edited_vote" value="{$vote->uniqId}"/>
<input type="text" id="name" name="name" value="{$vote->name|html}" class="form-control" title="{__('Generic', 'Your name')}" placeholder="{__('Generic', 'Your name')}" />
</div>
{if $editingVoteId === $vote->uniqId && !$expired}
<tr class="hidden-print">
<td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm" id="edit">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="hidden" name="edited_vote" value="{$vote->uniqId}"/>
<input type="text" id="name" name="name" value="{$vote->name|html}" class="form-control" title="{__('Generic', 'Your name')}" placeholder="{__('Generic', 'Your name')}" />
</div>
</td>
{foreach $vote->choices as $k=>$choice}
<td class="bg-info" headers="M{$headersM[$k]} D{$headersD[$k]} H{$headersH[$k]}">
<ul class="list-unstyled choice">
<li class="yes">
<input type="radio" id="y-choice-{$k}" name="choices[{$k}]" value="2" {if $choice==2}checked {/if}/>
<label class="btn btn-default btn-xs" for="y-choice-{$k}" title="{__('Poll results', 'Vote yes for')|html} {$slots_raw[$k]}">
<span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Generic', 'Yes')}</span>
</label>
</li>
<li class="ifneedbe">
<input type="radio" id="i-choice-{$k}" name="choices[{$k}]" value="1" {if $choice==1}checked {/if}/>
<label class="btn btn-default btn-xs" for="i-choice-{$k}" title="{__('Poll results', 'Vote ifneedbe for')|html} {$slots_raw[$k]}">
(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Generic', 'Ifneedbe')}</span>
</label>
</li>
<li class="no">
<input type="radio" id="n-choice-{$k}" name="choices[{$k}]" value="0" {if $choice==0}checked {/if}/>
<label class="btn btn-default btn-xs" for="n-choice-{$k}" title="{__('Poll results', 'Vote no for')|html} {$slots_raw[$k]}">
<span class="glyphicon glyphicon-ban-circle"></span><span class="sr-only">{__('Generic', 'No')}</span>
</label>
</li>
</ul>
</td>
{/foreach}
<td style="padding:5px"><button type="submit" class="btn btn-success btn-xs" name="save" value="{$vote->id|html}" title="{__('Poll results', 'Save the choices')} {$vote->name|html}">{__('Generic', 'Save')}</button></td>
{foreach $vote->choices as $k=>$choice}
</tr>
{elseif !$hidden}
<tr>
<td class="bg-info" headers="M{$headersM[$k]} D{$headersD[$k]} H{$headersH[$k]}">
<ul class="list-unstyled choice">
<li class="yes">
<input type="radio" id="y-choice-{$k}" name="choices[{$k}]" value="2" {if $choice==2}checked {/if}/>
<label class="btn btn-default btn-xs" for="y-choice-{$k}" title="{__('Poll results', 'Vote yes for')|html} {$slots_raw[$k]}">
<span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Generic', 'Yes')}</span>
</label>
</li>
<li class="ifneedbe">
<input type="radio" id="i-choice-{$k}" name="choices[{$k}]" value="1" {if $choice==1}checked {/if}/>
<label class="btn btn-default btn-xs" for="i-choice-{$k}" title="{__('Poll results', 'Vote ifneedbe for')|html} {$slots_raw[$k]}">
(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Generic', 'Ifneedbe')}</span>
</label>
</li>
<li class="no">
<input type="radio" id="n-choice-{$k}" name="choices[{$k}]" value="0" {if $choice==0}checked {/if}/>
<label class="btn btn-default btn-xs" for="n-choice-{$k}" title="{__('Poll results', 'Vote no for')|html} {$slots_raw[$k]}">
<span class="glyphicon glyphicon-ban-circle"></span><span class="sr-only">{__('Generic', 'No')}</span>
</label>
</li>
</ul>
</td>
{/foreach}
<td style="padding:5px"><button type="submit" class="btn btn-success btn-xs" name="save" value="{$vote->id|html}" title="{__('Poll results', 'Save the choices')} {$vote->name|html}">{__('Generic', 'Save')}</button></td>
{elseif !$hidden}
{* Voted line *}
{* Voted line *}
<th class="bg-info">{$vote->name|html}</th>
<th class="bg-info">{$vote->name|html}</th>
{foreach $vote->choices as $k=>$choice}
{foreach $vote->choices as $k=>$choice}
{if $choice==2}
<td class="bg-success text-success" headers="M{$headersM[$k]} D{$headersD[$k]} H{$k}"><span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Generic', 'Yes')}</span></td>
{elseif $choice==1}
<td class="bg-warning text-warning" headers="M{$headersM[$k]} D{$headersD[$k]} H{$k}">(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Generic', 'Ifneedbe')}</span></td>
{else}
<td class="bg-danger" headers="M{$headersM[$k]} D{$headersD[$k]} H{$k}"><span class="sr-only">{__('Generic', 'No')}</span></td>
{/if}
{/foreach}
{if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin)}
<td>
<a href="{if $admin}{poll_url id=$poll->admin_id vote_id=$vote->uniqId admin=true}{else}{poll_url id=$poll->id vote_id=$vote->uniqId}{/if}" class="btn btn-default btn-sm" title="{__('Poll results', 'Edit the line:')|escape} {$vote->name|html}">
<span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{__('Generic', 'Edit')}</span>
</a>
{if $admin}
<a href="{poll_url id=$admin_poll_id admin=true action='delete_vote' action_value=$vote->id}"
class="btn btn-default btn-sm"
title="{__('Poll results', 'Remove the line:')} {$vote->name|html}">
<span class="glyphicon glyphicon-remove text-danger"></span><span class="sr-only">{__('Generic', 'Remove')}</span>
</a>
{/if}
</td>
{if $choice==2}
<td class="bg-success text-success" headers="M{$headersM[$k]} D{$headersD[$k]} H{$k}"><span class="glyphicon glyphicon-ok"></span><span class="sr-only">{__('Generic', 'Yes')}</span></td>
{elseif $choice==1}
<td class="bg-warning text-warning" headers="M{$headersM[$k]} D{$headersD[$k]} H{$k}">(<span class="glyphicon glyphicon-ok"></span>)<span class="sr-only">{__('Generic', 'Ifneedbe')}</span></td>
{else}
<td></td>
<td class="bg-danger" headers="M{$headersM[$k]} D{$headersD[$k]} H{$k}"><span class="sr-only">{__('Generic', 'No')}</span></td>
{/if}
{/foreach}
{if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin)}
<td class="hidden-print">
<a href="{if $admin}{poll_url id=$poll->admin_id vote_id=$vote->uniqId admin=true}{else}{poll_url id=$poll->id vote_id=$vote->uniqId}{/if}" class="btn btn-default btn-sm" title="{__('Poll results', 'Edit the line:')|escape} {$vote->name|html}">
<span class="glyphicon glyphicon-pencil"></span><span class="sr-only">{__('Generic', 'Edit')}</span>
</a>
{if $admin}
<a href="{poll_url id=$admin_poll_id admin=true action='delete_vote' action_value=$vote->id}"
class="btn btn-default btn-sm"
title="{__('Poll results', 'Remove the line:')} {$vote->name|html}">
<span class="glyphicon glyphicon-remove text-danger"></span><span class="sr-only">{__('Generic', 'Remove')}</span>
</a>
{/if}
</td>
{else}
<td></td>
{/if}
</tr>
{/if}
{/foreach}
{* Line to add a new vote *}
{if $active && $editingVoteId === 0 && !$expired}
<tr id="vote-form">
<tr id="vote-form" class="hidden-print">
<td class="bg-info" style="padding:5px">
<div class="input-group input-group-sm">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>

View File

@ -1,8 +1,8 @@
{extends file='page.tpl'}
{block name=main}
<div class="alert alert-success text-center">
<h2>{__('adminstuds', 'The poll has been deleted')}</h2>
<div class="alert alert-{$message->type} text-center">
<h2>{$message->message}</h2>
<p>{__('Generic', 'Back to the homepage of')} <a href="{$SERVER_URL|html}">{$APPLICATION_NAME|html}</a></p>
</div>
{/block}

View File

@ -9,10 +9,10 @@
<div id="message-container">
{if !empty($message)}
<div class="alert alert-dismissible alert-{$message->type|html}" role="alert">{$message->message|html}{if $message->link != null}<br/><a href="{$message->link}">{$message->link}</a>{/if}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>
<div class="alert alert-dismissible alert-{$message->type|html} hidden-print" role="alert">{$message->message|html}{if $message->link != null}<br/><a href="{$message->link}">{$message->link}</a>{/if}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'CLose')}"><span aria-hidden="true">&times;</span></button></div>
{/if}
</div>
<div id="nameErrorMessage" class="hidden alert alert-dismissible alert-danger" role="alert">{__('Error', 'The name is invalid.')}<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>
<div id="nameErrorMessage" class="hidden alert alert-dismissible alert-danger hidden-print" role="alert">{__('Error', 'The name is invalid.')}<button type="button" class="close" data-dismiss="alert" aria-label="{__('Generic', 'CLose')}"><span aria-hidden="true">&times;</span></button></div>
{* Global informations about the current poll *}