Skip to content

Commit

Permalink
feat(Attributes): Added relation between Realms and Attributes and At…
Browse files Browse the repository at this point in the history
…tributeValue to secure attribute access
  • Loading branch information
ambroisemaupate committed Sep 5, 2023
1 parent b9e2f7a commit 6f5f477
Show file tree
Hide file tree
Showing 20 changed files with 193 additions and 34 deletions.
41 changes: 41 additions & 0 deletions lib/RoadizCoreBundle/migrations/Version20230905140844.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20230905140844 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add realm to attribute and attribute_value';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE attribute_values ADD realm_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE attribute_values ADD CONSTRAINT FK_184662BC9DFF5F89 FOREIGN KEY (realm_id) REFERENCES realms (id) ON DELETE SET NULL');
$this->addSql('CREATE INDEX IDX_184662BC9DFF5F89 ON attribute_values (realm_id)');
$this->addSql('ALTER TABLE attributes ADD realm_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE attributes ADD CONSTRAINT FK_319B9E709DFF5F89 FOREIGN KEY (realm_id) REFERENCES realms (id) ON DELETE SET NULL');
$this->addSql('CREATE INDEX IDX_319B9E709DFF5F89 ON attributes (realm_id)');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE attribute_values DROP FOREIGN KEY FK_184662BC9DFF5F89');
$this->addSql('DROP INDEX IDX_184662BC9DFF5F89 ON attribute_values');
$this->addSql('ALTER TABLE attribute_values DROP realm_id');
$this->addSql('ALTER TABLE attributes DROP FOREIGN KEY FK_319B9E709DFF5F89');
$this->addSql('DROP INDEX IDX_319B9E709DFF5F89 ON attributes');
$this->addSql('ALTER TABLE attributes DROP realm_id');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,14 @@ public function getSubscribedEvents(): array
public function prePersist(LifecycleEventArgs $event): void
{
$entity = $event->getObject();
if ($entity instanceof AttributeValueInterface) {
if ($entity instanceof AttributeValue) {
if (
null !== $entity->getAttribute() &&
null !== $entity->getAttribute()->getDefaultRealm()
) {
$entity->setRealm($entity->getAttribute()->getDefaultRealm());
}

/*
* Automatically set position only if not manually set before.
*/
Expand Down
23 changes: 23 additions & 0 deletions lib/RoadizCoreBundle/src/Entity/Attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ class Attribute extends AbstractEntity implements AttributeInterface
]
protected Collection $attributeDocuments;

#[ORM\ManyToOne(targetEntity: Realm::class)]
#[ORM\JoinColumn(
name: 'realm_id',
referencedColumnName: 'id',
unique: false,
nullable: true,
onDelete: 'SET NULL'
)]
#[SymfonySerializer\Ignore]
#[Serializer\Exclude]
private ?Realm $defaultRealm = null;

public function __construct()
{
$this->attributeTranslations = new ArrayCollection();
Expand Down Expand Up @@ -76,6 +88,17 @@ public function setAttributeDocuments(Collection $attributeDocuments): Attribute
return $this;
}

public function getDefaultRealm(): ?Realm
{
return $this->defaultRealm;
}

public function setDefaultRealm(?Realm $defaultRealm): Attribute
{
$this->defaultRealm = $defaultRealm;
return $this;
}

/**
* @return Collection<int, Document>
*/
Expand Down
23 changes: 23 additions & 0 deletions lib/RoadizCoreBundle/src/Entity/AttributeValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ class AttributeValue extends AbstractPositioned implements AttributeValueInterfa
]
protected ?Node $node = null;

#[ORM\ManyToOne(targetEntity: Realm::class)]
#[ORM\JoinColumn(
name: 'realm_id',
referencedColumnName: 'id',
unique: false,
nullable: true,
onDelete: 'SET NULL'
)]
#[SymfonySerializer\Ignore]
#[Serializer\Exclude]
private ?Realm $realm = null;

public function __construct()
{
$this->attributeValueTranslations = new ArrayCollection();
Expand Down Expand Up @@ -112,6 +124,17 @@ public function setNode(?Node $node): AttributeValue
return $this;
}

public function getRealm(): ?Realm
{
return $this->realm;
}

public function setRealm(?Realm $realm): AttributeValue
{
$this->realm = $realm;
return $this;
}

