First commit

This commit is contained in:
Marc Ducobu 2018-04-06 17:09:51 +02:00
commit c28c2bf119
27 changed files with 1434 additions and 0 deletions

9
ChillDocStoreBundle.php Normal file
View File

@ -0,0 +1,9 @@
<?php
namespace Chill\DocStoreBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillDocStoreBundle extends Bundle
{
}

View File

@ -0,0 +1,129 @@
<?php
namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\DocumentCategory;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\DocStoreBundle\Form\DocumentCategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/{_locale}/admin/document/category")
*/
class DocumentCategoryController extends Controller
{
/**
* @Route("/", name="document_category_index", methods="GET")
*/
public function index(): Response
{
$em = $this->getDoctrine()->getManager();
$categories = $em->getRepository("ChillDocStoreBundle:DocumentCategory")->findAll();
return $this->render(
'ChillDocStoreBundle:DocumentCategory:index.html.twig',
['document_categories' => $categories]);
}
/**
* @Route("/new", name="document_category_new", methods="GET|POST")
*/
public function new(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$documentCategory = new DocumentCategory();
$documentCategory
->setBundleId('Chill\DocStoreBundle\ChillDocStoreBundle');
$documentCategory
->setIdInsideBundle(
$em->getRepository("ChillDocStoreBundle:DocumentCategory")
->nextIdInsideBundle());
$documentCategory
->setDocumentClass(PersonDocument::class);
$form = $this->createForm(DocumentCategoryType::class, $documentCategory);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($documentCategory);
$em->flush();
return $this->redirectToRoute('document_category_index');
} else {
$documentCategory->setBundleId(
'Chill\DocStoreBundle\ChillDocStoreBundle');
}
return $this->render('ChillDocStoreBundle:DocumentCategory:new.html.twig', [
'document_category' => $documentCategory,
'form' => $form->createView(),
]);
}
/**
* @Route("/{bundleId}/{idInsideBundle}", name="document_category_show", methods="GET")
*/
public function show($bundleId, $idInsideBundle): Response
{
$em = $this->getDoctrine()->getManager();
$documentCategory = $em
->getRepository("ChillDocStoreBundle:DocumentCategory")
->findOneBy(
['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]);
return $this->render(
'ChillDocStoreBundle:DocumentCategory:show.html.twig',
['document_category' => $documentCategory]);
}
/**
* @Route("/{bundleId}/{idInsideBundle}/edit", name="document_category_edit", methods="GET|POST")
*/
public function edit(Request $request, $bundleId, $idInsideBundle): Response
{
$em = $this->getDoctrine()->getManager();
$documentCategory = $em
->getRepository("ChillDocStoreBundle:DocumentCategory")
->findOneBy(
['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]);
$form = $this->createForm(DocumentCategoryType::class, $documentCategory);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('document_category_edit', [
'bundleId' => $documentCategory->getBundleId(),
'idInsideBundle' => $documentCategory->getIdInsideBundle(),]);
}
return $this->render('ChillDocStoreBundle:DocumentCategory:edit.html.twig', [
'document_category' => $documentCategory,
'form' => $form->createView(),
]);
}
/**
* @Route("/{bundleId}/{idInsideBundle}", name="document_category_delete", methods="DELETE")
*/
public function delete(Request $request, $bundleId, $idInsideBundle): Response
{
$em = $this->getDoctrine()->getManager();
$documentCategory = $em
->getRepository("ChillDocStoreBundle:DocumentCategory")
->findOneBy(
['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]);
if ($this->isCsrfTokenValid('delete'.$bundleId.$idInsideBundle, $request->request->get('_token'))) {
$em->remove($documentCategory);
$em->flush();
}
return $this->redirectToRoute('document_category_index');
}
}

View File

@ -0,0 +1,163 @@
<?php
namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\DocStoreBundle\Form\PersonDocumentType;
use Chill\DocStoreBundle\Repository\DocumentRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Security\Core\Role\Role;
/**
* @Route("/{_locale}/person/{person}/document")
*
* TODO faire un controller abstrait ?
*/
class DocumentPersonController extends Controller
{
/**
* @Route("/", name="person_document_index", methods="GET")
*/
public function index(Person $person): Response
{
$em = $this->getDoctrine()->getManager();
if ($person === NULL) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$reachableScopes = $this->get('chill.main.security.authorization.helper')
->getReachableScopes(
$this->getUser(), new Role('CHILL_PERSON_DOCUMENT_SEE'),
$person->getCenter());
$documents = $em
->getRepository("ChillDocStoreBundle:PersonDocument")
->findBy(
array('person' => $person, 'scope' => $reachableScopes),
array('date' => 'DESC')
);
return $this->render(
'ChillDocStoreBundle:PersonDocument:index.html.twig',
[
'documents' => $documents,
'person' => $person
]);
}
/**
* @Route("/new", name="person_document_new", methods="GET|POST")
*/
public function new(Request $request, Person $person): Response
{
if ($person === NULL) {
throw $this->createNotFoundException('person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$user = $this->get('security.context')->getToken()->getUser();
$document = new PersonDocument();
$document->setUser($user);
$document->setPerson($person);
$document->setDate(new \DateTime('Now'));
$form = $this->createForm(PersonDocumentType::class, $document, array(
'center' => $document->getCenter(),
'role' => new Role('CHILL_PERSON_DOCUMENT_CREATE')
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->denyAccessUnlessGranted(
'CHILL_PERSON_DOCUMENT_CREATE', $document,
'creation of this activity not allowed');
$em = $this->getDoctrine()->getManager();
$em->persist($document);
$em->flush();
return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]);
}
return $this->render('ChillDocStoreBundle:PersonDocument:new.html.twig', [
'document' => $document,
'form' => $form->createView(),
'person' => $person,
]);
}
/**
* @Route("/{id}", name="person_document_show", methods="GET")
*/
public function show(Person $person, PersonDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_SEE', $document);
return $this->render(
'ChillDocStoreBundle:PersonDocument:show.html.twig',
['document' => $document, 'person' => $person]);
}
/**
* @Route("/{id}/edit", name="person_document_edit", methods="GET|POST")
*/
public function edit(Request $request, Person $person, PersonDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_UPDATE', $document);
$user = $this->get('security.context')->getToken()->getUser();
$document->setUser($user);
$document->setDate(new \DateTime('Now'));
$form = $this->createForm(
PersonDocumentType::class, $document, array(
'center' => $document->getCenter(),
'role' => new Role('CHILL_PERSON_DOCUMENT_UPDATE'),
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute(
'person_document_edit',
['id' => $document->getId(), 'person' => $person->getId()]);
}
return $this->render(
'ChillDocStoreBundle:PersonDocument:edit.html.twig',
[
'document' => $document,
'form' => $form->createView(),
'person' => $person,
]);
}
/**
* @Route("/{id}", name="person_document_delete", methods="DELETE")
*/
public function delete(Request $request, Person $person, PersonDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_DELETE', $document);
if ($this->isCsrfTokenValid('delete'.$document->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($document);
$em->flush();
}
return $this->redirectToRoute(
'person_document_index', ['person' => $person->getId()]);
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Chill\DocStoreBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class ChillDocStoreExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Chill\DocStoreBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*/
class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chill_doc_store');
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}

160
Entity/Document.php Normal file
View File

@ -0,0 +1,160 @@
<?php
namespace Chill\DocStoreBundle\Entity;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Chill\MainBundle\Entity\HasScopeInterface;
use Chill\MainBundle\Entity\User;
/**
* @ORM\MappedSuperclass()
*/
class Document implements HasScopeInterface
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="text")
*/
private $title;
/**
* @ORM\Column(type="text")
*/
private $description;
/**
* @ORM\ManyToOne(targetEntity="Chill\DocStoreBundle\Entity\DocumentCategory")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="category_bundle_id", referencedColumnName="bundle_id"),
* @ORM\JoinColumn(name="category_id_inside_bundle", referencedColumnName="id_inside_bundle")
* })
*/
private $category;
/**
* @ORM\Column(type="text")
*/
private $content;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
* @var \Chill\MainBundle\Entity\Scope The document's center
*/
private $scope;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
* @var \Chill\PersonBundle\Entity\user The user who encoded the exif_read_data
*/
private $user;
/**
* @ORM\Column(type="datetime")
*/
private $date;
public function getId()
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
/**
* @return DocumentCategory
*/
public function getCategory(): ?DocumentCategory
{
return $this->category;
}
public function setCategory(DocumentCategory $category): self
{
$this->category = $category;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
/**
* Get scope
*
* @return \Chill\MainBundle\Entity\Scope
*/
public function getScope()
{
return $this->scope;
}
public function setScope($scope): self
{
$this->scope = $scope;
return $this;
}
public function getUser()
{
return $this->user;
}
public function setUser($user): self
{
$this->user = $user;
return $this;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(\DateTimeInterface $date): self
{
$this->date = $date;
return $this;
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace Chill\DocStoreBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="Chill\DocStoreBundle\EntityRepository\DocumentCategoryRepository")
*/
class DocumentCategory
{
/**
* @ORM\Id()
* @ORM\Column(type="string", name="bundle_id")
* @var string The id of the bundle that has create the category (i.e. 'person', 'activity', ....)
*/
private $bundleId;
/**
* @ORM\Id()
* @ORM\Column(type="integer", name="id_inside_bundle")
* @var int The id which is unique inside the bundle
*/
private $idInsideBundle;
/**
* @ORM\Column(type="string", name="document_class")
* @var string The class of the document (ie Chill\DocStoreBundle\PersonDocument)
*/
private $documentClass;
/**
* @ORM\Column(type="json_array")
*/
private $name;
public function getBundleId() // ::class BundleClass (FQDN)
{
return $this->bundleId;
}
public function setBundleId($bundleId)
{
$this->bundleId = $bundleId;
}
public function getIdInsideBundle()
{
return $this->idInsideBundle;
}
public function setIdInsideBundle($idInsideBundle): self
{
$this->idInsideBundle = $idInsideBundle;
return $this;
}
public function getDocumentClass()
{
return $this->documentClass;
}
public function setDocumentClass($documentClass): self
{
$this->documentClass = $documentClass;
return $this;
}
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
} else {
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
}
return '';
} else {
return $this->name;
}
}
public function setName($name): self
{
$this->name = $name;
return $this;
}
}

45
Entity/PersonDocument.php Normal file
View File

@ -0,0 +1,45 @@
<?php
namespace Chill\DocStoreBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\HasScopeInterface;
use Chill\PersonBundle\Entity\Person;
/**
* @ORM\Entity()
*/
class PersonDocument extends Document implements HasCenterInterface, HasScopeInterface
{
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
* @var Person
*/
private $person;
/**
* Get person
*
* @return \Chill\MainBundle\Entity\Person
*/
public function getPerson()
{
return $this->person;
}
public function setPerson($person): self
{
$this->person = $person;
return $this;
}
public function getCenter()
{
return $this->getPerson()->getCenter();
}
}

View File

@ -0,0 +1,39 @@
<?php
/*
* Copyright (C) 2018 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\DocStoreBundle\EntityRepository;
use Doctrine\ORM\EntityRepository;
use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option;
/**
* Get an available idInsideBUndle
*/
class DocumentCategoryRepository extends EntityRepository
{
public function nextIdInsideBundle()
{
$array_res = $this->getEntityManager()
->createQuery(
'SELECT MAX(c.idInsideBundle) + 1 FROM ChillDocStoreBundle:DocumentCategory c')
->getSingleResult();
return $array_res[1] ?: 0;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Chill\DocStoreBundle\Form;
use Chill\DocStoreBundle\Entity\DocumentCategory;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class DocumentCategoryType extends AbstractType
{
private $chillBundlesFlipped;
public function __construct($kernelBundles)
{
// TODO faire un service dans CHillMain
foreach ($kernelBundles as $key => $value) {
if(substr($key, 0, 5) === 'Chill') {
$this->chillBundlesFlipped[$value] = $key;
}
}
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('bundleId', ChoiceType::class, array(
'choices' => $this->chillBundlesFlipped,
'disabled' => true,
))
->add('idInsideBundle', null, array(
'disabled' => true,
))
->add('documentClass', null, array(
'disabled' => true,
)) // cahcerh par default PersonDocument
->add('name', TranslatableStringFormType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => DocumentCategory::class,
]);
}
}

104
Form/PersonDocumentType.php Normal file
View File

@ -0,0 +1,104 @@
<?php
namespace Chill\DocStoreBundle\Form;
use Chill\DocStoreBundle\Entity\Document;
use Chill\DocStoreBundle\Entity\DocumentCategory;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Form\Type\AppendScopeChoiceTypeTrait;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Doctrine\Common\Persistence\ObjectManager;
use Chill\MainBundle\Templating\TranslatableStringHelper;
class PersonDocumentType extends AbstractType
{
use AppendScopeChoiceTypeTrait;
/**
* the user running this form
*
* @var User
*/
protected $user;
/**
*
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
*
* @var ObjectManager
*/
protected $om;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct(
TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper,
ObjectManager $om,
TranslatableStringHelper $translatableStringHelper
)
{
if (!$tokenStorage->getToken()->getUser() instanceof User) {
throw new \RuntimeException("you should have a valid user");
}
$this->user = $tokenStorage->getToken()->getUser();
$this->authorizationHelper = $authorizationHelper;
$this->om = $om;
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('description')
->add('content')
//->add('center')
->add('scope')
->add('date', 'date', array('required' => false, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy'))
->add('category', EntityType::class, array(
'class' => 'ChillDocStoreBundle:DocumentCategory',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.documentClass = :docClass')
->setParameter('docClass', PersonDocument::class);
},
'choice_label' => function ($entity = null) {
return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
},
))
;
$this->appendScopeChoices($builder, $options['role'],
$options['center'], $this->user, $this->authorizationHelper,
$this->translatableStringHelper, $this->om);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Document::class,
]);
$this->appendScopeChoicesOptions($resolver);
}
}

View File

@ -0,0 +1,3 @@
app:
resource: "@ChillDocStoreBundle/Controller/"
type: annotation

View File

@ -0,0 +1,27 @@
parameters:
# cl_chill_person.example.class: Chill\PersonBundle\Example
services:
Chill\DocStoreBundle\Form\DocumentCategoryType:
class: Chill\DocStoreBundle\Form\DocumentCategoryType
arguments: ['%kernel.bundles%']
tags:
- { name: form.type }
Chill\DocStoreBundle\Form\PersonDocumentType:
class: Chill\DocStoreBundle\Form\PersonDocumentType
arguments:
- "@security.token_storage"
- "@chill.main.security.authorization.helper"
- "@doctrine.orm.entity_manager"
- "@chill.main.helper.translatable_string"
tags:
- { name: form.type, alias: chill_docstorebundle_form_document }
Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter:
class: Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter
arguments:
- "@chill.main.security.authorization.helper"
tags:
- { name: security.voter }
- { name: chill.role }

View File

@ -0,0 +1,45 @@
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20180322123800 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
$this->addSql("CREATE SEQUENCE PersonDocument_id_seq INCREMENT BY 1 MINVALUE 1 START 1;");
$this->addSql("CREATE TABLE DocumentCategory (bundle_id VARCHAR(255) NOT NULL, id_inside_bundle INT NOT NULL, name JSON NOT NULL, document_class VARCHAR(255) NOT NULL, PRIMARY KEY(bundle_id, id_inside_bundle));");
$this->addSql("COMMENT ON COLUMN DocumentCategory.name IS '(DC2Type:json_array)';");
$this->addSql("CREATE TABLE PersonDocument (id INT NOT NULL, category_bundle_id VARCHAR(255) DEFAULT NULL, category_id_inside_bundle INT DEFAULT NULL, scope_id INT DEFAULT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, title TEXT NOT NULL, description TEXT NOT NULL, content TEXT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id));");
$this->addSql("CREATE INDEX IDX_BAADC20C369A0BE36EF62EFC ON PersonDocument (category_bundle_id, category_id_inside_bundle);");
$this->addSql("CREATE INDEX IDX_BAADC20C682B5931 ON PersonDocument (scope_id);");
$this->addSql("CREATE INDEX IDX_BAADC20CA76ED395 ON PersonDocument (user_id);");
$this->addSql("CREATE INDEX IDX_BAADC20C217BBB47 ON PersonDocument (person_id);");
$this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C369A0BE36EF62EFC FOREIGN KEY (category_bundle_id, category_id_inside_bundle) REFERENCES DocumentCategory (bundle_id, id_inside_bundle) NOT DEFERRABLE INITIALLY IMMEDIATE;");
$this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE;");
$this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20CA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;");
$this->addSql("ALTER TABLE PersonDocument ADD CONSTRAINT FK_BAADC20C217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;");
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
$this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C369A0BE36EF62EFC");
$this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C682B5931");
$this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20CA76ED395");
$this->addSql("ALTER TABLE PersonDocument DROP CONSTRAINT FK_BAADC20C217BBB47");
$this->addSql("DROP TABLE DocumentCategory;");
$this->addSql("DROP TABLE PersonDocument;");
$this->addSql("DROP SEQUENCE PersonDocument_id_seq;");
}
}

View File

@ -0,0 +1,21 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
<form method="post" action="{{ path('document_category_delete', {'bundleId': document_category.bundleId, 'idInsideBundle': document_category.idInsideBundle}) }}">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ document_category.bundleId ~ document_category.idInsideBundle) }}">
<button class="sc-button bt-delete">{{ 'Delete' | trans }}</button>
</form>

View File

@ -0,0 +1,20 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="sc-button bt-create">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

View File

@ -0,0 +1,31 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillMainBundle::Admin/layout.html.twig" %}
{% block title %}{{ 'Document category edit'|trans }}{% endblock title %}
{% block admin_content %}
<h1>{{ 'Document category edit'|trans }}</h1>
{{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig', {'button_label': 'Update'}) }}
<a href="{{ path('document_category_index') }}" class="sc-button">
{{ 'Back to the category list' | trans }}
</a>
{{ include('ChillDocStoreBundle:DocumentCategory:_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,60 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillMainBundle::Admin/layout.html.twig" %}
{% block title %}{{ 'Document category list' | trans }}{% endblock title %}
{% block admin_content %}
<h1>{{ 'Document category list' | trans }}</h1>
<table class="table">
<thead>
<tr>
<th>{{ 'Creator bundle id' | trans }}</th>
<th>{{ 'Internal id inside creator bundle' | trans }}</th>
<th>{{ 'Document class' | trans }}</th>
<th>{{ 'Name' | trans }}</th>
<th>{{ 'Actions' | trans }}</th>
</tr>
</thead>
<tbody>
{% for document_category in document_categories %}
<tr>
<td>{{ document_category.bundleId }}</td>
<td>{{ document_category.idInsideBundle }}</td>
<td>{{ document_category.documentClass }}</td>
<td>{{ document_category.name | localize_translatable_string}}</td>
<td>
<a href="{{ path('document_category_show', {'bundleId': document_category.bundleId, 'idInsideBundle': document_category.idInsideBundle}) }}" class="sc-button">
{{ 'show' | trans }}
</a>
<a href="{{ path('document_category_edit', {'bundleId': document_category.bundleId, 'idInsideBundle': document_category.idInsideBundle}) }}" class="sc-button bt-edit">
{{ 'edit' | trans }}
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="4">{{ 'no records found' | trans }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('document_category_new') }}" class="sc-button bt-create">{{ 'Create new' | trans }}</a>
{% endblock %}

View File

@ -0,0 +1,29 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillMainBundle::Admin/layout.html.twig" %}
{% block title %}{{ 'Create new document category' | trans }}{% endblock title %}
{% block admin_content %}
<h1>{{ 'Create new DocumentCategory' | trans }}</h1>
{{ include('ChillDocStoreBundle:DocumentCategory:_form.html.twig') }}
<a href="{{ path('document_category_index') }}" class="sc-button">
{{ 'Back to the category list' | trans }}
</a>
{% endblock %}

View File

@ -0,0 +1,54 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillMainBundle::Admin/layout.html.twig" %}
{% block title %}{{ 'Document category show'|trans }}{% endblock title %}
{% block admin_content %}
<h1>Document category</h1>
<table class="table">
<tbody>
<tr>
<th>{{ 'Creator bundle id' | trans }}</th>
<td>{{ document_category.bundleId }}</td>
</tr>
<tr>
<th>{{ 'Internal id inside creator bundle' | trans }}</th>
<td>{{ document_category.idInsideBundle }}</td>
</tr>
<tr>
<th>{{ 'Document class' | trans }}</th>
<td>{{ document_category.documentClass }}</td>
</tr>
<tr>
<th>{{ 'Name' | trans }}</th>
<td>{{ document_category.name | localize_translatable_string }}</td>
</tr>
</tbody>
</table>
<a href="{{ path('document_category_index') }}" class="sc-button">
{{ 'Back to the category list' | trans }}
</a>
<a href="{{ path('document_category_edit', {'bundleId': document_category.bundleId, 'idInsideBundle': document_category.idInsideBundle}) }}" class="sc-button bt-edit">
{{ 'Edit' | trans }}
</a>
{{ include('ChillDocStoreBundle:DocumentCategory:_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,5 @@
<form method="post" action="{{ path('person_document_delete', {'id': document.id, 'person': person.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ document.id) }}">
<button class="sc-button bt-delete">{{ 'Delete' | trans }}</button>
</form>

View File

@ -0,0 +1,4 @@
{{ form_start(form) }}
{{ form_widget(form) }}
<button class="sc-button bt-create">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}

View File

@ -0,0 +1,33 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillPersonBundle::layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Editing document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %}
{% block personcontent %}
<h1>{{ 'Edit Document' | trans }}</h1>
{{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig', {'button_label': 'Update'}) }}
<a href="{{ path('person_document_index', {'person': person.id}) }} " class="sc-button">
{{ 'Back to list' | trans }}
</a>
{{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,66 @@
{#
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillPersonBundle::layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Documents for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %}
{% block personcontent %}
<h1>{{ 'Document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}</h1>
<table class="table">
<thead>
<tr>
<th>{{ 'Title' | trans }}</th>
<th>{{ 'Description' | trans }}</th>
<th>{{ 'Content' | trans }}</th>
<th>{{ 'Last modification by' | trans }}</th>
<th>{{ 'Last update' | trans }}</th>
<th>{{ 'Actions' | trans }}</th>
</tr>
</thead>
<tbody>
{% for document in documents %}
<tr>
<td>{{ document.title }}</td>
<td>{{ document.description }}</td>
<td>{{ document.content }}</td>
<td>{{ document.user }}</td>
<td>{{ document.date ? document.date|date('Y-m-d H:i:s') : '' }}</td>
<td>
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="sc-button">
show
</a>
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="sc-button bt-edit">
edit
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="9">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('person_document_new', {'person': person.id}) }}" class="sc-button bt-create">
{{ 'Create new' | trans }}
</a>
{% endblock %}

View File

@ -0,0 +1,31 @@
{#
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillPersonBundle::layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'New document for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %}
{% block personcontent %}
<h1>{{ 'Create new Document' | trans }}</h1>
{{ include('ChillDocStoreBundle:PersonDocument:_form.html.twig') }}
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="sc-button bt-create">
{{ 'back to list' | trans }}
</a>
{% endblock %}

View File

@ -0,0 +1,68 @@
{#
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "ChillPersonBundle::layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %}
{% block personcontent %}
<h1>{{ 'Document' | trans }}</h1>
<table class="table">
<tbody>
<tr>
<th>{{ 'Title' | trans }}</th>
<td>{{ document.title }}</td>
</tr>
<tr>
<th>{{ 'Description' | trans }}</th>
<td>{{ document.description }}</td>
</tr>
<tr>
<th>{{ 'Content' | trans }}</th>
<td>{{ document.content }}</td>
</tr>
<tr>
<th>{{ 'Center' | trans}}</th>
<td>{{ document.center }}</td>
</tr>
<tr>
<th>{{ 'Scope' | trans }}</th>
<td>{{ document.scope.name | localize_translatable_string }}</td>
</tr>
<tr>
<th>{{ 'Last modificiation by' | trans }}</th>
<td>{{ document.user }}</td>
</tr>
<tr>
<th>{{ 'Last update' | trans }}</th>
<td>{{ document.date ? document.date|date('Y-m-d H:i:s') : '' }}</td>
</tr>
</tbody>
</table>
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="sc-button">
{{ 'Back to list' | trans }}
</a>
<a href="{{ path('person_document_edit', {'id': document.id, 'person': person.id}) }}" class="sc-button bt-edit">
{{ 'Edit' | trans }}
</a>
{{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }}
{% endblock %}

View File

@ -0,0 +1,83 @@
<?php
/*
* Copyright (C) 2018 Champs-Libres SCRLFS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\DocStoreBundle\Security\Authorization;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\ProvideRoleInterface;
/**
*
*/
class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleInterface
{
const CREATE = 'CHILL_PERSON_DOCUMENT_CREATE';
const SEE = 'CHILL_PERSON_DOCUMENT_SEE';
const SEE_DETAILS = 'CHILL_PERSON_DOCUMENT_SEE_DETAILS';
const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE';
const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE';
/**
*
* @var AuthorizationHelper
*/
protected $helper;
public function __construct(AuthorizationHelper $helper)
{
$this->helper = $helper;
}
protected function getSupportedAttributes()
{
return array(self::CREATE, self::SEE, self::UPDATE, self::DELETE,
self::SEE_DETAILS);
}
protected function getSupportedClasses()
{
return array('Chill\DocStoreBundle\Entity\PersonDocument');
}
protected function isGranted($attribute, $report, $user = null)
{
if (! $user instanceof \Chill\MainBundle\Entity\User){
return false;
}
return $this->helper->userHasAccess($user, $report, $attribute);
}
public function getRoles()
{
return $this->getSupportedAttributes();
}
public function getRolesWithoutScope()
{
return array();
}
public function getRolesWithHierarchy()
{
return ['PersonDocument' => $this->getRoles() ];
}
}