diff --git a/action/add_comment.php b/action/add_comment.php index 4bdd07c..9d537d2 100644 --- a/action/add_comment.php +++ b/action/add_comment.php @@ -21,6 +21,7 @@ use Framadate\Services\PollService; use Framadate\Services\InputService; use Framadate\Services\MailService; use Framadate\Services\NotificationService; +use Framadate\Services\SecurityService; use Framadate\Message; use Framadate\Utils; use Framadate\Editable; @@ -34,6 +35,7 @@ $poll_id = null; $poll = null; $message = null; $result = false; +$comments = array(); /* Services */ /*----------*/ @@ -43,7 +45,7 @@ $pollService = new PollService($connect, $logService); $inputService = new InputService(); $mailService = new MailService($config['use_smtp']); $notificationService = new NotificationService($mailService); - +$securityService = new SecurityService(); /* PAGE */ /* ---- */ @@ -57,7 +59,9 @@ if (!empty($_POST['poll'])) { if (!$poll) { $message = new Message('error', __('Error', 'This poll doesn\'t exist !')); -} else { +} else if ($poll && !$securityService->canAccessPoll($poll)) { + $message = new Message('error', __('Password', 'Wrong password')); +} else if ($poll) { $name = $inputService->filterName($_POST['name']); $comment = $inputService->filterComment($_POST['comment']); @@ -75,10 +79,9 @@ if (!$poll) { $message = new Message('danger', __('Error', 'Comment failed')); } } + $comments = $pollService->allCommentsByPollId($poll_id); } -$comments = $pollService->allCommentsByPollId($poll_id); - $smarty->error_reporting = E_ALL & ~E_NOTICE; $smarty->assign('comments', $comments); $comments_html = $smarty->fetch('part/comments_list.tpl'); diff --git a/adminstuds.php b/adminstuds.php index ceb0cdb..6416bfb 100644 --- a/adminstuds.php +++ b/adminstuds.php @@ -371,5 +371,7 @@ $smarty->assign('editingVoteId', $editingVoteId); $smarty->assign('message', $message); $smarty->assign('admin', true); $smarty->assign('hidden', false); +$smarty->assign('accessGranted', true); +$smarty->assign('resultPubliclyVisible', true); $smarty->display('studs.tpl'); diff --git a/app/classes/Framadate/Services/SecurityService.php b/app/classes/Framadate/Services/SecurityService.php index fc67a72..a4b6f33 100644 --- a/app/classes/Framadate/Services/SecurityService.php +++ b/app/classes/Framadate/Services/SecurityService.php @@ -2,6 +2,7 @@ namespace Framadate\Services; use Framadate\Security\Token; +use Framadate\Security\PasswordHasher; class SecurityService { @@ -48,5 +49,46 @@ class SecurityService { return $checked; } + /** + * Verify if the current session allows to access given poll. + * + * @param $poll \stdClass The poll which we seek access + * @return bool true if the current session can access this poll + */ + public function canAccessPoll($poll) { + if (is_null($poll->password_hash)) { + return true; + } + + $this->ensureSessionPollSecurityIsCreated(); + + $currentPassword = isset($_SESSION['poll_security'][$poll->id]) ? $_SESSION['poll_security'][$poll->id] : null; + if (!empty($currentPassword) && PasswordHasher::verify($currentPassword, $poll->password_hash)) { + return true; + } else { + unset($_SESSION['poll_security'][$poll->id]); + return false; + } + } + + /** + * Submit to the session a poll password + * + * @param $poll \stdClass The poll which we seek access + * @param $password string the password to compare + */ + public function submitPollAccess($poll, $password) { + if (!empty($password)) { + $this->ensureSessionPollSecurityIsCreated(); + $_SESSION['poll_security'][$poll->id] = $password; + } + } + + private function ensureSessionPollSecurityIsCreated() { + if (!isset($_SESSION['poll_security'])) { + $_SESSION['poll_security'] = array(); + } + } + } \ No newline at end of file diff --git a/css/style.css b/css/style.css index b88ae29..16e1865 100644 --- a/css/style.css +++ b/css/style.css @@ -488,4 +488,10 @@ table.results > tbody > tr:hover > td .glyphicon { /* Admin */ #poll_search { cursor: pointer; +} + +/* Studs */ +.password_request { + padding-top: 15px; + padding-bottom: 15px; } \ No newline at end of file diff --git a/locale/de.json b/locale/de.json index 3390065..4528f34 100644 --- a/locale/de.json +++ b/locale/de.json @@ -156,6 +156,13 @@ "anonyme": "anonym", "Comment added": "Kommentar hinzugefügt" }, + "Password": { + "Password": "DE_Mot de passe", + "Wrong password": "DE_Mot de passe incorrect.", + "Submit access": "DE_Accèder", + "You have to provide a password to access the poll.": "DE_Vous devez donner le mot de passe pour avoir accès à ce sondage.", + "You have to provide a password so you can participate to the poll.": "DE_Vous devez donner le mot de passe pour pouvoir participer à ce sondage." + }, "studs": { "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 an dieser Umfrage teilnehmen möchten, müssen Sie ihren Namen angeben, die Auswahl treffen, die Ihnen am ehesten zusagt und mit dem Plus-Button am Ende der Zeile bestätigen.", "POLL_LOCKED_WARNING": "Die Abstimmung wurde vom Administrator gesperrt. Bewertungen und Kommentare werden eingefroren; es ist nicht mehr möglich, teilzunehmen", diff --git a/locale/en.json b/locale/en.json index 8b004d6..67af1dd 100644 --- a/locale/en.json +++ b/locale/en.json @@ -156,6 +156,13 @@ "anonyme": "anonyme", "Comment added": "Comment saved" }, + "Password": { + "Password": "Password", + "Wrong password": "Wrong password", + "Submit access": "Submit access", + "You have to provide a password to access the poll.": "You have to provide a password to access the poll.", + "You have to provide a password so you can participate to the poll.": "You have to provide a password so you can participate to the poll." + }, "studs": { "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, make your choice, and submit it with the plus button at the end of the line.", "POLL_LOCKED_WARNING": "The administrator locked this poll. Votes and comments are frozen, it is no longer possible to participate", diff --git a/locale/es.json b/locale/es.json index 51a6991..5350b3f 100644 --- a/locale/es.json +++ b/locale/es.json @@ -156,6 +156,13 @@ "anonyme": "ES_anonyme", "Comment added": "ES_Commentaire ajouté" }, + "Password": { + "Password": "ES_Mot de passe", + "Wrong password": "ES_Mot de passe incorrect.", + "Submit access": "ES_Accèder", + "You have to provide a password to access the poll.": "ES_Vous devez donner le mot de passe pour avoir accès à ce sondage.", + "You have to provide a password so you can participate to the poll.": "ES_Vous devez donner le mot de passe pour pouvoir participer à ce sondage." + }, "studs": { "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", diff --git a/locale/fr.json b/locale/fr.json index 4f3cc62..d76e66e 100644 --- a/locale/fr.json +++ b/locale/fr.json @@ -156,6 +156,13 @@ "anonyme": "anonyme", "Comment added": "Commentaire ajouté" }, + "Password": { + "Password": "Mot de passe", + "Wrong password": "Mot de passe incorrect.", + "Submit access": "Accèder", + "You have to provide a password to access the poll.": "Vous devez donner le mot de passe pour avoir accès à ce sondage.", + "You have to provide a password so you can participate to the poll.": "Vous devez donner le mot de passe pour pouvoir participer à ce sondage." + }, "studs": { "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", diff --git a/locale/it.json b/locale/it.json index 0ca5008..81759f0 100644 --- a/locale/it.json +++ b/locale/it.json @@ -156,6 +156,13 @@ "anonyme": "anonimo", "Comment added": "Commento aggiunto" }, + "Password": { + "Password": "IT_Mot de passe", + "Wrong password": "IT_Mot de passe incorrect.", + "Submit access": "IT_Accèder", + "You have to provide a password to access the poll.": "IT_Vous devez donner le mot de passe pour avoir accès à ce sondage.", + "You have to provide a password so you can participate to the poll.": "IT_Vous devez donner le mot de passe pour pouvoir participer à ce sondage." + }, "studs": { "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.": "Per partecipare a questo sondaggio, è necessario inserire vostro nome, scegliere tutti i parametri che preferite e confermare la vostra scelta con il pulsante alla fine della riga.", "POLL_LOCKED_WARNING": "L'amministratore ha bloccato questa indagine. Voti e commenti sono congelati, non è più possibile partecipare", diff --git a/studs.php b/studs.php index c6c4616..d43ff0c 100644 --- a/studs.php +++ b/studs.php @@ -21,6 +21,7 @@ use Framadate\Services\PollService; use Framadate\Services\InputService; use Framadate\Services\MailService; use Framadate\Services\NotificationService; +use Framadate\Services\SecurityService; use Framadate\Message; use Framadate\Utils; use Framadate\Editable; @@ -34,6 +35,11 @@ $poll_id = null; $poll = null; $message = null; $editingVoteId = 0; +$accessGranted = true; +$resultPubliclyVisible = true; +$slots = array(); +$votes = array(); +$comments = array(); /* Services */ /*----------*/ @@ -43,6 +49,7 @@ $pollService = new PollService($connect, $logService); $inputService = new InputService(); $mailService = new MailService($config['use_smtp']); $notificationService = new NotificationService($mailService); +$securityService = new SecurityService(); /* PAGE */ @@ -62,78 +69,114 @@ if (!$poll) { } // ------------------------------- -// A vote is going to be edited +// Password verification // ------------------------------- -if (!empty($_GET['vote'])) { - $editingVoteId = filter_input(INPUT_GET, 'vote', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); +// TEMP, for testing purpose +if (isset($_GET['reset']) && $_GET['reset']) { + unset($_SESSION['poll_security']); } -// ------------------------------- -// Something to save (edit or add) -// ------------------------------- +if (!is_null($poll->password_hash)) { -if (!empty($_POST['save'])) { // Save edition of an old vote - $name = $inputService->filterName($_POST['name']); - $editedVote = filter_input(INPUT_POST, 'save', FILTER_VALIDATE_INT); - $choices = $inputService->filterArray($_POST['choices'], FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => CHOICE_REGEX]]); - - if (empty($editedVote)) { - $message = new Message('danger', __('Error', 'Something is going wrong...')); - } - if (count($choices) != count($_POST['choices'])) { - $message = new Message('danger', __('Error', 'There is a problem with your choices')); + // If we came from password submission + $password = isset($_POST['password']) ? $_POST['password'] : null; + if (!empty($password)) { + $securityService->submitPollAccess($poll, $password); } - if ($message == null) { - // Update vote - $result = $pollService->updateVote($poll_id, $editedVote, $name, $choices); - if ($result) { - 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', __('studs', 'Update vote succeeded')); - } - $notificationService->sendUpdateNotification($poll, NotificationService::UPDATE_VOTE, $name); - } else { - $message = new Message('danger', __('Error', 'Update vote failed')); - } + if (!$securityService->canAccessPoll($poll)) { + $accessGranted = false; } -} elseif (isset($_POST['save'])) { // Add a new vote - $name = $inputService->filterName($_POST['name']); - $choices = $inputService->filterArray($_POST['choices'], FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => CHOICE_REGEX]]); + $resultPubliclyVisible = $poll->results_publicly_visible; - if ($name == null) { - $message = new Message('danger', __('Error', 'The name is invalid.')); - } - if (count($choices) != count($_POST['choices'])) { - $message = new Message('danger', __('Error', 'There is a problem with your choices')); - } - - if ($message == null) { - // Add vote - $result = $pollService->addVote($poll_id, $name, $choices); - if ($result) { - 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', __('studs', 'Adding the vote succeeded')); - } - $notificationService->sendUpdateNotification($poll, NotificationService::ADD_VOTE, $name); - } else { - $message = new Message('danger', __('Error', 'Adding vote failed')); - } + if (!$accessGranted && !empty($password)) { + $message = new Message('danger', __('Password', 'Wrong password')); + } else if (!$accessGranted && !$resultPubliclyVisible) { + $message = new Message('danger', __('Password', 'You have to provide a password to access the poll.')); + } else if (!$accessGranted && $resultPubliclyVisible) { + $message = new Message('danger', __('Password', 'You have to provide a password so you can participate to the poll.')); } } + +// We allow actions only if access is granted +if ($accessGranted) { + + // ------------------------------- + // A vote is going to be edited + // ------------------------------- + + if (!empty($_GET['vote'])) { + $editingVoteId = filter_input(INPUT_GET, 'vote', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => POLL_REGEX]]); + } + + // ------------------------------- + // Something to save (edit or add) + // ------------------------------- + + if (!empty($_POST['save'])) { // Save edition of an old vote + $name = $inputService->filterName($_POST['name']); + $editedVote = filter_input(INPUT_POST, 'save', FILTER_VALIDATE_INT); + $choices = $inputService->filterArray($_POST['choices'], FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => CHOICE_REGEX]]); + + if (empty($editedVote)) { + $message = new Message('danger', __('Error', 'Something is going wrong...')); + } + if (count($choices) != count($_POST['choices'])) { + $message = new Message('danger', __('Error', 'There is a problem with your choices')); + } + + if ($message == null) { + // Update vote + $result = $pollService->updateVote($poll_id, $editedVote, $name, $choices); + if ($result) { + 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', __('studs', 'Update vote succeeded')); + } + $notificationService->sendUpdateNotification($poll, NotificationService::UPDATE_VOTE, $name); + } else { + $message = new Message('danger', __('Error', 'Update vote failed')); + } + } + } elseif (isset($_POST['save'])) { // Add a new vote + $name = $inputService->filterName($_POST['name']); + $choices = $inputService->filterArray($_POST['choices'], FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => CHOICE_REGEX]]); + + if ($name == null) { + $message = new Message('danger', __('Error', 'The name is invalid.')); + } + if (count($choices) != count($_POST['choices'])) { + $message = new Message('danger', __('Error', 'There is a problem with your choices')); + } + + if ($message == null) { + // Add vote + $result = $pollService->addVote($poll_id, $name, $choices); + if ($result) { + 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', __('studs', 'Adding the vote succeeded')); + } + $notificationService->sendUpdateNotification($poll, NotificationService::ADD_VOTE, $name); + } else { + $message = new Message('danger', __('Error', 'Adding vote failed')); + } + } + } } // Retrieve data -$slots = $pollService->allSlotsByPoll($poll); -$votes = $pollService->allVotesByPollId($poll_id); -$comments = $pollService->allCommentsByPollId($poll_id); +if ($resultPubliclyVisible) { + $slots = $pollService->allSlotsByPoll($poll); + $votes = $pollService->allVotesByPollId($poll_id); + $comments = $pollService->allCommentsByPollId($poll_id); +} // Assign data to template $smarty->assign('poll_id', $poll_id); @@ -149,5 +192,7 @@ $smarty->assign('editingVoteId', $editingVoteId); $smarty->assign('message', $message); $smarty->assign('admin', false); $smarty->assign('hidden', $poll->hidden); +$smarty->assign('accessGranted', $accessGranted); +$smarty->assign('resultPubliclyVisible', $resultPubliclyVisible); $smarty->display('studs.tpl'); diff --git a/tpl/part/comments.tpl b/tpl/part/comments.tpl index 7a3ad4a..b9c0fb4 100644 --- a/tpl/part/comments.tpl +++ b/tpl/part/comments.tpl @@ -3,12 +3,11 @@ {* Comment list *} {include 'part/comments_list.tpl'} -
+{* Add comment form *} +{if $active && !$expired && $accessGranted} + - - - {* Add comment form *} - {if $active && !$expired} +
{__('Comments', 'Add a comment to the poll')} @@ -21,11 +20,11 @@
- +
- {/if} -
\ No newline at end of file + +{/if} \ No newline at end of file diff --git a/tpl/part/password_request.tpl b/tpl/part/password_request.tpl new file mode 100644 index 0000000..aff6fe3 --- /dev/null +++ b/tpl/part/password_request.tpl @@ -0,0 +1,18 @@ +{if !$expired && ($active || $resultPubliclyVisible)} + + +
+
+
+ +
+ + + +
+
+
+
+
+{/if} + diff --git a/tpl/part/vote_table_classic.tpl b/tpl/part/vote_table_classic.tpl index bd092ef..e5e5070 100644 --- a/tpl/part/vote_table_classic.tpl +++ b/tpl/part/vote_table_classic.tpl @@ -97,7 +97,7 @@ {/foreach} - {if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin)} + {if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin) && $accessGranted} {__('Generic', 'Edit')} @@ -119,7 +119,7 @@ {* Line to add a new vote *} - {if $active && $editingVoteId === 0 && !$expired} + {if $active && $editingVoteId === 0 && !$expired && $accessGranted}
diff --git a/tpl/part/vote_table_date.tpl b/tpl/part/vote_table_date.tpl index a072a63..8ff1a04 100644 --- a/tpl/part/vote_table_date.tpl +++ b/tpl/part/vote_table_date.tpl @@ -148,7 +148,7 @@ {/foreach} - {if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin)} + {if $active && !$expired && ($poll->editable == constant('Framadate\Editable::EDITABLE_BY_ALL') or $admin) && $accessGranted} {__('Generic', 'Edit')} @@ -170,7 +170,7 @@ {* Line to add a new vote *} - {if $active && $editingVoteId === 0 && !$expired} + {if $active && $editingVoteId === 0 && !$expired && $accessGranted}
diff --git a/tpl/studs.tpl b/tpl/studs.tpl index e5d1113..7e873ab 100644 --- a/tpl/studs.tpl +++ b/tpl/studs.tpl @@ -12,6 +12,7 @@ {block name=main} + {* Messages *}
{if !empty($message)} @@ -20,49 +21,55 @@ + {if !$accessGranted && !$resultPubliclyVisible} - {* Global informations about the current poll *} + {include 'part/password_request.tpl' active=$poll->active} -{include 'part/poll_info.tpl' admin=$admin} - -{* Information about voting *} -{if $expired} -
-

