Commit 1a6dfd93 authored by kanellov's avatar kanellov

labs completed

parent ec0782e2
......@@ -15,11 +15,13 @@ return [
['/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',
'target_path' => 'data/uploads',
],
],
......
......@@ -28,7 +28,7 @@ return function (Slim\App $app) {
$container['settings']['db']['user'],
$container['settings']['db']['pass']
);
// RedBeanPHP\R::freeze();
RedBeanPHP\R::freeze();
// RedBeanPHP\R::debug( true );
$container['view'] = function ($c) {
......
......@@ -66,6 +66,22 @@ return function (Slim\App $app) {
);
};
$container[Action\Lab\DownloadAttachment::class] = function ($c) {
$settings = $c->get('settings');
$uploadTargetPath = $settings['schools']['file_upload']['target_path'];
return new Action\Lab\DownloadAttachment(
$c->get(Service\LabServiceInterface::class),
$uploadTargetPath
);
};
$container[Action\Lab\RemoveAttachment::class] = function ($c) {
return new Action\Lab\RemoveAttachment(
$c->get(Service\LabServiceInterface::class)
);
};
$container[Action\Assets\ListAssets::class] = function ($c) {
return new Action\Assets\ListAssets(
$c->get('view'),
......@@ -110,7 +126,10 @@ return function (Slim\App $app) {
};
$container[Service\LabServiceInterface::class] = function ($c) {
return new Service\LabService();
$settings = $c->get('settings');
$uploadTargetPath = $settings['schools']['file_upload']['target_path'];
return new Service\LabService($uploadTargetPath);
};
$container[Service\AssetServiceInterface::class] = function ($c) {
......@@ -166,9 +185,10 @@ return function (Slim\App $app) {
$container[InputFilter\Lab::class] = function ($c) {
$settings = $c->get('settings');
$fileUploadSettings = $settings['schools']['file_upload'];
$uploadTmpPath = $settings['schools']['file_upload']['tmp_path'];
return new InputFilter\Lab(
$fileUploadSettings,
$uploadTmpPath,
$c->get(Service\LabServiceInterface::class)
);
};
......@@ -188,8 +208,11 @@ return function (Slim\App $app) {
$this->delete('/staff', Action\Staff\DeleteTeacher::class);
$this->get('/labs', Action\Lab\ListAll::class)->setName('school.labs');
$this->post('/labs', Action\Lab\PersistLab::class)->setName('school.labcreate')
$this->post('/labs', Action\Lab\PersistLab::class)
->add(Middleware\InputFilterLab::class);
$this->get('/labs/attachment', Action\Lab\DownloadAttachment::class)
->setName('school.labs.attachment');
$this->delete('/labs/attachment', Action\Lab\RemoveAttachment::class);
$this->get('/assets', Action\Assets\ListAssets::class)->setName('school.assets');
$this->post('/assets', Action\Assets\PersistAsset::class)
......
......@@ -241,19 +241,6 @@ INSERT INTO `itemcategory` VALUES (8,'ACCESS POINT'),(26,'LAPTOP'),(7,'MEDIA CON
/*!40000 ALTER TABLE `itemcategory` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `lesson`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `lesson` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `lab`
--
......@@ -269,6 +256,7 @@ CREATE TABLE `lab` (
`use_ext_program` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`use_in_program` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`attachment` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`attachment_mime` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`has_network` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`has_server` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`school_id` int(11) unsigned DEFAULT NULL,
......@@ -281,6 +269,43 @@ CREATE TABLE `lab` (
COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `labtype`
--
DROP TABLE IF EXISTS `labtype`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `labtype` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `labtype`
--
LOCK TABLES `labtype` WRITE;
/*!40000 ALTER TABLE `labtype` DISABLE KEYS */;
INSERT INTO `labtype` VALUES (1,' ΕΡΓΑΣΤΗΡΙΟ ΠΛΗΡ/ΚΗΣ'),(2,'ΕΡΓΑΣΤΗΡΙΟ ΦΥΣΙΚΩΝ ΕΠΙΣΤΗΜΩΝ'),(3,'ΕΡΓΑΣΤΗΡΙΟ ΤΕΧΝΟΛΟΓΙΑΣ'),(4,'ΑΛΛΟ ΕΡΓΑΣΤΗΡΙΟ '),(5,'ΓΩΝΙΑ ΥΠΟΛΟΓΙΣΤΗ'),(6,'ΒΙΒΛΙΟΘΗΚΗ'),(7,'ΑΙΘΟΥΣΑ ΔΙΔΑΣΚΑΛΙΑΣ'),(8,'ΑΛΛΗ ΑΙΘΟΥΣΑ');
/*!40000 ALTER TABLE `labtype` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `lesson`
--
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `lesson` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `lesson_lab`
......
......@@ -85,9 +85,10 @@
el: '#lab-form-modal',
form: null,
lab: null,
attachment: null,
url: null,
events: {
// 'submit': 'persistLab',
'submit': 'persistLab',
'click button.remove': 'removeLab'
},
initialize: function () {
......@@ -99,31 +100,12 @@
that.form[0].reset();
that.form.find('input[type="hidden"]').val('');
});
this.form.find('input[type="file"]').fileupload({
url: that.form.data('url'),
multipart: true,
submit: function (e, data) {
data.formData = utils.serializeObject(that.form);
data.jqXHR = $(this).fileupload('send', data);
return false;
},
done: function (response) {
if (that.lab) {
that.lab.set(response);
} else {
that.model.add(response);
}
that.hide();
},
fail: function (xhr, err) {
var messages;
if (422 === xhr.status) {
messages = JSON.parse(xhr.responseText).messages || {};
utils.formMessages.render(that.form, messages);
} else {
alert('Προέκυψε κάποιο σφάλμα');
}
}
this.attachment = this.form.find('.uploaded');
this.attachment.on('click', 'a.btn-remove', function (evt) {
var url;
evt.preventDefault();
url = $(evt.target).closest('a').attr('href');
that.removeAttachment(url);
});
},
render: function (labId) {
......@@ -145,12 +127,20 @@
var name;
element = $(element);
name = element.attr('name');
if ('file' === element.attr('type')) return;
if ('checkbox' === element.attr('type')) {
element.prop('checked', utils.parseInt(labAttributes[name]));
} else {
element.val(labAttributes[name] || '');
}
});
if (!this.lab || !this.lab.get('attachment')) {
this.attachment.find('a').attr('href', '#');
this.attachment.hide();
} else {
this.attachment.find('a').attr('href', this.attachment.data('href').replace('__lab_id__', this.lab.get('id')));
this.attachment.show();
}
this.show();
return this;
},
......@@ -162,52 +152,43 @@
this.$el.modal('hide');
return this;
},
// persistLab: function (evt) {
// var formData = utils.serializeObject(this.form),
// that = this,
// upload = this.form.find('input[type="file"]');
// evt.preventDefault();
// upload
// $('#fileupload').fileupload('send', {
// files: upload[0].files
// });
////
//// ({
//// url: that.url,
//// submit: function (e, data) {
//// var $this = $(this);
//// data.formData = formData;
//// data.jqXHR = $this.fileupload('send', data);
//// return false;
//// },
//// done: function (response) {
//// if (that.lab) {
//// that.lab.set(response);
//// } else {
//// that.model.add(response);
//// }
//// that.hide();
//// },
//// error: function (xhr, err) {
//// var messages;
//// if (422 === xhr.status) {
//// messages = JSON.parse(xhr.responseText).messages || {};
//// utils.formMessages.render(that.form, messages);
//// } else {
//// alert('Προέκυψε κάποιο σφάλμα');
//// }
//// }
//// });
//// upload.fileupload('send');
// upload.fileupload('destroy');
////
//// $.ajax({
//// url: that.url,
//// type: 'post',
//// contentType: 'multipart/form-data',
//// data: data,
//// }).).fail(function );
// },
persistLab: function (evt) {
var formData = utils.serializeObject(this.form),
that = this,
upload = this.form.find('input[type="file"]').fileupload({
autoUpload: false
}),
postPromise;
evt.preventDefault();
if (upload[0].files.length === 0) {
postPromise = $.ajax({
url: that.url,
type: 'post',
data: formData
});
} else {
postPromise = upload.fileupload('send', {files: upload[0].files});
}
postPromise.done(function (response) {
if (that.lab) {
that.lab.set(response);
} else {
that.model.add(response);
}
that.hide();
}).fail(function (xhr, err) {
var messages;
if (xhr && 422 === xhr.status) {
messages = JSON.parse(xhr.responseText).messages || {};
utils.formMessages.render(that.form, messages);
} else {
alert('Προέκυψε κάποιο σφάλμα');
}
});
upload.fileupload('destroy');
},
removeLab: function(evt) {
var that = this;
if (!confirm('Να διαγραφεί ο χώρος;')) {
......@@ -227,6 +208,22 @@
alert('Δεν ήταν δυνατή η διαγραφή του χώρου');
});
},
removeAttachment: function (url) {
var that = this;
if (!confirm('Να διαγραφή το αρχείο;')) {
return;
}
$.ajax({
url: url,
type: 'delete',
}).done(function (response) {
that.lab.set('attachment', null);
that.lab.set('attachment_mime', null);
that.attachment.hide();
}).fail(function () {
alert('Δεν ήταν δυνατή η διαγραφή του αρχείου');
});
}
});
......
<?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\Schools\Action\Lab;
use GrEduLabs\Schools\Service\LabServiceInterface;
use Slim\Http\Request;
use Slim\Http\Response;
class DownloadAttachment
{
private $labService;
private $uploadDir;
public function __construct(LabServiceInterface $labService, $uploadDir)
{
$this->labService = $labService;
$this->uploadDir = $uploadDir;
}
public function __invoke(Request $req, Response $res)
{
$school = $req->getAttribute('school', false);
if (!$school) {
return $res->withStatus(403, 'No school');
}
$lab_id = $req->getParam('lab_id', false);
if (!$lab_id) {
return $res->withStatus(404, 'No lab id');
}
$lab = $this->labService->getLabForSchool($school->id, $lab_id);
if ($lab['attachment'] && is_readable($this->uploadDir . '/' . $lab['attachment'])) {
$contents = file_get_contents($this->uploadDir . '/' . $lab['attachment']);
$contentType = $lab['attachment_mime'] ? $lab['attachment_mime'] : 'application/octet-stream';
$res = $res->withHeader('Content-Type', $contentType);
$res = $res->withHeader(
'Content-Disposition',
'filename="' . basename($lab['attachment']) . '"'
);
$res->getBody()->write($contents);
} else {
$res->withStatus(404, 'No attachment');
}
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\Schools\Action\Lab;
use GrEduLabs\Schools\Service\LabServiceInterface;
use Slim\Http\Request;
use Slim\Http\Response;
class RemoveAttachment
{
private $labService;
public function __construct(LabServiceInterface $labService)
{
$this->labService = $labService;
}
public function __invoke(Request $req, Response $res)
{
$school = $req->getAttribute('school', false);
if (!$school) {
return $res->withStatus(403, 'No school');
}
$lab_id = $req->getParam('lab_id', false);
if (!$lab_id) {
return $res->withStatus(404, 'No lab id');
}
$lab = $this->labService->getLabForSchool($school->id, $lab_id);
try {
$this->labService->removeLabAttachment($lab['id']);
return $res->withStatus(204);
} catch (Exception $ex) {
return $res->withStatus(500, $ex->getMessage());
}
}
}
......@@ -17,7 +17,7 @@ trait InputFilterTrait
{
$this->inputFilter->setData($data);
$isValid = $this->inputFilter->isValid();
return [
'is_valid' => $isValid,
'values' => $isValid ? $this->inputFilter->getValues() : [],
......
......@@ -19,9 +19,9 @@ use Zend\Validator;
class Lab
{
use InputFilterTrait;
public function __construct(
array $fileUploadSettings,
$uploadTmpPath,
LabServiceInterface $labService
) {
$id = new Input('id');
......@@ -57,17 +57,17 @@ class Lab
$lessons->setRequired(false);
$lessons->getValidatorChain()
->attach(new Validator\NotEmpty());
$attachment = new FileInput('attachment');
$attachment->setRequired(false)
->getFilterChain()
->attach(new Filter\File\RenameUpload([
'target' => $fileUploadSettings['target_path'],
'target' => $uploadTmpPath,
'randomize' => true,
]));
$attachment->getValidatorChain()
->attach(new Validator\File\UploadFile());
$use_ext_program= new Input('use_ext_program');
$use_ext_program->setRequired(false);
......@@ -80,7 +80,7 @@ class Lab
->attach(new Validator\NotEmpty())->attach(new Validator\InArray([
'haystack' => $labService->getHasNetworkValues(),
]));
$has_server = new Input('has_server');
$has_server->setRequired(false);
$has_server->getValidatorChain()
......
......@@ -16,21 +16,18 @@ use Slim\Http\Response;
class InputFilterLab
{
private $inputFilter;
public function __construct(callable $inputFilter)
{
$this->inputFilter = $inputFilter;
}
public function __invoke(Request $req, Response $res, callable $next)
{
$data = array_merge_recursive($req->getParams(), $req->getUploadedFiles());
$data = array_merge_recursive($req->getParams(), $_FILES);
$inputFilter = $this->inputFilter;
$result = $inputFilter($data);
var_dump($req->getParams(), $req->getUploadedFiles(), $data);
die();
if (!$result['is_valid']) {
$res = $res->withStatus(422, 'validation error');
$res->withJson($result);
......
......@@ -10,10 +10,17 @@
namespace GrEduLabs\Schools\Service;
use InvalidArgumentException;
use RedBeanPHP\OODBBean;
use RedBeanPHP\R;
class LabService implements LabServiceInterface
{
private $filesPath;
public function __construct($filesPath)
{
$this->filesPath = $filesPath;
}
public function createLab(array $data)
{
......@@ -44,11 +51,11 @@ class LabService implements LabServiceInterface
$lab->sharedLesson = $this->getLessonsById($data['lessons']);
$lab->use_ext_program = $data['use_ext_program'];
$lab->use_in_program = $data['use_in_program'];
$lab->attachment = $data['attachment'];
$lab->has_network = $data['has_network'];
$lab->has_server = $data['has_server'];
$lab->responsible = R::load('teacher', $data['responsible_id']);
R::store($lab);
$this->storeAttachement($lab, $data['attachment']);
R::store($lab);
}
......@@ -123,6 +130,27 @@ class LabService implements LabServiceInterface
]);
}
private function storeAttachement(OODBBean $lab, array $attachment = null)
{
if (null === $attachment) {
return;
}
$schoolPath = $lab->school->registry_no . '/lab_' . $lab->id;
$fullPath = $this->filesPath . '/' . $schoolPath;
if (!is_dir($fullPath)) {
mkdir($fullPath, 0700, true);
}
// remove previous
unlink($this->filesPath . '/' . $lab->attachment);
// move new file
rename($attachment['tmp_name'], $fullPath . '/' . $attachment['name']);
$lab->attachment = $schoolPath . '/' . $attachment['name'];
$lab->attachment_mime = $attachment['type'];
return $lab;
}
public function getHasNetworkValues()
{
return [
......@@ -136,4 +164,37 @@ class LabService implements LabServiceInterface
{
return ['ΝΑΙ', 'ΟΧΙ'];
}
public function getLabForSchool($school_id, $id)
{
$lab = R::findOne('lab', ' school_id = ? AND id = ? ', [
$school_id,
$id,
]);
if (!$lab) {
return;
}
return $this->exportLab($lab);
}
public function removeLabAttachment($lab_id)
{
$lab = R::load('lab', $lab_id);
if (!$lab->id) {
throw new InvalidArgumentException('No lab');
}
if (!$lab->attachment) {
return ;
}
if (is_writable($this->filesPath . '/' . $lab->attachment)) {
unlink($this->filesPath . '/' . $lab->attachment);
}
$lab->attachment = null;
$lab->attachment_mime = null;
R::store($lab);
}
}
......@@ -15,6 +15,9 @@ interface LabServiceInterface
public function updateLab(array $data, $id);
public function getLabById($id);
public function getLabsBySchoolId($id);
public function getLabForSchool($school_id, $id);
public function removeLabAttachment($lab_id);
public function getLessons();
public function getLessonsByLabId($id);
......
......@@ -35,7 +35,7 @@
<div class="form-group">
<label class="control-label hidden-xs hidden-sm col-md-3" for="el-{{ name }}">{{ label|raw }}</label>
<div class="col-xs-12 col-sm-12 col-md-9">
{#<div class="input-group">
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-default btn-file">
Επιλέξτε&hellip; <input type="file" multiple name="{{ name }}" id="el-{{ name }}">
......@@ -45,13 +45,23 @@
{% for attr_name, attr_value in attributes|default({}) %}
{{ attr_name }}="{{ attr_value }}"
{% endfor %}>
<span class="input-group-btn">
<span class="btn btn-default btn-file-remove">
<i class="fa fa-remove"></i>
</span>
</span>
</div>#}
<input type="file" multiple name="{{ name }}" id="el-{{ name }}">
</div>
{% if value %}
<div class="pull-right uploaded btn-group btn-group-sm" data-href="{{ value }}">
<a href="#" target="_blank" class="btn-download btn bnt-link btn-sm">
<i class="fa fa-download"></i> Λήψη</a>
<a href="#" class="btn-remove btn bnt-link btn-sm text-danger">
<i class="fa fa-remove"></i> Διαγραφή</a>
</div>
{% endif %}
</div>
</div>
{% endmacro %}
......
......@@ -55,7 +55,8 @@
</table>
</div>
<div class="modal fade" id="lab-form-modal" tabindex="-1" role="dialog" aria-labelledby="lab-from">
<form class="form-horizontal" enctype="multipart/form-data">
<form class="form-horizontal" method="post" action="{{ path_for('school.labs') }}"
data-url="{{ path_for('school.labs') }}" enctype="multipart/form-data">
<div class="modal-dialog" role="form">
<div class="modal-content">
<div class="modal-header">
......@@ -71,7 +72,7 @@
{{ macros.select('has_network', 'Δίκτυο', network_options, '', {'required': ''}) }}
{{ macros.select('has_server', 'Ύπαρξη server', server_options, '', {'required': ''}) }}
{{ macros.input('area', 'Επιφάνεια (m<sup>2</sup>)', '', 'number', {'required': '', 'min': 0, 'max': 500}) }}
{{ macros.file('attachment', 'Αρχείο κάτοψης') }}
{{ macros.file('attachment', 'Αρχείο κάτοψης ή φωτογραφία', path_for('school.labs.attachment', {}, {'lab_id': '__lab_id__'})) }}
{{ macros.select('lessons', 'Μαθήματα', lessons_options, '', {'multiple': ''}) }}
{{ macros.text('use_in_program', 'Χρήση στα πλαίσια μαθημάτων') }}
{{ macros.text('use_ext_program', 'Χρήση για δραστηριότητες εκτός εκπαιδευτικού προγράμματος') }}
......
......@@ -69,7 +69,7 @@ body {
}
/* file upload input */
/*
.btn-file {
position: relative;
overflow: hidden;
......@@ -88,7 +88,7 @@ body {
background: white;
cursor: inherit;
display: block;
}*/
}
/* school */
......
......@@ -48,26 +48,25 @@
}
//
// $(document).on('change', '.btn-file :file', function () {
// var input = $(this),
// numFiles = input.get(0).files ? input.get(0).files.length : 1,
// label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
// input.trigger('fileselect', [numFiles, label]);
// });