Merge remote-tracking branch 'origin/master' into stable

This commit is contained in:
Julien Fastré 2020-06-15 15:19:22 +02:00
commit 61c11c3eee
11 changed files with 216 additions and 24 deletions

View File

@ -22,5 +22,13 @@ Version 1.5.4
=============
- replace default message on download button below dropzone ;
- launch event when dropzone is initialized, to allow to customize events on dropzone;
- launch event when dropzone is initialized, to allow to customize events on dropzone;
- add privacy events to document index / show
- add privacy events to document edit / update
- remove dump message
Version 1.5.5
=============
- add button to remove existing document in form, and improve UI in this part
- fix error when document is removed in form

View File

@ -5,7 +5,9 @@ namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\DocStoreBundle\Form\PersonDocumentType;
use Chill\DocStoreBundle\Repository\DocumentRepository;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@ -29,9 +31,21 @@ class DocumentPersonController extends Controller
*/
protected $translator;
public function __construct(TranslatorInterface $translator)
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* DocumentPersonController constructor.
*
* @param TranslatorInterface $translator
* @param EventDispatcherInterface $eventDispatcher
*/
public function __construct(TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher)
{
$this->translator = $translator;
$this->eventDispatcher = $eventDispatcher;
}
/**
@ -59,6 +73,12 @@ class DocumentPersonController extends Controller
array('date' => 'DESC')
);
$event = new PrivacyEvent($person, array(
'element_class' => PersonDocument::class,
'action' => 'index'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render(
'ChillDocStoreBundle:PersonDocument:index.html.twig',
[
@ -119,7 +139,14 @@ class DocumentPersonController extends Controller
{
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_SEE', $document);
$event = new PrivacyEvent($person, array(
'element_class' => PersonDocument::class,
'element_id' => $document->getId(),
'action' => 'show'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render(
'ChillDocStoreBundle:PersonDocument:show.html.twig',
['document' => $document, 'person' => $person]);
@ -147,14 +174,29 @@ class DocumentPersonController extends Controller
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans("The document is successfully updated"));
$event = new PrivacyEvent($person, array(
'element_class' => PersonDocument::class,
'element_id' => $document->getId(),
'action' => 'update'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->redirectToRoute(
'person_document_edit',
['id' => $document->getId(), 'person' => $person->getId()]);
} elseif ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->translator->trans("This form contains errors"));
}
$event = new PrivacyEvent($person, array(
'element_class' => PersonDocument::class,
'element_id' => $document->getId(),
'action' => 'edit'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render(
'ChillDocStoreBundle:PersonDocument:edit.html.twig',
[

View File

@ -30,6 +30,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf
$loader->load('services/controller.yml');
$loader->load('services/menu.yml');
$loader->load('services/fixtures.yml');
$loader->load('services/form.yml');
}
public function prepend(ContainerBuilder $container)

View File

@ -10,14 +10,25 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Chill\DocStoreBundle\Entity\StoredObject;
use Symfony\Component\Form\CallbackTransformer;
use Doctrine\ORM\EntityManagerInterface;
/**
*
* Form type which allow to join a document
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class StoredObjectType extends AbstractType
{
/**
*
* @var EntityManagerInterface
*/
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
@ -86,6 +97,9 @@ class StoredObjectType extends AbstractType
}
if (NULL === $object->getFilename()) {
// remove the original object
$this->em->remove($object);
return null;
}

View File

