Skip to content

Commit

Permalink
Add proper "Form\SubmitAnswerController"
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienClairembault committed Aug 6, 2024
1 parent 56a2dad commit e3a6ddd
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 93 deletions.
92 changes: 0 additions & 92 deletions ajax/form/answer.php

This file was deleted.

34 changes: 34 additions & 0 deletions phpunit/functional/Glpi/Form/AnswersSetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
use Glpi\Form\Answer;
use Glpi\Form\AnswersHandler\AnswersHandler;
use Glpi\Form\AnswersSet;
use Glpi\Form\Destination\FormDestinationProblem;
use Glpi\Form\Form;
use Glpi\Form\Question;
use Glpi\Form\QuestionType\QuestionTypeAssignee;
Expand Down Expand Up @@ -304,6 +305,27 @@ public function testGetCreatedItems(): void
// handled in the "FormDestinationTicket" tests class.
}

public function testGetLinksToCreatedItemssForAdmin() {
$this->login();
$form = $this->createAndGetFormWithTwoProblemDestination();

$answers_handler = AnswersHandler::getInstance();
$answers = $answers_handler->saveAnswers($form, [], \Session::getLoginUserID());

$this->assertCount(2, $answers->getLinksToCreatedItems());
}

public function testGetLinksToCreatedItemssForEndUser() {
$this->login("post-only", "postonly");
$form = $this->createAndGetFormWithTwoProblemDestination();

$answers_handler = AnswersHandler::getInstance();
$answers = $answers_handler->saveAnswers($form, [], \Session::getLoginUserID());

// User can't see problems, still there is one fallback link to the answers
$this->assertCount(1, $answers->getLinksToCreatedItems());
}

private function createAndGetFormWithTwoAnswers(): Form
{
$form = $this->createForm(
Expand All @@ -321,4 +343,16 @@ private function createAndGetFormWithTwoAnswers(): Form

return $form;
}

private function createAndGetFormWithTwoProblemDestination(): Form
{
$form = $this->createForm(
(new FormBuilder())
->addQuestion("Name", QuestionTypeShortText::class)
->addDestination(FormDestinationProblem::class, "My first problem")
->addDestination(FormDestinationProblem::class, "My second problem")
);

return $form;
}
}
134 changes: 134 additions & 0 deletions src/Glpi/Controller/Form/SubmitAnswerController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

namespace Glpi\Controller\Form;

use Glpi\Controller\Controller;
use Glpi\Form\AccessControl\FormAccessControlManager;
use Glpi\Form\AccessControl\FormAccessParameters;
use Glpi\Form\AnswersHandler\AnswersHandler;
use Glpi\Form\AnswersSet;
use Glpi\Form\EndUserInputNameProvider;
use Glpi\Form\Form;
use Glpi\Security\Attribute\SecurityStrategy;
use Session;
use Symfony\Component\CssSelector\Exception\InternalErrorException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;

final class SubmitAnswerController implements Controller
{
#[SecurityStrategy('no_check')] // Some forms can be accessed anonymously
#[Route(
"/ajax/Form/SubmitAnswers",
name: "glpi_form_submit_answers",
methods: "POST"
)]
public function __invoke(Request $request): Response
{
$form = $this->loadSubmittedForm($request);
$this->checkFormAccessPolicies($form, $request);

$answers = $this->saveSubmittedAnswers($form, $request);
$links = $answers->getLinksToCreatedItems();

return new JsonResponse([
'links_to_created_items' => $links,
]);
}

private function loadSubmittedForm(Request $request): Form
{
$forms_id = $request->request->getInt("forms_id");
if (!$forms_id) {
throw new BadRequestHttpException(
"The 'forms_id' parameter is mandatory."
);
}

$form = Form::getById($forms_id);
if (!$form) {
throw new NotFoundHttpException("Form not found.");
}

return $form;
}

private function checkFormAccessPolicies(Form $form, Request $request)
{
$form_access_manager = FormAccessControlManager::getInstance();

$parameters = new FormAccessParameters(
session_info: Session::getCurrentSessionInfo(),
url_parameters: $request->request->all(),
);

if (!$form_access_manager->canAnswerForm($form, $parameters)) {
throw new AccessDeniedHttpException(
"You are not allowed to answer this form."
);
}
}

private function saveSubmittedAnswers(
Form $form,
Request $request
): AnswersSet {
$post = $request->request->all();
$answers = (new EndUserInputNameProvider())->getAnswers($post);
if (empty($answers)) {
throw new BadRequestHttpException(
"You must submit at least one answer."
);
}

$handler = AnswersHandler::getInstance();
$answers_set = $handler->saveAnswers(
$form,
$answers,
Session::getLoginUserID()
);
if (!$answers_set) {
throw new InternalErrorException("Failed to save answers.");
}

return $answers_set;
}
}
24 changes: 24 additions & 0 deletions src/Glpi/Form/AnswersSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,30 @@ public function getCreatedItems(): array
return $items;
}

/**
* Get links to created items that are visible for the current user.
*
* @return string[]
*/
public function getLinksToCreatedItems(): array
{
$links = [];
foreach ($this->getCreatedItems() as $item) {
if ($item->canViewItem()) {
$links[] = $item->getLink();
}
}

// If no items were created, display one link to the answers themselves
// TODO: delete this later this we will force at least one ticket to
// be always created.
if (empty($links)) {
$links[] = $this->getLink();
}

return $links;
}

/**
* Count answers for a given form
*
Expand Down
2 changes: 1 addition & 1 deletion templates/pages/form_renderer.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
{# Is this a single or multi sections forms ? #}
{% set is_single_section_form = form.getSections()|length == 1 %}

<form id="forms_form_answers" method="POST" action="{{ path("ajax/form/answer.php") }}">
<form id="forms_form_answers" method="POST" action="{{ path("/ajax/Form/SubmitAnswers") }}">

<div class="container container-narrow form-renderer">

Expand Down

0 comments on commit e3a6ddd

Please sign in to comment.