diff --git a/admin/migration.php b/admin/migration.php index 1551e9d..25bc733 100644 --- a/admin/migration.php +++ b/admin/migration.php @@ -20,6 +20,8 @@ use Framadate\Migration\From_0_0_to_0_8_Migration; use Framadate\Migration\From_0_8_to_0_9_Migration; use Framadate\Migration\AddColumn_receiveNewComments_For_0_9; +use Framadate\Migration\AddColumn_uniqId_In_vote_For_0_9; +use Framadate\Migration\AddColumn_hidden_In_poll_For_0_9; use Framadate\Migration\Migration; use Framadate\Utils; @@ -31,7 +33,9 @@ set_time_limit(300); $migrations = [ new From_0_0_to_0_8_Migration(), new From_0_8_to_0_9_Migration(), - new AddColumn_receiveNewComments_For_0_9() + new AddColumn_receiveNewComments_For_0_9(), + new AddColumn_uniqId_In_vote_For_0_9(), + new AddColumn_hidden_In_poll_For_0_9(), ]; // --------------------------------------- diff --git a/adminstuds.php b/adminstuds.php index 38c92bf..d4da24b 100644 --- a/adminstuds.php +++ b/adminstuds.php @@ -22,6 +22,7 @@ use Framadate\Services\InputService; use Framadate\Services\LogService; use Framadate\Message; use Framadate\Utils; +use Framadate\Editable; include_once __DIR__ . '/app/inc/init.php'; @@ -45,10 +46,12 @@ $inputService = new InputService(); /* PAGE */ /* ---- */ -if (!empty($_GET['poll']) && strlen($_GET['poll']) === 24) { +if (!empty($_GET['poll'])) { $admin_poll_id = filter_input(INPUT_GET, 'poll', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); - $poll_id = substr($admin_poll_id, 0, 16); - $poll = $pollService->findById($poll_id); + if (strlen($admin_poll_id) === 24) { + $poll_id = substr($admin_poll_id, 0, 16); + $poll = $pollService->findById($poll_id); + } } if (!$poll) { @@ -63,7 +66,7 @@ if (!$poll) { if (isset($_POST['update_poll_info'])) { $updated = false; - $field = $inputService->filterAllowedValues($_POST['update_poll_info'], ['title', 'admin_mail', 'description', 'rules', 'expiration_date', 'name']); + $field = $inputService->filterAllowedValues($_POST['update_poll_info'], ['title', 'admin_mail', 'description', 'rules', 'expiration_date', 'name', 'hidden']); // Update the right poll field if ($field == 'title') { @@ -89,17 +92,22 @@ if (isset($_POST['update_poll_info'])) { switch ($rules) { case 0: $poll->active = false; - $poll->editable = false; + $poll->editable = Editable::NOT_EDITABLE; $updated = true; break; case 1: $poll->active = true; - $poll->editable = false; + $poll->editable = Editable::NOT_EDITABLE; $updated = true; break; case 2: $poll->active = true; - $poll->editable = true; + $poll->editable = Editable::EDITABLE_BY_ALL; + $updated = true; + break; + case 3: + $poll->active = true; + $poll->editable = Editable::EDITABLE_BY_OWN; $updated = true; break; } @@ -116,6 +124,13 @@ if (isset($_POST['update_poll_info'])) { $poll->admin_name = $admin_name; $updated = true; } + } elseif ($field == 'hidden') { + $hidden = filter_input(INPUT_POST, 'hidden', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => BOOLEAN_REGEX]]); + $hidden = $hidden==null?false:true; + if ($hidden != $poll->hidden) { + $poll->hidden = $hidden; + $updated = true; + } } // Update poll in database @@ -131,8 +146,8 @@ if (isset($_POST['update_poll_info'])) { // A vote is going to be edited // ------------------------------- -if (!empty($_POST['edit_vote'])) { - $editingVoteId = filter_input(INPUT_POST, 'edit_vote', FILTER_VALIDATE_INT); +if (!empty($_GET['vote'])) { + $editingVoteId = filter_input(INPUT_GET, 'vote', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); } // ------------------------------- @@ -373,6 +388,7 @@ $smarty->assign('comments', $comments); $smarty->assign('editingVoteId', $editingVoteId); $smarty->assign('message', $message); $smarty->assign('admin', true); +$smarty->assign('hidden', $poll->hidden); $smarty->assign('parameter_name_regex', NAME_REGEX); $smarty->display('studs.tpl'); \ No newline at end of file diff --git a/app/classes/Framadate/Editable.php b/app/classes/Framadate/Editable.php new file mode 100644 index 0000000..142265d --- /dev/null +++ b/app/classes/Framadate/Editable.php @@ -0,0 +1,37 @@ +editable = true; + $this->editable = Editable::EDITABLE_BY_ALL; $this->clearChoices(); } diff --git a/app/classes/Framadate/FramaDB.php b/app/classes/Framadate/FramaDB.php index d9743be..830d50c 100644 --- a/app/classes/Framadate/FramaDB.php +++ b/app/classes/Framadate/FramaDB.php @@ -90,9 +90,9 @@ class FramaDB { } function updatePoll($poll) { - $prepared = $this->prepare('UPDATE `' . Utils::table('poll') . '` SET title=?, admin_name=?, admin_mail=?, description=?, end_date=?, active=?, editable=? WHERE id = ?'); + $prepared = $this->prepare('UPDATE `' . Utils::table('poll') . '` SET title=?, admin_name=?, admin_mail=?, description=?, end_date=?, active=?, editable=?, hidden=? WHERE id = ?'); - return $prepared->execute([$poll->title, $poll->admin_name, $poll->admin_mail, $poll->description, $poll->end_date, $poll->active, $poll->editable, $poll->id]); + return $prepared->execute([$poll->title, $poll->admin_name, $poll->admin_mail, $poll->description, $poll->end_date, $poll->active, $poll->editable, $poll->hidden, $poll->id]); } function allCommentsByPollId($poll_id) { @@ -122,15 +122,16 @@ class FramaDB { return $prepared->execute([$insert_position, $insert_position + 1, $poll_id]); } - function insertVote($poll_id, $name, $choices) { - $prepared = $this->prepare('INSERT INTO `' . Utils::table('vote') . '` (poll_id, name, choices) VALUES (?,?,?)'); - $prepared->execute([$poll_id, $name, $choices]); + function insertVote($poll_id, $name, $choices, $token) { + $prepared = $this->prepare('INSERT INTO `' . Utils::table('vote') . '` (poll_id, name, choices, uniqId) VALUES (?,?,?,?)'); + $prepared->execute([$poll_id, $name, $choices, $token]); $newVote = new \stdClass(); $newVote->poll_id = $poll_id; $newVote->id = $this->pdo->lastInsertId(); $newVote->name = $name; $newVote->choices = $choices; + $newVote->uniqId = $token; return $newVote; } diff --git a/app/classes/Framadate/Message.php b/app/classes/Framadate/Message.php index 9819e00..c7d7ede 100644 --- a/app/classes/Framadate/Message.php +++ b/app/classes/Framadate/Message.php @@ -22,10 +22,12 @@ class Message { var $type; var $message; + var $link; - function __construct($type, $message) { + function __construct($type, $message, $link=null) { $this->type = $type; $this->message = $message; + $this->link = $link; } } diff --git a/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php b/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php new file mode 100644 index 0000000..dd335f9 --- /dev/null +++ b/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php @@ -0,0 +1,77 @@ +query('SHOW TABLES'); + $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN); + + // Check if tables of v0.9 are presents + $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables); + return count($diff) === 0; + } + + /** + * This methode is called only one time in the migration page. + * + * @param \PDO $pdo The connection to database + * @return bool true is the execution succeeded + */ + function execute(\PDO $pdo) { + $this->alterPollTable($pdo); + + return true; + } + + private function alterPollTable(\PDO $pdo) { + $pdo->exec(' + ALTER TABLE `' . Utils::table('poll') . '` + ADD `hidden` TINYINT( 1 ) NOT NULL DEFAULT "0"'); + } + +} diff --git a/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php b/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php index 9f698f9..865502a 100644 --- a/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php +++ b/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php @@ -37,7 +37,7 @@ class AddColumn_receiveNewComments_For_0_9 implements Migration { * @return string The description of the migration class */ function description() { - return "Add column \"receiveNewComments\" for version 0.9"; + return 'Add column "receiveNewComments" for version 0.9'; } /** diff --git a/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php b/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php new file mode 100644 index 0000000..440d2de --- /dev/null +++ b/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php @@ -0,0 +1,79 @@ +query('SHOW TABLES'); + $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN); + + // Check if tables of v0.9 are presents + $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables); + return count($diff) === 0; + } + + /** + * This methode is called only one time in the migration page. + * + * @param \PDO $pdo The connection to database + * @return bool true is the execution succeeded + */ + function execute(\PDO $pdo) { + $this->alterPollTable($pdo); + + return true; + } + + private function alterPollTable(\PDO $pdo) { + $pdo->exec(' + ALTER TABLE `' . Utils::table('vote') . '` + ADD `uniqId` CHAR(16) NOT NULL + AFTER `id`, + ADD INDEX (`uniqId`) ;'); + } + +} diff --git a/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php b/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php index 4e0c0e8..ac985f5 100644 --- a/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php +++ b/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php @@ -37,7 +37,7 @@ class From_0_0_to_0_8_Migration implements Migration { * @return string The description of the migration class */ function description() { - return "First installation of the Framadate application (v0.8)"; + return 'First installation of the Framadate application (v0.8)'; } /** diff --git a/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php b/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php index 2920bd3..bed4fe8 100644 --- a/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php +++ b/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php @@ -37,7 +37,7 @@ class From_0_8_to_0_9_Migration implements Migration { * @return string The description of the migration class */ function description() { - return "From 0.8 to 0.9"; + return 'From 0.8 to 0.9'; } /** diff --git a/app/classes/Framadate/Security/Token.php b/app/classes/Framadate/Security/Token.php index 7222dbf..b4a4b9b 100644 --- a/app/classes/Framadate/Security/Token.php +++ b/app/classes/Framadate/Security/Token.php @@ -5,14 +5,17 @@ class Token { private $time; private $value; + private $length; + private static $codeAlphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789'; - function __construct() { + function __construct($length = 64) { + $this->length = $length; $this->time = time() + TOKEN_TIME; $this->value = $this->generate(); } private function generate() { - return sha1(uniqid(mt_rand(), true)); + return self::getToken($this->length); } public function getTime() { @@ -31,5 +34,58 @@ class Token { return $value === $this->value; } + /** + * Get a secure token if possible, or a less secure one if not. + * + * @param int $length The token length + * @param bool $crypto_strong If passed, tells if the token is "cryptographically strong" or not. + * @return string + */ + public static function getToken($length, &$crypto_strong = false) { + if (function_exists('openssl_random_pseudo_bytes')) { + openssl_random_pseudo_bytes(1, $crypto_strong); // Fake use to see if the algorithm used was "cryptographically strong" + return self::getSecureToken($length); + } + return self::getUnsecureToken($length); + } + + public static function getUnsecureToken($length) { + $string = ''; + mt_srand(); + for ($i = 0; $i < $length; $i++) { + $string .= self::$codeAlphabet[mt_rand() % strlen(self::$codeAlphabet)]; + } + + return $string; + } + + /** + * @author http://stackoverflow.com/a/13733588 + */ + public static function getSecureToken($length){ + $token = ""; + for($i=0;$i<$length;$i++){ + $token .= self::$codeAlphabet[self::crypto_rand_secure(0,strlen(self::$codeAlphabet))]; + } + return $token; + } + + /** + * @author http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322 + */ + private static function crypto_rand_secure($min, $max) { + $range = $max - $min; + if ($range < 0) return $min; // not so random... + $log = log($range, 2); + $bytes = (int) ($log / 8) + 1; // length in bytes + $bits = (int) $log + 1; // length in bits + $filter = (int) (1 << $bits) - 1; // set all lower bits to 1 + do { + $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes))); + $rnd = $rnd & $filter; // discard irrelevant bits + } while ($rnd >= $range); + return $min + $rnd; + } + } \ No newline at end of file diff --git a/app/classes/Framadate/Services/PollService.php b/app/classes/Framadate/Services/PollService.php index cf32713..ad5a1e2 100644 --- a/app/classes/Framadate/Services/PollService.php +++ b/app/classes/Framadate/Services/PollService.php @@ -21,6 +21,7 @@ namespace Framadate\Services; use Framadate\Form; use Framadate\FramaDB; use Framadate\Utils; +use Framadate\Security\Token; class PollService { @@ -66,8 +67,8 @@ class PollService { function addVote($poll_id, $name, $choices) { $choices = implode($choices); - - return $this->connect->insertVote($poll_id, $name, $choices); + $token = $this->random(16); + return $this->connect->insertVote($poll_id, $name, $choices, $token); } function addComment($poll_id, $name, $comment) { @@ -115,6 +116,7 @@ class PollService { $obj = new \stdClass(); $obj->id = $vote->id; $obj->name = $vote->name; + $obj->uniqId = $vote->uniqId; $obj->choices = str_split($vote->choices); $splitted[] = $obj; @@ -176,15 +178,8 @@ class PollService { return [$poll_id, $admin_poll_id]; } - private function random($car) { - // TODO Better random ? - $string = ''; - $chaine = 'abcdefghijklmnopqrstuvwxyz123456789'; - mt_srand(); - for ($i = 0; $i < $car; $i++) { - $string .= $chaine[mt_rand() % strlen($chaine)]; - } - - return $string; + private function random($length) { + return Token::getToken($length); } + } diff --git a/app/classes/Framadate/Utils.php b/app/classes/Framadate/Utils.php index 7491c4f..9c0ab32 100644 --- a/app/classes/Framadate/Utils.php +++ b/app/classes/Framadate/Utils.php @@ -97,23 +97,30 @@ class Utils { } /** - * Fonction permettant de générer les URL pour les sondage - * @param string $id L'identifiant du sondage - * @param bool $admin True pour générer une URL pour l'administration d'un sondage, False pour un URL publique - * @return string L'url pour le sondage + * Function allowing to generate poll's url + * @param string $id The poll's id + * @param bool $admin True to generate an admin URL, false for a public one + * @param string $vote_id (optional) The vote's unique id + * @return string The poll's URL. */ - public static function getUrlSondage($id, $admin = false) { + public static function getUrlSondage($id, $admin = false, $vote_id='') { if (URL_PROPRE) { if ($admin === true) { $url = str_replace('/admin', '', self::get_server_name()) . $id . '/admin'; } else { $url = str_replace('/admin', '', self::get_server_name()) . $id; + if ($vote_id != '') { + $url .= '/vote/'.$vote_id."#edit"; + } } } else { if ($admin === true) { $url = str_replace('/admin', '', self::get_server_name()) . 'adminstuds.php?poll=' . $id; } else { $url = str_replace('/admin', '', self::get_server_name()) . 'studs.php?poll=' . $id; + if ($vote_id != '') { + $url .= '&vote='.$vote_id."#edit"; + } } } diff --git a/app/inc/constants.php b/app/inc/constants.php index 60bab3c..cada2f8 100644 --- a/app/inc/constants.php +++ b/app/inc/constants.php @@ -21,10 +21,11 @@ const VERSION = '0.9'; // Regex -const POLL_REGEX = '/^[a-z0-9]+$/'; +const POLL_REGEX = '/^[a-zA-Z0-9]+$/'; const CHOICE_REGEX = '/^[012]$/'; const NAME_REGEX = '/^[áàâäãåçéèêëíìîïñóòôöõúùûüýÿæœa-z0-9_ -]+$/i'; const BOOLEAN_REGEX = '/^(on|off|true|false|1|0)$/'; +const EDITABLE_CHOICE_REGEX = '/^[0-2]$/'; // CSRF (300s = 5min) const TOKEN_TIME = 300; diff --git a/app/inc/smarty.php b/app/inc/smarty.php index c9bad47..63cea1d 100644 --- a/app/inc/smarty.php +++ b/app/inc/smarty.php @@ -34,8 +34,25 @@ $smarty->assign('html_lang', $html_lang); $smarty->assign('langs', $ALLOWED_LANGUAGES); $smarty->assign('date_format', $date_format); -function smarty_modifier_poll_url($poll_id, $admin = false) { - return Utils::getUrlSondage($poll_id, $admin); +// Dev Mode +if (isset($_SERVER['FRAMADATE_DEVMODE']) && $_SERVER['FRAMADATE_DEVMODE']) { + $smarty->force_compile = true; + $smarty->compile_check = true; + +} else { + $smarty->force_compile = false; + $smarty->compile_check = false; +} + + +function smarty_function_poll_url($params, Smarty_Internal_Template $template) { + $poll_id = filter_var($params['id'], FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); + $admin = (isset($params['admin']) && $params['admin']) ? true : false; + $vote_unique_id = isset($params['vote_id']) ? filter_var($params['vote_id'], FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]) : ''; + + // If filter_var fails (i.e.: hack tentative), it will return false. At least no leak is possible from this. + + return Utils::getUrlSondage($poll_id, $admin, $vote_unique_id); } function smarty_modifier_markdown($md, $clear = false) { diff --git a/composer.lock b/composer.lock index 14618a2..7997006 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "4771fa2616869cff821e2bf1daa6245c", + "hash": "35bdfd24b481ad94a99b6fd67499aba9", "packages": [ { "name": "o80/i18n", @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/olivierperez/o80-i18n.git", - "reference": "830112445b557068b9fe02b576d5cf770fcdf037" + "reference": "669befcdadf3a745193792f51e97af1e70b3e614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/olivierperez/o80-i18n/zipball/830112445b557068b9fe02b576d5cf770fcdf037", - "reference": "830112445b557068b9fe02b576d5cf770fcdf037", + "url": "https://api.github.com/repos/olivierperez/o80-i18n/zipball/669befcdadf3a745193792f51e97af1e70b3e614", + "reference": "669befcdadf3a745193792f51e97af1e70b3e614", "shasum": "" }, "require": { @@ -50,9 +50,7 @@ "internationalization", "php" ], - "time": "2015-03-21 22:37:40" - "time": "2015-03-27 19:37:27" - "time": "2015-03-23 21:40:47" + "time": "2015-03-30 22:20:26" }, { "name": "smarty/smarty", diff --git a/create_poll.php b/create_poll.php index c9b12f4..664182d 100644 --- a/create_poll.php +++ b/create_poll.php @@ -4,20 +4,21 @@ * 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 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 + * 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 STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Rapha�l DROZ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) */ use Framadate\Form; +use Framadate\Editable; use Framadate\Utils; include_once __DIR__ . '/app/inc/init.php'; @@ -45,26 +46,28 @@ $title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_STRING); $name = filter_input(INPUT_POST, 'name', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => NAME_REGEX]]); $mail = filter_input(INPUT_POST, 'mail', FILTER_VALIDATE_EMAIL); $description = filter_input(INPUT_POST, 'description', FILTER_SANITIZE_STRING); -$editable = filter_input(INPUT_POST, 'editable', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => BOOLEAN_REGEX]]); +$editable = filter_input(INPUT_POST, 'editable', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => EDITABLE_CHOICE_REGEX]]); $receiveNewVotes = filter_input(INPUT_POST, 'receiveNewVotes', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => BOOLEAN_REGEX]]); $receiveNewComments = filter_input(INPUT_POST, 'receiveNewComments', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => BOOLEAN_REGEX]]); +$hidden = filter_input(INPUT_POST, 'hidden', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => BOOLEAN_REGEX]]); -// On initialise également les autres variables +// On initialise �galement les autres variables $error_on_mail = false; $error_on_title = false; $error_on_name = false; $error_on_description = false; -// + if (!empty($_POST[GO_TO_STEP_2])) { $_SESSION['form']->title = $title; $_SESSION['form']->admin_name = $name; $_SESSION['form']->admin_mail = $mail; $_SESSION['form']->description = $description; - $_SESSION['form']->editable = ($editable !== null); + $_SESSION['form']->editable = $editable; $_SESSION['form']->receiveNewVotes = ($receiveNewVotes !== null); $_SESSION['form']->receiveNewComments = ($receiveNewComments !== null); + $_SESSION['form']->hidden = ($hidden !== null); if ($config['use_smtp'] == true) { if (empty($mail)) { @@ -174,20 +177,6 @@ if (!empty($_POST[GO_TO_STEP_2])) { } } -// Checkbox checked ? -if ($_SESSION['form']->editable) { - $editable = 'checked'; -} - -if ($_SESSION['form']->receiveNewVotes) { - $receiveNewVotes = 'checked'; -} - -if ($_SESSION['form']->receiveNewComments) { - $receiveNewComments = 'checked'; -} - - $useRemoteUser = USE_REMOTE_USER && isset($_SERVER['REMOTE_USER']); $smarty->assign('title', $title); @@ -204,6 +193,7 @@ $smarty->assign('poll_mail', Utils::fromPostOrDefault('mail', $_SESSION['form']- $smarty->assign('poll_editable', Utils::fromPostOrDefault('editable', $_SESSION['form']->editable)); $smarty->assign('poll_receiveNewVotes', Utils::fromPostOrDefault('receiveNewVotes', $_SESSION['form']->receiveNewVotes)); $smarty->assign('poll_receiveNewComments', Utils::fromPostOrDefault('receiveNewComments', $_SESSION['form']->receiveNewComments)); +$smarty->assign('poll_hidden', Utils::fromPostOrDefault('hidden', $_SESSION['form']->hidden)); $smarty->assign('form', $_SESSION['form']); $smarty->display('create_poll.tpl'); diff --git a/css/style.css b/css/style.css index 469f019..ffac6ca 100644 --- a/css/style.css +++ b/css/style.css @@ -124,6 +124,7 @@ caption { #email-form .btn-edit, #description-form .btn-edit, #poll-rules-form .btn-edit, +#poll-hidden-form .btn-edit, #expiration-form .btn-edit, #name-form .btn-edit { position:absolute; @@ -138,6 +139,8 @@ caption { #description-form:hover .btn-edit, #poll-rules-form .btn-edit:focus, #poll-rules-form:hover .btn-edit, +#poll-hidden-form .btn-edit:focus, +#poll-hidden-form:hover .btn-edit, #expiration-form .btn-edit:focus, #expiration-form:hover .btn-edit, #name-form .btn-edit:focus, @@ -155,7 +158,7 @@ caption { margin-bottom:0; } -#poll-rules-form p, +#poll-rules-form p, #poll-hidden-form p, .jumbotron p.well { font-size:16px; } diff --git a/htaccess.txt b/htaccess.txt new file mode 100644 index 0000000..8b223e9 --- /dev/null +++ b/htaccess.txt @@ -0,0 +1,13 @@ +###################### +# .htaccess example. # +###################### + + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} -f [OR] + RewriteCond %{REQUEST_FILENAME} -d + + RewriteRule ^([a-zA-Z0-9]{16})$ studs.php?poll=$1 + RewriteRule ^([a-zA-Z0-9]{16})/vote/([a-zA-Z0-9]{16})$ studs.php?poll=$1&vote_id=$2 + RewriteRule ^([a-zA-Z0-9]{24})/admin$ adminstuds.php?poll=$1 + \ No newline at end of file diff --git a/js/app/create_poll.js b/js/app/create_poll.js new file mode 100644 index 0000000..66521dc --- /dev/null +++ b/js/app/create_poll.js @@ -0,0 +1,54 @@ +/** + * 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) + */ + +$(document).ready(function () { + + $("#formulaire").submit(function (event) { + var isHidden = $("#hidden").prop('checked'); + var isOptionAllUserCanModifyEverything = $("#editableByAll").is(":checked"); + + if (isHidden && isOptionAllUserCanModifyEverything) { + event.preventDefault(); + $("#hiddenWithBadEditionModeError").removeClass("hidden"); + } else { + $("#hiddenWithBadEditionModeError").addClass("hidden"); + } + }); + + // Check cookies are enabled too + var cookieEnabled = function () { + var cookieEnabled = navigator.cookieEnabled; + + // if not IE4+ nor NS6+ + if (!cookieEnabled && typeof navigator.cookieEnabled === "undefined") { + document.cookie = "testcookie"; + cookieEnabled = document.cookie.indexOf("testcookie") != -1; + } + + return cookieEnabled; + }; + + if (cookieEnabled()) { + // Show the form block + document.getElementById("form-block").setAttribute("style", ""); + } else { + // Show the warning about cookies + document.getElementById("cookie-warning").setAttribute("style", ""); + } + +}); \ No newline at end of file diff --git a/js/app/studs.js b/js/app/studs.js index c19817a..0266c63 100644 --- a/js/app/studs.js +++ b/js/app/studs.js @@ -3,22 +3,22 @@ * 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 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 + * 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 STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) */ $(document).ready(function () { - $(".check-name").click(function (event) { + $("#poll_form").submit(function (event) { var name = $("#name").val(); var regexContent = $("#parameter_name_regex").text().split("/"); var regex = new RegExp(regexContent[1], regexContent[2]); diff --git a/js/core.js b/js/core.js index 3687d49..be4fcbd 100644 --- a/js/core.js +++ b/js/core.js @@ -76,6 +76,20 @@ $(document).ready(function() { return false; }); + $('#poll-hidden-form .btn-edit').on('click', function() { + $('#poll-hidden-form p').hide(); + $('#poll-hidden-form .js-poll-hidden').removeClass("hidden"); + $('.js-poll-hidden input[type=checkbox]').focus(); + return false; + }); + + $('#poll-hidden-form .btn-cancel').on('click', function() { + $('#poll-hidden-form p').show(); + $('#poll-hidden-form .js-poll-hidden').addClass("hidden"); + $('.js-poll-hidden .btn-edit').focus(); + return false; + }); + $('#expiration-form .btn-edit').on('click', function() { $('#expiration-form p').hide(); $('.js-expiration').removeClass("hidden"); diff --git a/locale/de.json b/locale/de.json index 03f6540..5a3512f 100644 --- a/locale/de.json +++ b/locale/de.json @@ -111,9 +111,12 @@ "Votes and comments are locked": "Abstimmungen und Kommentare sind gesperrt", "Votes and comments are open": "Abstimmungen und Kommentare sind möglich", "Votes are editable": "Die Abstimmungen können geändert werden", + "Votes are editable solely by their owner.": "DE_Les votes sont modifiables uniquement par leur créateur", "Save the new rules": "Neue Regeln speichern", "Cancel the rules edit": "Neue Regeln nicht speichern", - "The name is invalid.": "Der Name ist ungültig." + "The name is invalid.": "Der Name ist ungültig.", + "Results are hidden.": "DE_Les résultats sont cachés.", + "Results are visible.": "DE_Les résultats sont visibles." }, "Poll results": { "Votes of the poll": "Abstimmungen der Umfrage ", @@ -144,7 +147,8 @@ "If you want to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line.": "Wenn Sie bei dieser Umfrage abstimmen möchten, müssen Sie ihren Namen angeben. Wählen Sie die Optionen, die für Sie am besten passen und bestätigen Sie diese über den Plus-Button am Ende der Zeile.", "POLL_LOCKED_WARNING": "Die Administration gesperrt diese Umfrage. Bewertungen und Kommentare werden eingefroren, es ist nicht mehr möglich, teilzunehmen", "The poll is expired, it will be deleted soon.": "Die Umfrage ist abgelaufen, es wird bald gelöscht werden.", - "Deletion date:": "Löschdatum:" + "Deletion date:": "Löschdatum:", + "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote:": "DE_Votre vote a bien été pris en compte, mais faites attention : ce sondage n'autorise l'édition de votre vote qu'avec le lien personnalisé suivant ; conservez le précieusement ! " }, "adminstuds": { "As poll administrator, you can change all the lines of this poll with this button": "Als Administrator der Umfrage, können Sie alle Zeilen der Umfrage über diesen Button ändern", @@ -186,9 +190,12 @@ "You are in the poll creation section.": "Sie können hier Umfragen erstellen", "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.", "Go to step 2": "Weiter zum 2. Schritt" }, "Step 2": { @@ -297,6 +304,7 @@ "Framadate is not properly installed, please check the \"INSTALL\" to setup the database before continuing.": "Framadate ist nicht richtig installiert, überprüfen Sie bitte die Schaltfläche \"INSTALL\", um das Setup der Datenbank, bevor Sie fortfahren.", "Failed to save poll": "Fehlgeschlagen Umfrage sparen", "Update vote failed": "Update vote failed", - "Adding vote failed": "Adding vote failed" + "Adding vote failed": "Adding vote failed", + "You can't create a poll with hidden results with the following edition option:": "DE_Vous ne pouvez pas créer de sondage avec résulats cachés avec les options d'éditions suivantes : " } } \ No newline at end of file diff --git a/locale/en.json b/locale/en.json index 5403eef..5e03ef4 100644 --- a/locale/en.json +++ b/locale/en.json @@ -112,9 +112,12 @@ "Votes and comments are locked": "Votes and comments are locked", "Votes and comments are open": "Votes and comments are open", "Votes are editable": "Votes are editable", + "Votes are editable solely by their owner.": "Votes are editable solely by their owner", "Save the new rules": "Save the new rules", "Cancel the rules edit": "Cancel the rules edit", - "The name is invalid.": "The name is invalid." + "The name is invalid.": "The name is invalid.", + "Results are hidden.": "Results are hidden.", + "Results are visible.": "Results are visible." }, "Poll results": { "Votes of the poll": "Votes of the poll", @@ -145,7 +148,8 @@ "If you want to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line.": "If you want to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line.", "POLL_LOCKED_WARNING": "The administration locked this poll. Votes and comments are frozen, it is no longer possible to participate", "The poll is expired, it will be deleted soon.": "The poll is expired, it will be deleted soon.", - "Deletion date:": "Deletion date:" + "Deletion date:": "Deletion date:", + "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote:": "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote." }, "adminstuds": { "As poll administrator, you can change all the lines of this poll with this button": "As poll administrator, you can change all the lines of this poll with this button", @@ -187,9 +191,12 @@ "You are in the poll creation section.": "You are in the poll creation section.", "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.", "Go to step 2": "Go to step 2" }, "Step 2": { @@ -298,6 +305,7 @@ "Framadate is not properly installed, please check the \"INSTALL\" to setup the database before continuing.": "Framadate is not properly installed, please check the 'INSTALL' to setup the database before continuing.", "Failed to save poll": "Failed to save poll", "Update vote failed": "Update vote failed", - "Adding vote failed": "Adding vote failed" + "Adding vote failed": "Adding vote 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: " } } \ No newline at end of file diff --git a/locale/es.json b/locale/es.json index a11b5c7..601c291 100644 --- a/locale/es.json +++ b/locale/es.json @@ -111,9 +111,12 @@ "Votes and comments are locked": "ES_Les votes et commentaires sont verrouillés", "Votes and comments are open": "ES_Les votes et commentaires sont ouverts", "Votes are editable": "ES_Les votes sont modifiables", + "Votes are editable solely by their owner.": "ES_Les votes sont modifiables uniquement par leur créateur", "Save the new rules": "ES_Enregistrer les nouvelles permissions", "Cancel the rules edit": "ES_Annuler le changement de permissions", - "The name is invalid.": "ES_Le nom n'est pas valide." + "The name is invalid.": "ES_Le nom n'est pas valide.", + "Results are hidden.": "ES_Les résultats sont cachés.", + "Results are visible.": "ES_Les résultats sont visibles." }, "Poll results": { "Votes of the poll": "ES_Votes du sondage", @@ -144,7 +147,8 @@ "If you want to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line.": "Para participar a esta encuesta, introduzca su nombre, elige todas las valores que son apriopriadas y validar su seleccion con el botón verde a la fin de línea.", "POLL_LOCKED_WARNING": "ES_L'administrateur a verrouillé ce sondage. Les votes et commentaires sont gelés, il n'est plus possible de participer", "The poll is expired, it will be deleted soon.": "ES_Le sondage a expiré, il sera bientôt supprimé.", - "Deletion date:": "ES_Date de suppression :" + "Deletion date:": "ES_Date de suppression :", + "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote:": "ES_Votre vote a bien été pris en compte, mais faites attention : ce sondage n'autorise l'édition de votre vote qu'avec le lien personnalisé suivant ; conservez le précieusement ! " }, "adminstuds": { "As poll administrator, you can change all the lines of this poll with this button": "En calidad de administrador, Usted puede cambiar todas la líneas de este encuesta con este botón", @@ -186,9 +190,12 @@ "You are in the poll creation section.": "Usted ha eligiendo de crear une nueva encuesta!", "Required fields cannot be left blank.": "Gracias por completar los campos con una *.", "Poll title": "ES_Titre du sondage", - "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.", + "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.", "Go to step 2": "ES_Aller à l'étape 2" }, "Step 2": { @@ -297,6 +304,7 @@ "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", "Update vote failed": "ES_Mise à jour du vote échoué", - "Adding vote failed": "ES_Ajout d'un vote échoué" + "Adding vote failed": "ES_Ajout d'un vote é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 : " } } \ No newline at end of file diff --git a/locale/fr.json b/locale/fr.json index a962f1a..31bb497 100644 --- a/locale/fr.json +++ b/locale/fr.json @@ -111,9 +111,12 @@ "Votes and comments are locked": "Les votes et commentaires sont verrouillés", "Votes and comments are open": "Les votes et commentaires sont ouverts", "Votes are editable": "Les votes sont modifiables", + "Votes are editable solely by their owner.": "Les votes sont modifiables uniquement par leur créateur", "Save the new rules": "Enregistrer les nouvelles permissions", "Cancel the rules edit": "Annuler le changement de permissions", - "The name is invalid.": "Le nom n'est pas valide." + "The name is invalid.": "Le nom n'est pas valide.", + "Results are hidden.": "Les résultats sont cachés.", + "Results are visible.": "Les résultats sont visibles." }, "Poll results": { "Votes of the poll": "Votes du sondage", @@ -144,7 +147,8 @@ "If you want to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line.": "Pour participer à ce sondage, veuillez entrer votre nom, choisir toutes les valeurs qui vous conviennent et valider votre choix avec le bouton en bout de ligne.", "POLL_LOCKED_WARNING": "L'administrateur a verrouillé ce sondage. Les votes et commentaires sont gelés, il n'est plus possible de participer", "The poll is expired, it will be deleted soon.": "Le sondage a expiré, il sera bientôt supprimé.", - "Deletion date:": "Date de suppression :" + "Deletion date:": "Date de suppression :", + "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote:": "Votre vote a bien été pris en compte, mais faites attention : ce sondage n'autorise l'édition de votre vote qu'avec le lien personnalisé suivant ; conservez le précieusement ! " }, "adminstuds": { "As poll administrator, you can change all the lines of this poll with this button": "En tant qu'administrateur, vous pouvez modifier toutes les lignes de ce sondage avec ce bouton", @@ -186,9 +190,12 @@ "You are in the poll creation section.": "Vous avez choisi de créer un nouveau sondage.", "Required fields cannot be left blank.": "Merci de remplir les champs obligatoires, marqués d'une *.", "Poll title": "Titre du sondage", - "Voters can modify their vote themselves.": "Vous souhaitez que les sondés puissent modifier leur ligne eux-mêmes.", + "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.", "Go to step 2": "Aller à l'étape 2" }, "Step 2": { @@ -297,6 +304,7 @@ "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", "Update vote failed": "Mise à jour du vote échoué", - "Adding vote failed": "Ajout d'un vote échoué" + "Adding vote failed": "Ajout d'un vote é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 : " } } diff --git a/studs.php b/studs.php index 461d86d..0d360d2 100644 --- a/studs.php +++ b/studs.php @@ -22,6 +22,7 @@ use Framadate\Services\InputService; use Framadate\Services\MailService; use Framadate\Message; use Framadate\Utils; +use Framadate\Editable; include_once __DIR__ . '/app/inc/init.php'; @@ -93,7 +94,9 @@ function sendUpdateNotification($poll, $mailService, $name, $type) { if (!empty($_GET['poll'])) { $poll_id = filter_input(INPUT_GET, 'poll', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); - $poll = $pollService->findById($poll_id); + if (strlen($poll_id) === 16) { + $poll = $pollService->findById($poll_id); + } } if (!$poll) { @@ -106,8 +109,8 @@ if (!$poll) { // A vote is going to be edited // ------------------------------- -if (!empty($_POST['edit_vote'])) { - $editingVoteId = filter_input(INPUT_POST, 'edit_vote', FILTER_VALIDATE_INT); +if (!empty($_GET['vote'])) { + $editingVoteId = filter_input(INPUT_GET, 'vote', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); } // ------------------------------- @@ -130,7 +133,13 @@ if (!empty($_POST['save'])) { // Save edition of an old vote // Update vote $result = $pollService->updateVote($poll_id, $editedVote, $name, $choices); if ($result) { - $message = new Message('success', _('Update vote successfully.')); + if ($poll->editable == Editable::EDITABLE_BY_OWN) { + $editedVoteUniqId = filter_input(INPUT_POST, 'edited_vote', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); + $urlEditVote = Utils::getUrlSondage($poll_id, false, $editedVoteUniqId); + $message = new Message('success', __('studs', "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote:"), $urlEditVote); + } else { + $message = new Message('success', _('Update vote successfully.')); + } sendUpdateNotification($poll, $mailService, $name, UPDATE_VOTE); } else { $message = new Message('danger', _('Update vote failed.')); @@ -151,7 +160,12 @@ if (!empty($_POST['save'])) { // Save edition of an old vote // Add vote $result = $pollService->addVote($poll_id, $name, $choices); if ($result) { - $message = new Message('success', _('Update vote successfully.')); + if ($poll->editable == Editable::EDITABLE_BY_OWN) { + $urlEditVote = Utils::getUrlSondage($poll_id, false, $result->uniqId); + $message = new Message('success', __('studs', "Your vote has been registered successfully, but be careful: regarding this poll options, you need to keep this personal link to edit your own vote:"), $urlEditVote); + } else { + $message = new Message('success', _('Update vote successfully.')); + } sendUpdateNotification($poll, $mailService, $name, ADD_VOTE); } else { $message = new Message('danger', _('Update vote failed.')); @@ -202,6 +216,7 @@ $smarty->assign('comments', $comments); $smarty->assign('editingVoteId', $editingVoteId); $smarty->assign('message', $message); $smarty->assign('admin', false); +$smarty->assign('hidden', $poll->hidden); $smarty->assign('parameter_name_regex', NAME_REGEX); $smarty->display('studs.tpl'); diff --git a/tpl/add_slot.tpl b/tpl/add_slot.tpl index a8593e1..3ef5e5e 100644 --- a/tpl/add_slot.tpl +++ b/tpl/add_slot.tpl @@ -1,7 +1,7 @@ {extends file='page.tpl'} {block name=main} -
+