/**
* After clone method.
*
Expand Down
6 changes: 6 additions & 0 deletions lib/RoadizCoreBundle/src/Form/AttributeType.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'required' => false,
'help' => 'attributes.form_help.searchable'
])
->add('defaultRealm', RealmChoiceType::class, [
'label' => 'attributes.defaultRealm',
'help' => 'attributes.defaultRealm.help',
'placeholder' => 'attributes.defaultRealm.placeholder',
'required' => false,
])
->add('attributeTranslations', CollectionType::class, [
'label' => 'attributes.form.attributeTranslations',
'allow_add' => true,
Expand Down
30 changes: 30 additions & 0 deletions lib/RoadizCoreBundle/src/Form/AttributeValueRealmType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Form;

use RZ\Roadiz\CoreBundle\Model\AttributeValueInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class AttributeValueRealmType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('realm', RealmChoiceType::class, [
'label' => false,
'placeholder' => 'attributeValue.realm.placeholder',
'required' => false,
]);
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'label' => false,
'data_class' => AttributeValueInterface::class,
]);
}
}
12 changes: 12 additions & 0 deletions lib/RoadizCoreBundle/src/Form/AttributeValueTranslationType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\Length;

Expand Down Expand Up @@ -103,6 +105,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
break;
}
}
$builder->add('attributeValue', AttributeValueRealmType::class);
}

/**
Expand Down Expand Up @@ -134,6 +137,15 @@ protected function getOptions(AttributeValueTranslationInterface $attributeValue
], $options ?: []);
}

public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'label' => false,
'data_class' => AttributeValueTranslationInterface::class,
]);
}


/**
* @inheritDoc
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,12 @@ protected function supports(string $attribute, $subject): bool
*/
public function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
switch ($subject->getType()) {
case RealmInterface::TYPE_PLAIN_PASSWORD:
return $this->voteForPassword($attribute, $subject, $token);
case RealmInterface::TYPE_USER:
return $this->voteForUser($attribute, $subject, $token);
case RealmInterface::TYPE_ROLE:
return $this->voteForRole($attribute, $subject, $token);
}
return false;
return match ($subject->getType()) {
RealmInterface::TYPE_PLAIN_PASSWORD => $this->voteForPassword($attribute, $subject, $token),
RealmInterface::TYPE_USER => $this->voteForUser($attribute, $subject, $token),
RealmInterface::TYPE_ROLE => $this->voteForRole($attribute, $subject, $token),
default => false,
};
}

