Removed field permissions from Part edit page

This commit is contained in:
Jan Böhmer 2022-11-06 21:29:03 +01:00
parent fc1af24ef9
commit 5e06557cf0
12 changed files with 29 additions and 87 deletions

View file

@ -54,7 +54,7 @@ class CollectionTypeExtension extends AbstractTypeExtension
public static function getExtendedTypes(): iterable public static function getExtendedTypes(): iterable
{ {
return [CollectionType::class, WorkaroundCollectionType::class]; return [CollectionType::class];
} }
public function configureOptions(OptionsResolver $resolver): void public function configureOptions(OptionsResolver $resolver): void

View file

@ -50,6 +50,7 @@ use App\Form\Type\StructuralEntityType;
use App\Form\WorkaroundCollectionType; use App\Form\WorkaroundCollectionType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\UrlType; use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -106,16 +107,15 @@ class OrderdetailType extends AbstractType
} }
//Attachment section //Attachment section
$event->getForm()->add('pricedetails', WorkaroundCollectionType::class, [ $event->getForm()->add('pricedetails', CollectionType::class, [
'entry_type' => PricedetailType::class, 'entry_type' => PricedetailType::class,
'allow_add' => $this->security->isGranted('@parts_prices.create'), 'allow_add' => true,
'allow_delete' => $this->security->isGranted('@parts_prices.delete'), 'allow_delete' => true,
'label' => false, 'label' => false,
'reindex_enable' => true, 'reindex_enable' => true,
'prototype_data' => $dummy_pricedetail, 'prototype_data' => $dummy_pricedetail,
'by_reference' => false, 'by_reference' => false,
'entry_options' => [ 'entry_options' => [
'disabled' => !$this->security->isGranted('@parts_prices.edit'),
'measurement_unit' => $options['measurement_unit'], 'measurement_unit' => $options['measurement_unit'],
], ],
]); ]);

View file