{__('adminstuds', 'Column\'s adding')}

diff --git a/tpl/admin/polls.tpl b/tpl/admin/polls.tpl index e26e3ae..53bbd1f 100644 --- a/tpl/admin/polls.tpl +++ b/tpl/admin/polls.tpl @@ -91,11 +91,11 @@ {/if} {$poll->votes|html} {$poll->id|html} - {__('Admin', 'See the poll')} - {__('Admin', 'Change the poll')} diff --git a/tpl/confirm/delete_comments.tpl b/tpl/confirm/delete_comments.tpl index c94bf10..bd9642f 100644 --- a/tpl/confirm/delete_comments.tpl +++ b/tpl/confirm/delete_comments.tpl @@ -1,7 +1,7 @@ {extends file='page.tpl'} {block name=main} - +

{__('adminstuds', 'Confirm removal of all comments of the poll')}

diff --git a/tpl/confirm/delete_poll.tpl b/tpl/confirm/delete_poll.tpl index 9db0777..7bba15a 100644 --- a/tpl/confirm/delete_poll.tpl +++ b/tpl/confirm/delete_poll.tpl @@ -1,7 +1,7 @@ {extends file='page.tpl'} {block name=main} - +

{__('adminstuds', 'Confirm removal of the poll')}

diff --git a/tpl/confirm/delete_votes.tpl b/tpl/confirm/delete_votes.tpl index ed863b1..38faf64 100644 --- a/tpl/confirm/delete_votes.tpl +++ b/tpl/confirm/delete_votes.tpl @@ -1,7 +1,7 @@ {extends file='page.tpl'} {block name=main} - +

{__('adminstuds', 'Confirm removal of all votes of the poll')}

diff --git a/tpl/create_poll.tpl b/tpl/create_poll.tpl index ec0e665..7d49a76 100644 --- a/tpl/create_poll.tpl +++ b/tpl/create_poll.tpl @@ -1,5 +1,9 @@ {extends file='page.tpl'} +{block name="header"} + +{/block} + {block name=main}