/**
Expand All @@ -61,7 +58,7 @@ public function voteOnAttribute(string $attribute, $subject, TokenInterface $tok
* @param TokenInterface $token
* @return bool
*/
private function voteForRole(string $attribute, $subject, TokenInterface $token): bool
private function voteForRole(string $attribute, RealmInterface $subject, TokenInterface $token): bool
{
if (null === $role = $subject->getRole()) {
return false;
Expand All @@ -75,7 +72,7 @@ private function voteForRole(string $attribute, $subject, TokenInterface $token)
* @param TokenInterface $token
* @return bool
*/
private function voteForUser(string $attribute, $subject, TokenInterface $token): bool
private function voteForUser(string $attribute, RealmInterface $subject, TokenInterface $token): bool
{
if ($subject->getUsers()->count() === 0 || null === $token->getUser()) {
return false;
Expand All @@ -91,7 +88,7 @@ private function voteForUser(string $attribute, $subject, TokenInterface $token)
* @param TokenInterface $token
* @return bool
*/
private function voteForPassword(string $attribute, $subject, TokenInterface $token): bool
private function voteForPassword(string $attribute, RealmInterface $subject, TokenInterface $token): bool
{
$request = $this->requestStack->getCurrentRequest();
if (null === $request || empty($subject->getPlainPassword())) {
Expand Down
18 changes: 18 additions & 0 deletions lib/RoadizCoreBundle/translations/core/messages.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,24 @@
<target></target>
</trans-unit>

<trans-unit xml:space="preserve" id="attributes.defaultRealm">
<source>attributes.defaultRealm</source>
<target></target>
</trans-unit>
<trans-unit xml:space="preserve" id="attributes.defaultRealm.help">
<source>attributes.defaultRealm.help</source>
<target></target>
</trans-unit>
<trans-unit xml:space="preserve" id="attributes.defaultRealm.placeholder">
<source>attributes.defaultRealm.placeholder</source>
<note>Default text when no realm is attached to an attribute</note>
<target></target>
</trans-unit>
<trans-unit xml:space="preserve" id="attributeValue.realm.placeholder">
<source>attributeValue.realm.placeholder</source>
<note>Default text when no realm is attached to an attribute-value</note>
<target></target>
</trans-unit>
</body>
</file>
</xliff>
18 changes: 10 additions & 8 deletions lib/Rozier/src/Controllers/Nodes/NodesAttributesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,15 @@ protected function handleAddAttributeForm(Request $request, Node $node, Translat

/**
* @param Request $request
* @param int $nodeId
* @param int $translationId
* @param int $attributeValueId
* @param int $nodeId
* @param int $translationId
* @param int $attributeValueId
*
* @return Response
* @throws RuntimeError
*/
public function deleteAction(Request $request, $nodeId, $translationId, $attributeValueId): Response
public function deleteAction(Request $request, int $nodeId, int $translationId, int $attributeValueId): Response
{
$this->denyAccessUnlessGranted('ROLE_ACCESS_ATTRIBUTES_DELETE');

/** @var AttributeValue|null $item */
$item = $this->em()->find(AttributeValue::class, $attributeValueId);
if ($item === null) {
Expand All @@ -215,6 +214,8 @@ public function deleteAction(Request $request, $nodeId, $translationId, $attribu
throw $this->createNotFoundException('Node-source does not exist');
}

$this->denyAccessUnlessGranted(NodeVoter::EDIT_ATTRIBUTE, $node);

/** @var NodesSources|null $nodeSource */
$nodeSource = $this->em()
->getRepository(NodesSources::class)
Expand Down Expand Up @@ -267,11 +268,10 @@ public function deleteAction(Request $request, $nodeId, $translationId, $attribu
* @param int $translationId
* @param int $attributeValueId
* @return Response
* @throws RuntimeError
*/
public function resetAction(Request $request, int $nodeId, int $translationId, int $attributeValueId): Response
{
$this->denyAccessUnlessGranted('ROLE_ACCESS_ATTRIBUTES_DELETE');

/** @var AttributeValueTranslation|null $item */
$item = $this->em()
->getRepository(AttributeValueTranslation::class)
Expand All @@ -291,6 +291,8 @@ public function resetAction(Request $request, int $nodeId, int $translationId, i
throw $this->createNotFoundException('Node-source does not exist');
}

$this->denyAccessUnlessGranted(NodeVoter::EDIT_ATTRIBUTE, $node);

/** @var NodesSources|null $nodeSource */
$nodeSource = $this->em()
->getRepository(NodesSources::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ export default class AttributeValuePosition {
attributeValueId: attributeValueId,
newPosition: newPosition,
}
// TODO: entry point
if (window.Rozier.routes.attributeValueAjaxEdit) {
const route = window.Rozier.routes.attributeValueAjaxEdit
if (route && attributeValueId) {
this.currentRequest = $.ajax({
url: window.Rozier.routes.attributeValueAjaxEdit.replace('%attributeValueId%', attributeValueId),
url: route.replace('%attributeValueId%', attributeValueId),
type: 'POST',
dataType: 'json',
data: postData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<thead>
<tr>
<th>{% trans %}attributes.code{% endtrans %}</th>
<th class="uk-visible-large">{% trans %}attributes.group{% endtrans %}</th>
<th>{% trans %}attributes.value{% endtrans %}</th>
<th class="uk-visible-xlarge">{% trans %}attributes.group{% endtrans %}</th>
<th></th>
<th>{% trans %}actions{% endtrans %}</th>
</tr>
</thead>
Expand All @@ -36,7 +36,7 @@
<span class="color" style="background-color:{{ attributeValue.attribute.color|default('transparent') }};"></span>
{{- attribute_value_translation_form.vars.data|attribute_label -}}
</td>
<td class="uk-visible-large">{%- if attributeValue.attribute.group %}
<td class="uk-visible-xlarge">{%- if attributeValue.attribute.group %}
{{- attributeValue.attribute.group|attribute_group_label -}}
{% endif -%}</td>
<td>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

<link href="{{ asset('css/vendor.aaeedaa02e00b12e41cf.css', 'Rozier') }}" rel="stylesheet">

<link href="{{ asset('css/app.c9045ea8fbedd28c00ed.css', 'Rozier') }}" rel="stylesheet">
<link href="{{ asset('css/app.d45a1cf8e90fcc4fd94a.css', 'Rozier') }}" rel="stylesheet">



Expand Down
4 changes: 2 additions & 2 deletions lib/Rozier/src/Resources/views/partials/js-inject.html.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

<script src="{{ asset('js/vendor.f2fb807281e9789f4232.js', 'Rozier') }}" defer type="text/javascript"></script>
<script src="{{ asset('js/vendor.3c7e5e0ab2e763c35a6d.js', 'Rozier') }}" defer type="text/javascript"></script>

<script src="{{ asset('js/app.f2fb807281e9789f4232.js', 'Rozier') }}" defer type="text/javascript"></script>
<script src="{{ asset('js/app.3c7e5e0ab2e763c35a6d.js', 'Rozier') }}" defer type="text/javascript"></script>

Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

<script src="{{ asset('js/simple.f2fb807281e9789f4232.js', 'Rozier') }}" defer type="text/javascript"></script>
<script src="{{ asset('js/simple.3c7e5e0ab2e763c35a6d.js', 'Rozier') }}" defer type="text/javascript"></script>

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading

0 comments on commit 6f5f477

Please sign in to comment.