@ -30,8 +30,6 @@ class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface
public function toAsyncFile($data)
{
dump($data);
if ($data instanceof StoredObject) {
return $data;
}
@ -39,8 +37,6 @@ class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface
public function toData(AsyncFileInterface $asyncFile)
{
dump($asyncFile);
$object = $this->em
->getRepository(StoredObject::class)
->findByFilename($asyncFile->getObjectName())

View File

@ -5,4 +5,5 @@ services:
Chill\DocStoreBundle\Controller\DocumentPersonController:
autowire: true
arguments:
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'

View File

@ -0,0 +1,6 @@
services:
Chill\DocStoreBundle\Form\StoredObjectType:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
tags:
- { name: form.type }

View File

@ -1,6 +1,7 @@
// override dropzone from dropzoneJS
.dropzone {
margin-bottom: 0.5rem;
.dz-preview {
display: initial;
margin-left: auto;
@ -19,7 +20,15 @@
}
}
.sc-button.dz-bt-below-dropzone {
width: 100%;
}
.chill-dropzone__below-zone {
display: flex;
& > *:not(:last-child) {
margin-right: 1rem;
}
.sc-button.dz-bt-below-dropzone {
width: 100%;
}
}

View File

@ -98,15 +98,26 @@ var encryptFile = function(originalFile, zoneData, done) {
reader.readAsArrayBuffer(originalFile);
};
var addBelowButton = (btn, zone, zoneData) => {
let
belowZone = zone.querySelector('.chill-dropzone__below-zone');
if (belowZone === null) {
belowZone = document.createElement('div');
belowZone.classList.add('chill-dropzone__below-zone');
zone.appendChild(belowZone);
}
belowZone.appendChild(btn);
};
var initialize = function(zone) {
var createZone = (zone, zoneData) => {
var
created = document.createElement('div'),
initMessage = document.createElement('div'),
initContent = zone.dataset.labelInitMessage,
zoneData = { zone: zone, suffix: createFilename() },
dropzoneI;
created.classList.add('dropzone');
initMessage.classList.add('dz-message');
initMessage.appendChild(document.createTextNode(initContent));
@ -157,8 +168,6 @@ var initialize = function(zone) {
zone.insertBefore(created, zone.firstChild);
insertDownloadButton(zone, zoneData);
let event = new CustomEvent("chill_dropzone_initialized", {
detail: {
dropzone: dropzoneI,
@ -168,6 +177,21 @@ var initialize = function(zone) {
window.dispatchEvent(event);
};
var initialize = function(zone) {
var
allowRemove = zone.dataset.allowRemove,
zoneData = { zone: zone, suffix: createFilename(), allowRemove: allowRemove, old: null }
;
if (hasDataInForm(zone, zoneData)) {
insertRemoveButton(zone, zoneData);
insertDownloadButton(zone, zoneData);
} else {
createZone(zone, zoneData);
}
};
var createFilename = () => {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@ -195,6 +219,35 @@ var storeDataInForm = (zone, zoneData) => {
insertDownloadButton(zone);
};
const restoreDataInForm = (zone, zoneData) => {
var
inputKey = zone.querySelector('input[data-stored-object-key]'),
inputIv = zone.querySelector('input[data-stored-object-iv]'),
inputObject = zone.querySelector('input[data-async-file-upload]'),
inputType = zone.querySelector('input[data-async-file-type]')
;
if (zoneData.old === null) {
console.log('should not have restored data');
return;
}
inputKey.value = zoneData.old.key;
inputIv.value = zoneData.old.iv;
inputType.value = zoneData.old.type;
inputObject.value = zoneData.old.obj;
insertDownloadButton(zone);
};
const hasDataInForm = (zone, zoneData) => {
var
inputObject = zone.querySelector('input[data-async-file-upload]')
;
return inputObject.value.length > 0;
};
var removeDataInForm = (zone, zoneData) => {
var
inputKey = zone.querySelector('input[data-stored-object-key]'),
@ -202,7 +255,15 @@ var removeDataInForm = (zone, zoneData) => {
inputObject = zone.querySelector('input[data-async-file-upload]'),
inputType = zone.querySelector('input[data-async-file-type]')
;
// store data for future usage
zoneData.old = {
key: inputKey.value,
iv: inputIv.value,
obj: inputObject.value,
type: inputType.value
};
// set blank values
inputKey.value = "";
inputIv.value = "";
inputType.value = "";
@ -211,7 +272,57 @@ var removeDataInForm = (zone, zoneData) => {
insertDownloadButton(zone);
};
var insertDownloadButton = (zone) => {
var insertRemoveButton = (zone, zoneData) => {
var
removeButton = document.createElement('a'),
cancelButton = document.createElement('a'),
labelRemove = zone.dataset.dictRemove,
labelCancel = 'Restaurer'
;
removeButton.classList.add('sc-button', 'bt-delete');
removeButton.textContent = labelRemove;
cancelButton.classList.add('sc-button');
cancelButton.textContent = labelCancel;
removeButton.addEventListener('click', (e) => {
e.preventDefault();
if (zoneData.allowRemove === 'true') {
removeDataInForm(zone, zoneData);
cancelButton.addEventListener('click', (e) => {
e.preventDefault();
restoreDataInForm(zone, zoneData);
cancelButton.remove();
zone.querySelector('.dropzone').remove();
initialize(zone);
});
}
addBelowButton(cancelButton, zone, zoneData);
//zone.appendChild(cancelButton);
removeButton.remove();
createZone(zone, zoneData);
});
addBelowButton(removeButton, zone, zoneData);
// zone.appendChild(removeButton);
};
const removeDownloadButton = (zone, zoneData) => {
var
existingButtons = zone.querySelectorAll('a[data-download-button]')
;
// remove existing
existingButtons.forEach(function(b) {
b.remove();
});
};
var insertDownloadButton = (zone, zoneData) => {
var
existingButtons = zone.querySelectorAll('a[data-download-button]'),
newButton = document.createElement('a'),
@ -247,7 +358,8 @@ var insertDownloadButton = (zone) => {
newButton.classList.add('sc-button', 'bt-download', 'dz-bt-below-dropzone');
newButton.textContent = labelQuietButton;
zone.appendChild(newButton);
addBelowButton(newButton, zone, zoneData);
//zone.appendChild(newButton);
initializeDownload(zone);
};

View File

@ -24,3 +24,4 @@ Max files exceeded. Remove previous files: Nombre maximum de fichier atteint. Su
Cancel upload: Annuler le téléversement
Are you sure you want to cancel this upload ?: Êtes-vous sûrs de vouloir annuler ce téléversement ?
Upload canceled: Téléversement annulé
Remove existing file: Supprimer le document existant

View File

@ -11,6 +11,8 @@
data-dict-cancel-upload="{{ 'Cancel upload'|trans|escape('html_attr') }}"
data-dict-cancel-upload-confirm="{{ 'Are you sure you want to cancel this upload ?'|trans|escape('html_attr') }}"
data-dict-upload-canceled="{{ 'Upload canceled'|trans|escape('html_attr') }}"
data-dict-remove="{{ 'Remove existing file'|trans|escape('html_attr') }}"
data-allow-remove="{% if required %}false{% else %}true{% endif %}"
data-temp-url-generator="{{ path('async_upload.generate_url', { 'method': 'GET' })|escape('html_attr') }}">
{{ form_widget(form.filename) }}
{{ form_widget(form.keyInfos, { 'attr': { 'data-stored-object-key': 1 } }) }}