{__('studs', 'The poll is expired, it will be deleted soon.')}

-

{__('studs', 'Deletion date:')} {$deletion_date|date_format:$date_format['txt_short']|html}

-
-{else} - {if $admin} - {include 'part/poll_hint_admin.tpl'} {else} - {include 'part/poll_hint.tpl' active=$poll->active} + + {* Global informations about the current poll *} + {include 'part/poll_info.tpl' admin=$admin} + + {* Information about voting *} + {if $expired} +
+

{__('studs', 'The poll is expired, it will be deleted soon.')}

+

{__('studs', 'Deletion date:')} {$deletion_date|date_format:$date_format['txt_short']|html}

+
+ {else} + {if $admin} + {include 'part/poll_hint_admin.tpl'} + {else} + {include 'part/poll_hint.tpl' active=$poll->active} + {/if} + {/if} + + {* Scroll left and right *} + + + {if !$accessGranted && $resultPubliclyVisible} + {include 'part/password_request.tpl' active=$poll->active} + {/if} + + {* Vote table *} + {if $poll->format === 'D'} + {include 'part/vote_table_date.tpl' active=$poll->active} + {else} + {include 'part/vote_table_classic.tpl' active=$poll->active} + {/if} + + {* Comments *} + {include 'part/comments.tpl' active=$poll->active comments=$comments} + {/if} -{/if} - -{* Scroll left and right *} - - - - -{* Vote table *} - -{if $poll->format === 'D'} - {include 'part/vote_table_date.tpl' active=$poll->active} -{else} - {include 'part/vote_table_classic.tpl' active=$poll->active} -{/if} - -{* Comments *} - -{include 'part/comments.tpl' active=$poll->active comments=$comments} {/block}