@ -103,7 +103,6 @@ class PartBaseType extends AbstractType
'attr' => [ 'attr' => [
'placeholder' => 'part.edit.name.placeholder', 'placeholder' => 'part.edit.name.placeholder',
], ],
'disabled' => !$this->security->isGranted('name.edit', $part),
]) ])
->add('description', RichTextEditorType::class, [ ->add('description', RichTextEditorType::class, [
'required' => false, 'required' => false,
@ -114,7 +113,6 @@ class PartBaseType extends AbstractType
'placeholder' => 'part.edit.description.placeholder', 'placeholder' => 'part.edit.description.placeholder',
'rows' => 2, 'rows' => 2,
], ],
'disabled' => !$this->security->isGranted('description.edit', $part),
]) ])
->add('minAmount', SIUnitType::class, [ ->add('minAmount', SIUnitType::class, [
'attr' => [ 'attr' => [
@ -123,13 +121,11 @@ class PartBaseType extends AbstractType
], ],
'label' => 'part.edit.mininstock', 'label' => 'part.edit.mininstock',
'measurement_unit' => $part->getPartUnit(), 'measurement_unit' => $part->getPartUnit(),
'disabled' => !$this->security->isGranted('minamount.edit', $part),
]) ])
->add('category', StructuralEntityType::class, [ ->add('category', StructuralEntityType::class, [
'class' => Category::class, 'class' => Category::class,
'label' => 'part.edit.category', 'label' => 'part.edit.category',
'disable_not_selectable' => true, 'disable_not_selectable' => true,
'disabled' => !$this->security->isGranted('category.edit', $part),
'constraints' => [ 'constraints' => [
], ],
]) ])
@ -138,7 +134,6 @@ class PartBaseType extends AbstractType
'required' => false, 'required' => false,
'label' => 'part.edit.footprint', 'label' => 'part.edit.footprint',
'disable_not_selectable' => true, 'disable_not_selectable' => true,
'disabled' => !$this->security->isGranted('footprint.edit', $part),
]) ])
->add('tags', TextType::class, [ ->add('tags', TextType::class, [
'required' => false, 'required' => false,
@ -149,7 +144,6 @@ class PartBaseType extends AbstractType
'data-controller' => 'elements--tagsinput', 'data-controller' => 'elements--tagsinput',
'data-autocomplete' => $this->urlGenerator->generate('typeahead_tags', ['query' => '__QUERY__']), 'data-autocomplete' => $this->urlGenerator->generate('typeahead_tags', ['query' => '__QUERY__']),
], ],
'disabled' => !$this->security->isGranted('tags.edit', $part),
]); ]);
//Manufacturer section //Manufacturer section
@ -158,32 +152,27 @@ class PartBaseType extends AbstractType
'required' => false, 'required' => false,
'label' => 'part.edit.manufacturer.label', 'label' => 'part.edit.manufacturer.label',
'disable_not_selectable' => true, 'disable_not_selectable' => true,
'disabled' => !$this->security->isGranted('manufacturer.edit', $part),
]) ])
->add('manufacturer_product_url', UrlType::class, [ ->add('manufacturer_product_url', UrlType::class, [
'required' => false, 'required' => false,
'empty_data' => '', 'empty_data' => '',
'label' => 'part.edit.manufacturer_url.label', 'label' => 'part.edit.manufacturer_url.label',
'disabled' => !$this->security->isGranted('mpn.edit', $part),
]) ])
->add('manufacturer_product_number', TextType::class, [ ->add('manufacturer_product_number', TextType::class, [
'required' => false, 'required' => false,
'empty_data' => '', 'empty_data' => '',
'label' => 'part.edit.mpn', 'label' => 'part.edit.mpn',
'disabled' => !$this->security->isGranted('mpn.edit', $part),
]) ])
->add('manufacturing_status', ChoiceType::class, [ ->add('manufacturing_status', ChoiceType::class, [
'label' => 'part.edit.manufacturing_status', 'label' => 'part.edit.manufacturing_status',
'choices' => $status_choices, 'choices' => $status_choices,
'required' => false, 'required' => false,
'disabled' => !$this->security->isGranted('status.edit', $part),
]); ]);
//Advanced section //Advanced section
$builder->add('needsReview', CheckboxType::class, [ $builder->add('needsReview', CheckboxType::class, [
'required' => false, 'required' => false,
'label' => 'part.edit.needs_review', 'label' => 'part.edit.needs_review',
'disabled' => !$this->security->isGranted('edit', $part),
]) ])
->add('favorite', CheckboxType::class, [ ->add('favorite', CheckboxType::class, [
'required' => false, 'required' => false,
@ -194,14 +183,12 @@ class PartBaseType extends AbstractType
'unit' => 'g', 'unit' => 'g',
'label' => 'part.edit.mass', 'label' => 'part.edit.mass',
'required' => false, 'required' => false,
'disabled' => !$this->security->isGranted('mass.edit', $part),
]) ])
->add('partUnit', StructuralEntityType::class, [ ->add('partUnit', StructuralEntityType::class, [
'class' => MeasurementUnit::class, 'class' => MeasurementUnit::class,
'required' => false, 'required' => false,
'disable_not_selectable' => true, 'disable_not_selectable' => true,
'label' => 'part.edit.partUnit', 'label' => 'part.edit.partUnit',
'disabled' => !$this->security->isGranted('unit.edit', $part),
]); ]);
//Comment section //Comment section
@ -212,20 +199,18 @@ class PartBaseType extends AbstractType
'rows' => 4, 'rows' => 4,
], ],
'mode' => 'markdown-full', 'mode' => 'markdown-full',
'disabled' => !$this->security->isGranted('comment.edit', $part),
'empty_data' => '', 'empty_data' => '',
]); ]);
//Part Lots section //Part Lots section
$builder->add('partLots', CollectionType::class, [ $builder->add('partLots', CollectionType::class, [
'entry_type' => PartLotType::class, 'entry_type' => PartLotType::class,
'allow_add' => $this->security->isGranted('lots.create', $part), 'allow_add' => true,
'allow_delete' => $this->security->isGranted('lots.delete', $part), 'allow_delete' => true,
'reindex_enable' => true, 'reindex_enable' => true,
'label' => false, 'label' => false,
'entry_options' => [ 'entry_options' => [
'measurement_unit' => $part->getPartUnit(), 'measurement_unit' => $part->getPartUnit(),
'disabled' => !$this->security->isGranted('lots.edit', $part),
], ],
'by_reference' => false, 'by_reference' => false,
]); ]);
@ -233,49 +218,45 @@ class PartBaseType extends AbstractType
//Attachment section //Attachment section
$builder->add('attachments', CollectionType::class, [ $builder->add('attachments', CollectionType::class, [
'entry_type' => AttachmentFormType::class, 'entry_type' => AttachmentFormType::class,
'allow_add' => $this->security->isGranted('attachments.create', $part), 'allow_add' => true,
'allow_delete' => $this->security->isGranted('attachments.delete', $part), 'allow_delete' => true,
'reindex_enable' => true, 'reindex_enable' => true,
'label' => false, 'label' => false,
'entry_options' => [ 'entry_options' => [
'data_class' => PartAttachment::class, 'data_class' => PartAttachment::class,
'disabled' => !$this->security->isGranted('attachments.edit', $part),
], ],
'by_reference' => false, 'by_reference' => false,
]); ]);
$builder->add('master_picture_attachment', MasterPictureAttachmentType::class, [ $builder->add('master_picture_attachment', MasterPictureAttachmentType::class, [
'required' => false, 'required' => false,
'disabled' => !$this->security->isGranted('attachments.edit', $part),
'label' => 'part.edit.master_attachment', 'label' => 'part.edit.master_attachment',
'entity' => $part, 'entity' => $part,
]); ]);
//Orderdetails section //Orderdetails section
$builder->add('orderdetails', WorkaroundCollectionType::class, [ $builder->add('orderdetails', CollectionType::class, [
'entry_type' => OrderdetailType::class, 'entry_type' => OrderdetailType::class,
'allow_add' => $this->security->isGranted('orderdetails.create', $part),
'allow_delete' => $this->security->isGranted('orderdetails.delete', $part),
'reindex_enable' => true, 'reindex_enable' => true,
'allow_add' => true,
'allow_delete' => true,
'label' => false, 'label' => false,
'by_reference' => false, 'by_reference' => false,
'prototype_data' => new Orderdetail(), 'prototype_data' => new Orderdetail(),
'entry_options' => [ 'entry_options' => [
'measurement_unit' => $part->getPartUnit(), 'measurement_unit' => $part->getPartUnit(),
'disabled' => !$this->security->isGranted('orderdetails.edit', $part),
], ],
]); ]);
$builder->add('parameters', CollectionType::class, [ $builder->add('parameters', CollectionType::class, [
'entry_type' => ParameterType::class, 'entry_type' => ParameterType::class,
'allow_add' => $this->security->isGranted('parameters.create', $part), 'allow_add' => true,
'allow_delete' => $this->security->isGranted('parameters.delete', $part), 'allow_delete' => true,
'label' => false, 'label' => false,
'reindex_enable' => true, 'reindex_enable' => true,
'by_reference' => false, 'by_reference' => false,
'prototype_data' => new PartParameter(), 'prototype_data' => new PartParameter(),
'entry_options' => [ 'entry_options' => [
'disabled' => !$this->security->isGranted('parameters.edit', $part),
'data_class' => PartParameter::class, 'data_class' => PartParameter::class,
], ],
]); ]);

