Commit cefed6c8 authored by Vassilis Kanellopoulos's avatar Vassilis Kanellopoulos Committed by kanellov

application form

parent 34656bdd
......@@ -20,6 +20,7 @@ return [
'module/sch_inventory/bootstrap.php',
'module/sch_sync/bootstrap.php',
'module/schools/bootstrap.php',
'module/application_form/bootstrap.php',
],
'cache_config' => 'data/cache/config/settings.php',
];
......@@ -22,6 +22,12 @@ return [
'callables' => [],
'routes' => [
['/', ['guest', 'user'], ['get']],
['/school', ['school'], ['get']],
['/school/labs', ['school'], ['get', 'post']],
['/school/staff', ['school'], ['get', 'post', 'delete']],
['/school/assets', ['school'], ['get', 'post', 'delete']],
['/school/labs/attachment', ['school'], ['get', 'delete']],
['/application-form', ['school'], ['get', 'post']],
],
],
],
......
......@@ -12,6 +12,7 @@ return [
'web_dir' => __DIR__ . '/../../public',
'paths' => [
'module/schools/public',
'module/application_form/public',
],
],
];
......@@ -8,17 +8,6 @@
*/
return [
'acl' => [
'guards' => [
'routes' => [
['/school', ['school'], ['get']],
['/school/labs', ['school'], ['get', 'post']],
['/school/staff', ['school'], ['get', 'post', 'delete']],
['/school/assets', ['school'], ['get', 'post', 'delete']],
['/school/labs/attachment', ['school'], ['get', 'delete']],
],
],
],
'schools' => [
'file_upload' => [
'tmp_path' => 'data/tmp',
......
......@@ -79,6 +79,13 @@ return function (Slim\App $app) {
return new \Slim\Csrf\Guard();
};
$container[GrEduLabs\Application\Middleware\AddCsrfToView::class] = function ($c) {
return new GrEduLabs\Application\Middleware\AddCsrfToView(
$c->get('view'),
$c->get('csrf')
);
};
$container['GrEduLabs\\Application\\Action\\Index'] = function ($c) {
return new GrEduLabs\Application\Action\Index($c['view']);
};
......
<?php
/**
* gredu_labs.
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
*
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Action\AppForm;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Views\Twig;
class Index
{
protected $view;
public function __construct(Twig $view)
{
$this->view = $view;
}
public function __invoke(Request $req, Response $res, array $args = [])
{
return $this->view->render($res, 'app-form/index.twig', [
'assets' => [
[
'typeName' => 'ΒΙΝΤΕΟΠΡΟΒΟΛΕΑΣ',
'labName' => 'ΕΡΓΑΣΤΗΡΙΟ ΠΛΗΡΟΦ/ΚΗΣ 1',
'quantity' => 2,
],
[
'typeName' => 'LAPTOP',
'labName' => 'ΕΡΓΑΣΤΗΡΙΟ ΠΛΗΡΟΦ/ΚΗΣ 2',
'quantity' => 1,
],
[
'typeName' => 'ΠΛΗΚΤΡΟΛΟΓΙΟ',
'labName' => 'ΕΡΓΑΣΤΗΡΙΟ ΠΛΗΡΟΦ/ΚΗΣ 2',
'quantity' => 10,
],
],
'for_choices' => [
[
'label' => 'ΠΛΗΡΕΣ ΕΡΓΑΣΤΗΡΙΟ',
'value' => 'ΠΛΗΡΕΣ ΕΡΓΑΣΤΗΡΙΟ',
],
[
'label' => 'ΑΝΑΒΑΘΜΙΣΗ ΕΡΓΑΣΤΗΡΙΟΥ',
'value' => 'ΑΝΑΒΑΘΜΙΣΗ ΕΡΓΑΣΤΗΡΙΟΥ',
],
[
'label' => 'ΚΙΝΗΤΟ ΕΡΓΑΣΤΗΡΙΟ',
'value' => 'ΚΙΝΗΤΟ ΕΡΓΑΣΤΗΡΙΟ',
],
],
'lab_choices' => [
[
'value' => 1,
'label' => 'ΕΡΓΑΣΤΗΡΙΟ ΠΛΗΡΟΦ/ΚΗΣ 1',
],
[
'value' => 2,
'label' => 'ΕΡΓΑΣΤΗΡΙΟ ΠΛΗΡΟΦ/ΚΗΣ 2',
],
],
'type_choices' => [
[
'value' => 1,
'label' => 'ΒΙΝΤΕΟΠΡΟΒΟΛΕΑΣ',
],
[
'value' => 3,
'label' => 'LAPTOP',
],
[
'value' => 2,
'label' => 'ΠΛΗΚΤΡΟΛΟΓΙΟ',
],
],
]);
}
}
<?php
/**
* gredu_labs.
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
*
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Application\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Csrf\Guard;
use Slim\Views\Twig;
class AddCsrfToView
{
private $view;
private $csrf;
public function __construct(Twig $view, Guard $csrf)
{
$this->view = $view;
$this->csrf = $csrf;
}
public function __invoke(ServerRequestInterface $req, ResponseInterface $res, callable $next)
{
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
$name = $req->getAttribute($nameKey);
$value = $req->getAttribute($valueKey);
$this->view['csrf'] = [
'name_key' => $nameKey,
'value_key' => $valueKey,
'name' => $name,
'value' => $value,
];
return $next($req, $res);
}
}
<?php
/**
* gredu_labs.
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
*
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
return function (Slim\App $app) {
$container = $app->getContainer();
$events = $container['events'];
$events('on', 'app.autoload', function ($stop, $autoloader) {
$autoloader->addPsr4('GrEduLabs\\ApplicationForm\\', __DIR__ . '/src/');
});
$events('on', 'app.services', function ($stop, $container) {
$container[GrEduLabs\ApplicationForm\Service\ApplicationFormServiceInterface::class] = function ($c) {
return new GrEduLabs\ApplicationForm\Service\ApplicationFormService();
};
$container[GrEduLabs\ApplicationForm\InputFilter\ApplicationForm::class] = function ($c) {
return new GrEduLabs\ApplicationForm\InputFilter\ApplicationForm(
$c->get(GrEduLabs\ApplicationForm\Service\ApplicationFormServiceInterface::class),
$c->get(GrEduLabs\Schools\Service\SchoolServiceInterface::class),
$c->get(GrEduLabs\ApplicationForm\InputFilter\ApplicationFormItemCollection::class)
);
};
$container[GrEduLabs\ApplicationForm\InputFilter\ApplicationFormItem::class] = function ($c) {
return new GrEduLabs\ApplicationForm\InputFilter\ApplicationFormItem(
$c->get(GrEduLabs\Schools\Service\LabServiceInterface::class),
$c->get(GrEduLabs\Schools\Service\AssetServiceInterface::class)
);
};
$container[GrEduLabs\ApplicationForm\InputFilter\ApplicationFormItemCollection::class] = function ($c) {
return new GrEduLabs\ApplicationForm\InputFilter\ApplicationFormItemCollection(
$c->get(GrEduLabs\ApplicationForm\InputFilter\ApplicationFormItem::class)
);
};
$container[GrEduLabs\ApplicationForm\Action\ApplicationForm::class] = function ($c) {
return new GrEduLabs\ApplicationForm\Action\ApplicationForm(
$c->get('view'),
$c->get(GrEduLabs\Schools\Service\AssetServiceInterface::class),
$c->get(GrEduLabs\ApplicationForm\Service\ApplicationFormServiceInterface::class),
$c->get(GrEduLabs\ApplicationForm\InputFilter\ApplicationForm::class)
);
};
});
$events('on', 'app.bootstrap', function ($stop, $app, $container) {
$container['view']->getEnvironment()->getLoader()->prependPath(__DIR__ . '/templates');
$app->map(['get', 'post'], '/application-form', GrEduLabs\ApplicationForm\Action\ApplicationForm::class)
->add(GrEduLabs\Schools\Middleware\FetchSchoolFromIdentity::class)
->add(GrEduLabs\Application\Middleware\AddCsrfToView::class)
->add('csrf')
->setName('application_form');
});
};
<?php
/**
* gredu_labs.
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
*
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\ApplicationForm\Action;
use GrEduLabs\ApplicationForm\Service\ApplicationFormServiceInterface;
use GrEduLabs\Schools\Service\AssetServiceInterface;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Views\Twig;
use Zend\InputFilter\InputFilterInterface;
class ApplicationForm
{
/**
* @var Twig
*/
protected $view;
/**
*
* @var AssetServiceInterface
*/
protected $assetsService;
/**
*
* @var ApplicationFormServiceInterface
*/
protected $appFormService;
/**
*
* @var InputFilterInterface
*/
protected $appFormInputFilter;
public function __construct(
Twig $view,
AssetServiceInterface $assetsService,
ApplicationFormServiceInterface $appFormService,
InputFilterInterface $appFormInputFilter
) {
$this->view = $view;
$this->assetsService = $assetsService;
$this->appFormService = $appFormService;
$this->appFormInputFilter = $appFormInputFilter;
}
public function __invoke(Request $req, Response $res)
{
$school = $req->getAttribute('school');
if ($req->isPost()) {
$this->appFormInputFilter->setData(array_merge($req->getParams(), [
'school_id' => $school->id,
]));
if ($this->appFormInputFilter->isValid()) {
$data = $this->appFormInputFilter->getValues();
$this->appFormService->submit($data);
}
var_dump($this->appFormInputFilter->getMessages());
die('error');
$this->view['messages'] = $this->appFormInputFilter->getMessages();
}
$res = $this->view->render($res, 'application_form/form.twig', [
'type_choices' => array_map(function ($category) {
return ['value' => $category['id'], 'label' => $category['name']];
}, $this->assetsService->getAllItemCategories()),
'apply_for_choices' => array_map(function ($choice) {
return ['value' => $choice, 'label' => $choice];
}, $this->appFormService->getApplyForChoices()),
]);
return $res;
}
}
<?php
/**
* gredu_labs
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\ApplicationForm\InputFilter;
use GrEduLabs\ApplicationForm\Service\ApplicationFormServiceInterface;
use GrEduLabs\Schools\Service\SchoolServiceInterface;
use Zend\Filter;
use Zend\InputFilter\CollectionInputFilter;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator;
class ApplicationForm extends InputFilter
{
public function __construct(
ApplicationFormServiceInterface $appFormService,
SchoolServiceInterface $schoolService,
CollectionInputFilter $itemsInputFilter
) {
$schoolId = new Input('school_id');
$schoolId->setRequired(true)
->getFilterChain()
->attach(new Filter\ToInt());
$schoolId->getValidatorChain()
->attach(new Validator\NotEmpty());
$applyFor = new Input('apply_for');
$applyFor->setRequired(true)
->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\InArray([
'haystack' => $appFormService->getApplyForChoices(),
]));
$newLabPerspective = new Input('new_lab_perspective');
$newLabPerspective->setRequired(true)
->getFilterChain()
->attach(new Filter\ToInt());
$newLabPerspective->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\InArray([
'haystack' => [0, 1],
]));
$comments = new Input('comments');
$comments->setRequired(false)
->getFilterChain()
->attach(new Filter\StripTags())
->attach(new Filter\StringTrim());
$this->add($schoolId)
->add($applyFor)
->add($newLabPerspective)
->add($comments)
->add($itemsInputFilter, 'items')
;
}
}
<?php
/**
* gredu_labs
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\ApplicationForm\InputFilter;
use GrEduLabs\Schools\Service\AssetServiceInterface;
use GrEduLabs\Schools\Service\LabServiceInterface;
use Zend\Filter;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator;
class ApplicationFormItem extends InputFilter
{
public function __construct(
LabServiceInterface $labService,
AssetServiceInterface $assetsService
) {
$lab_id = new Input('lab_id');
$lab_id->setRequired(true)
->getFilterChain()
->attach(new Filter\ToInt());
$lab_id->getValidatorChain()
->attach(new Validator\NotEmpty());
$itemCategoryId = new Input('itemcategory_id');
$itemCategoryId->setRequired(true)
->getFilterChain()
->attach(new Filter\ToInt());
$itemCategoryId->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\Callback([
'callback' => function ($value) use ($assetsService) {
try {
$type = $assetsService->getItemCategoryById($value);
return $type && $type['id'] == $value;
} catch (Exception $ex) {
return false;
}
},
'message' => 'Ο τύπος εξοπλισμού δεν είναι έγκυρος',
]));
$qty = new Input('qty');
$qty->setRequired(true)
->getFilterChain()
->attach(new Filter\ToInt());
$qty->getValidatorChain()
->attach(new Validator\NotEmpty())
->attach(new Validator\GreaterThan([
'min' => 0,
]));
$reasons = new Input('reasons');
$reasons->setRequired(true)
->getFilterChain()
->attach(new Filter\StripTags())
->attach(new Filter\StringTrim());
$reasons->getValidatorChain()
->attach(new Validator\NotEmpty());
$this->add($itemCategoryId)
->add($qty)
->add($reasons);
}
}
<?php
/**
* gredu_labs
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\ApplicationForm\InputFilter;
use Zend\InputFilter\CollectionInputFilter;
use Zend\InputFilter\InputFilterInterface;
class ApplicationFormItemCollection extends CollectionInputFilter
{
public function __construct(InputFilterInterface $itemInputFilter)
{
$this->setInputFilter($itemInputFilter);
}
}
<?php
/**
* gredu_labs.
*
* @link https://github.com/eellak/gredu_labs for the canonical source repository
*
* @copyright Copyright (c) 2008-2015 Greek Free/Open Source Software Society (https://gfoss.ellak.gr/)
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\ApplicationForm\Service;
use RedBeanPHP\R;
class ApplicationFormService implements ApplicationFormServiceInterface
{
protected static $applyForChoices = [
'ΠΛΗΡΕΣ ΕΡΓΑΣΤΗΡΙΟ',
'ΑΝΑΒΑΘΜΙΣΗ ΕΡΓΑΣΤΗΡΙΟΥ',
'ΚΙΝΗΤΟ ΕΡΓΑΣΤΗΡΙΟ',
];
public function getApplyForChoices()
{
return static::$applyForChoices;
}
public function submit(array $data)
{
$appForm = R::dispense('applicationform');
$appForm->school_id = $data['school_id'];
$appForm->apply_for = $data['apply_for'];
$appForm->new_lab_perspective = $data['new_lab_perspective'];
$appForm->comments = $data['comments'];
}
}
......@@ -8,17 +8,11 @@
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Action\AppForm;
namespace GrEduLabs\ApplicationForm\Service;
use Slim\Http\Request;
use Slim\Http\Response;
class SubmitAppForm
interface ApplicationFormServiceInterface
{
public function __invoke(Request $req, Response $res, array $args = [])
{
$params = $req->getParams();
var_dump($params);
die();
}
public function getApplyForChoices();
public function submit(array $data);
}
......@@ -61,50 +61,52 @@
Αίτηση <small>για νέο εξοπλισμό</small>
{% endblock %}
</h1>
<form method="post" action="{{ path_for('app-form.submit') }}">
<form method="post" action="">
<div class="form-group">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent pulvinar tincidunt
odio, vel pretium mauris imperdiet at. In tempor fermentum enim, euismod posuere
purus venenatis sit amet. Sed tincidunt, sapien et varius congue, orci urna rutrum
magna, in porttitor tellus ante nec quam. Praesent non ante commodo, ornare tellus
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent pulvinar tincidunt
odio, vel pretium mauris imperdiet at. In tempor fermentum enim, euismod posuere
purus venenatis sit amet. Sed tincidunt, sapien et varius congue, orci urna rutrum
magna, in porttitor tellus ante nec quam. Praesent non ante commodo, ornare tellus
ut, commodo dolor.</p>
</div>
<fieldset>
<legend>Υπάρχον εξοπλισμός</legend>
<div class="table-responsive">
<table class="table table-hover table-striped table-condensed">
<thead>
<tr>
<th>Χώρος</th>
<th>Τύπος</th>
<th>Πλήθος</th>
</tr>
</thead>
<tbody>
{% for asset in assets %}
<tr>
<td>{{ asset.labName }}</td>
<td>{{ asset.typeName }}</td>
<td>{{ asset.quantity }}</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center">Δεν έχει καταχωρηθεί εξοπλισμός</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="6"></td>
</tr>
</tfoot>
</table>
</div>
</fieldset>
<fieldset>
<legend>Νέος εξοπλισμός</legend>
<div class="form-group" id="items-list">
<div class="table-responsive">
<div class="table-responsive">
<fieldset>
<legend>Υπάρχον εξοπλισμός</legend>
<table class="table table-hover table-striped table-condensed">
<thead>
<tr>
<th>Χώρος</th>
<th>Τύπος</th>
<th>Πλήθος</th>
</tr>
</thead>
<tbody>
{% for asset in assets %}
<tr>
<td>{{ asset.labName }}</td>
<td>{{ asset.typeName }}</td>
<td>{{ asset.quantity }}</td>
</tr>
{% else %}
<tr>
<td colspan="6" class="text-center">Δεν έχει καταχωρηθεί εξοπλισμός</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="6"></td>
</tr>
</tfoot>
</table>
</fieldset>
</div>
<div class="table-responsive">
<fieldset>
<legend>Νέος εξοπλισμός</legend>
<div class="form-group" id="items-list">
<table class="table table-hover table-striped">
<thead>
<tr>
......@@ -128,12 +130,12 @@
</tfoot>
</table>
</div>
</div>
</fieldset>
</fieldset>
</div>
<fieldset>
<legend>Επιπλέον</legend>
{{ macros.select('for', 'Αίτημα του σχολείου για', for_choices) }}
{{ macros.yesno('new-lab-perspective', 'Ύπαρξη - προοπτική αίθουσας για δημιουργία νέου εργαστηρίου')}}
{{ macros.select('apply_for', 'Αίτημα του σχολείου για', apply_for_choices) }}
{{ macros.yesno('new_lab_perspective', 'Ύπαρξη - προοπτική αίθουσας για δημιουργία νέου εργαστηρίου')}}
{{ macros.text('comments', 'Σχόλια/Παρατηρήσεις', '') }}
</fieldset>
......@@ -141,12 +143,14 @@
<div class="form-group text-center">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary">Υποβολή</button>
</div>
<input type="hidden" name="{{ csrf.name_key }}" value="{{ csrf.name }}">
<input type="hidden" name="{{ csrf.value_key }}" value="{{ csrf.value }}">
</form>
<script type="text/template" id="app-form-item-row-template">
<td>{{ macros.itemSelect('lab', 'Χώρος', lab_choices) }}</td>
<td>{{ macros.itemSelect('type', 'Τύπος', type_choices) }}</td>
<td>{{ macros.itemCount('count', 'Πλήθος') }}</td>
<td><textarea class="form-control input-sm" rows="1" cols="20" name="items[<%= index %>][comments]" placeholder="Αιτιολογία χρήσης"></textarea></td>
<td>{{ macros.itemSelect('lab_id', 'Χώρος', lab_choices) }}</td>
<td>{{ macros.itemSelect('itemcategory_id', 'Τύπος', type_choices) }}</td>
<td>{{ macros.itemCount('qty', 'Πλήθος') }}</td>
<td><textarea class="form-control input-sm" rows="1" cols="20" name="items[<%= index %>][reasons]" placeholder="Αιτιολογία χρήσης"></textarea></td>
<td><button type="button" class="btn btn-xs text-danger remove-row">
<i class="fa fa-remove"></i>
</button</td>
......@@ -158,5 +162,5 @@
{{ parent() }}