View file

@ -1,23 +0,0 @@
<?php
namespace App\Form;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
/**
* This a workaround for the issue #37024.
*/
class WorkaroundCollectionType extends CollectionType
{
/**
* Use the original implementation for finishView() instead of the one, the one that cause the bug.
*/
public function finishView(FormView $view, FormInterface $form, array $options)
{
if ($view->vars['prototype']->vars['multipart']) {
$view->vars['multipart'] = true;
}
}
}

View file

@ -57,13 +57,6 @@ class PartVoter extends ExtendedVoter
protected function supports($attribute, $subject): bool protected function supports($attribute, $subject): bool
{ {
if (is_a($subject, Part::class, true)) { if (is_a($subject, Part::class, true)) {
//Check if a sub permission should be checked -> $attribute has format name.edit
if (false !== strpos($attribute, '.')) {
[$perm, $op] = explode('.', $attribute);
return $this->resolver->isValidOperation('parts_'.$perm, $op);
}
return $this->resolver->isValidOperation('parts', $attribute); return $this->resolver->isValidOperation('parts', $attribute);
} }
@ -73,13 +66,6 @@ class PartVoter extends ExtendedVoter
protected function voteOnUser(string $attribute, $subject, User $user): bool protected function voteOnUser(string $attribute, $subject, User $user): bool
{ {
//Check for sub permissions
if (false !== strpos($attribute, '.')) {
[$perm, $op] = explode('.', $attribute);
return $this->resolver->inherit($user, 'parts_'.$perm, $op) ?? false;
}
//Null concealing operator means, that no //Null concealing operator means, that no
return $this->resolver->inherit($user, 'parts', $attribute) ?? false; return $this->resolver->inherit($user, 'parts', $attribute) ?? false;
} }

View file

@ -11,7 +11,7 @@
</table> </table>
<button type="button" class="btn btn-success" {{ collection.create_btn() }} <button type="button" class="btn btn-success" {{ collection.create_btn() }}
{% if not is_granted('lots.create', part) %}disabled{% endif %}> {% if not is_granted('edit', part) %}disabled{% endif %}>
<i class="fas fa-plus-square fa-fw"></i> <i class="fas fa-plus-square fa-fw"></i>
{% trans %}part_lot.create{% endtrans %} {% trans %}part_lot.create{% endtrans %}
</button> </button>

View file

@ -6,12 +6,12 @@
<table class="table table-striped table-sm table-responsive-md" id="orderdetails_table" {{ collection.target() }}> <table class="table table-striped table-sm table-responsive-md" id="orderdetails_table" {{ collection.target() }}>
<tbody> <tbody>
{% for detail in form.orderdetails %} {% for detail in form.orderdetails %}
{{ form_widget(detail, {'disable_delete' : not is_granted('orderdetails.delete', part)}) }} {{ form_widget(detail) }}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<button type="button" class="btn btn-success" {{ collection.create_btn() }} {% if not is_granted('orderdetails.create', part) %}disabled{% endif %}> <button type="button" class="btn btn-success" {{ collection.create_btn() }}>
<i class="fas fa-plus-square fa-fw"></i> <i class="fas fa-plus-square fa-fw"></i>
{% trans %}orderdetail.create{% endtrans %} {% trans %}orderdetail.create{% endtrans %}
</button> </button>

View file

@ -24,7 +24,7 @@
</tbody> </tbody>
</table> </table>
<button type="button" class="btn btn-success" {% if not is_granted('parameters.create', part) %}disabled{% endif %} {{ collection.create_btn() }}> <button type="button" class="btn btn-success" {% if not is_granted('edit', part) %}disabled{% endif %} {{ collection.create_btn() }}>
<i class="fas fa-plus-square fa-fw"></i> <i class="fas fa-plus-square fa-fw"></i>
{% trans %}specification.create{% endtrans %} {% trans %}specification.create{% endtrans %}
</button> </button>

View file

@ -15,7 +15,7 @@
<td>{{ form_widget(form.price_related_quantity, {'attr': {'class': 'form-control-sm'}}) }} {{ form_errors(form.price_related_quantity) }}</td> <td>{{ form_widget(form.price_related_quantity, {'attr': {'class': 'form-control-sm'}}) }} {{ form_errors(form.price_related_quantity) }}</td>
<td> <td>
<button type="button" class="btn btn-danger order_btn_delete btn-sm" title="{% trans %}orderdetail.delete{% endtrans %}" <button type="button" class="btn btn-danger order_btn_delete btn-sm" title="{% trans %}orderdetail.delete{% endtrans %}"
{{ collection.delete_btn() }} {% if not is_granted('@parts_prices.delete') %}disabled{% endif %}> {{ collection.delete_btn() }}>
<i class="fas fa-trash-alt fa-fw"></i> <i class="fas fa-trash-alt fa-fw"></i>
</button> </button>
{{ form_errors(form) }} {{ form_errors(form) }}
@ -50,15 +50,14 @@
</tbody> </tbody>
</table> </table>
<button type="button" class="btn btn-success" {{ collection.create_pricedetail_btn() }} {% if not is_granted('@parts_prices.create') %}disabled{% endif %}> <button type="button" class="btn btn-success" {{ collection.create_pricedetail_btn() }}>
<i class="fas fa-plus-square fa-fw"></i> <i class="fas fa-plus-square fa-fw"></i>
{% trans %}pricedetail.create{% endtrans %} {% trans %}pricedetail.create{% endtrans %}
</button> </button>
</div> </div>
</td> </td>
<td> <td>
<button type="button" class="btn btn-danger order_btn_delete" {{ collection.delete_btn() }} title="{% trans %}orderdetail.delete{% endtrans %}" <button type="button" class="btn btn-danger order_btn_delete" {{ collection.delete_btn() }} title="{% trans %}orderdetail.delete{% endtrans %}">
{% if not is_granted('@parts_orderdetails.delete') %}disabled{% endif %}>
<i class="fas fa-trash-alt fa-fw"></i> <i class="fas fa-trash-alt fa-fw"></i>
</button> </button>
{{ form_errors(form) }} {{ form_errors(form) }}
@ -93,8 +92,7 @@
{{ form_widget(form) }} {{ form_widget(form) }}
</td> </td>
<td> <td>
<button type="button" class="btn btn-danger lot_btn_delete" {{ collection.delete_btn() }} <button type="button" class="btn btn-danger lot_btn_delete" {{ collection.delete_btn() }}>
{% if not is_granted('lots.delete', form.parent.parent.vars.data) %}disabled{% endif %}>
<i class="fas fa-trash-alt fa-fw"></i> <i class="fas fa-trash-alt fa-fw"></i>
{% trans %}part_lot.delete{% endtrans %} {% trans %}part_lot.delete{% endtrans %}
</button> </button>
@ -111,7 +109,7 @@
{{ form_widget(form) }} {{ form_widget(form) }}
</td> </td>
<td> <td>
<button type="button" class="btn btn-danger lot_btn_delete" {{ collection.delete_btn() }} {# {% if not is_granted('attachments.delete', part) %}disabled{% endif %}#}> <button type="button" class="btn btn-danger lot_btn_delete" {{ collection.delete_btn() }}>
<i class="fas fa-trash-alt fa-fw"></i> <i class="fas fa-trash-alt fa-fw"></i>
{% trans %}attachment.delete{% endtrans %} {% trans %}attachment.delete{% endtrans %}
</button> </button>

View file

@ -9,7 +9,7 @@
<tr> <tr>
<td>{% trans %}user.creating_user{% endtrans %}</td> <td>{% trans %}user.creating_user{% endtrans %}</td>
<td>{% if is_granted('show_users', part) %} <td>{% if is_granted('show_history', part) %}
{{ creating_user(part).fullName(true) ?? 'Unknown'|trans }} {{ creating_user(part).fullName(true) ?? 'Unknown'|trans }}
{% else %} {% else %}
{% trans %}accessDenied{% endtrans %} {% trans %}accessDenied{% endtrans %}
@ -24,7 +24,7 @@
<tr> <tr>
<td>{% trans %}user.last_editing_user{% endtrans %}</td> <td>{% trans %}user.last_editing_user{% endtrans %}</td>
<td>{% if is_granted('show_users', part) %} <td>{% if is_granted('show_history', part) %}
{{ last_editing_user(part).fullName(true) ?? 'Unknown'|trans }} {{ last_editing_user(part).fullName(true) ?? 'Unknown'|trans }}
{% else %} {% else %}
{% trans %}accessDenied{% endtrans %} {% trans %}accessDenied{% endtrans %}

View file

@ -12,7 +12,7 @@
</tbody> </tbody>
</table> </table>
<button type="button" class="btn btn-success" {{ collection.create_btn() }} {% if part_mode and not is_granted('attachments.create', part) %}disabled{% endif %}> <button type="button" class="btn btn-success" {{ collection.create_btn() }} {% if part_mode and not is_granted('edit', part) %}disabled{% endif %}>
<i class="fas fa-plus-square fa-fw"></i> <i class="fas fa-plus-square fa-fw"></i>
{% trans %}attachment.create{% endtrans %} {% trans %}attachment.create{% endtrans %}
</button> </button>

View file

@ -136,7 +136,7 @@
{% else %} {% else %}
{{ entity.addedDate | format_datetime(datetime_format) }} {{ entity.addedDate | format_datetime(datetime_format) }}
{% endif %} {% endif %}
{% if is_granted('show_users', entity) %} {% if is_granted('show_history', entity) %}
{% if lastModified == true %} {% if lastModified == true %}
{% set user = last_editing_user(entity) %} {% set user = last_editing_user(entity) %}
{% else %} {% else %}
@ -145,9 +145,9 @@
{% if user is not null %} {% if user is not null %}
{% if user.fullName is not empty %} {% if user.fullName is not empty %}
<a href="{{ path('user_info', {"id": user.id}) }}" title="@{{ user.name }}"><i>({{ user.fullName }})</i></a> (<a href="{{ path('user_info', {"id": user.id}) }}" title="@{{ user.name }}">{{ user.fullName }}</a>)
{% else %} {% else %}
<a href="{{ path('user_info', {"id": user.id}) }}" title="@{{ user.name }}"><i>(@{{ user.name }})</i></a> (<a href="{{ path('user_info', {"id": user.id}) }}" title="@{{ user.name }}">@{{ user.name }}</a>)
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}