diff --git a/src/Entity/Attachments/Attachment.php b/src/Entity/Attachments/Attachment.php index 409320e1..96399fe2 100644 --- a/src/Entity/Attachments/Attachment.php +++ b/src/Entity/Attachments/Attachment.php @@ -59,7 +59,10 @@ abstract class Attachment extends NamedDBElement /** * When the path begins with one of this placeholders */ - const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%FOOTPRINTS%', '%FOOTPRINTS3D%']; + const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%']; + + /** @var array Placeholders for attachments which using built in files. */ + const BUILTIN_PLACEHOLDER = ['%FOOTPRINTS%', '%FOOTPRINTS3D%']; /** * @var bool @@ -128,7 +131,17 @@ abstract class Attachment extends NamedDBElement return true; } - return !in_array($tmp[0], static::INTERNAL_PLACEHOLDER, false); + return !in_array($tmp[0], array_merge(static::INTERNAL_PLACEHOLDER, static::BUILTIN_PLACEHOLDER), false); + } + + /** + * Checks if the attachment file is using a builtin file. (see BUILTIN_PLACEHOLDERS const for possible placeholders) + * If a file is built in, the path is shown to user in url field (no sensitive infos are provided) + * @return bool True if the attachment is uning an builtin file. + */ + public function isBuiltIn() : bool + { + return static::checkIfBuiltin($this->path); } /******************************************************************************** @@ -167,13 +180,13 @@ abstract class Attachment extends NamedDBElement } /** - * The URL to the external file. - * Returns null, if the file is not external. + * The URL to the external file, or the path to the built in file. + * Returns null, if the file is not external (and not builtin). * @return string|null */ public function getURL(): ?string { - if (!$this->isExternal()) { + if (!$this->isExternal() && !$this->isBuiltIn()) { return null; } @@ -204,8 +217,6 @@ abstract class Attachment extends NamedDBElement return $this->path; } - - /** * Returns the filename of the attachment. * For a path like %BASE/path/foo.bar, foo.bar will be returned. @@ -336,6 +347,22 @@ abstract class Attachment extends NamedDBElement * Static functions *****************************************************************************************************/ + /** + * Checks if the given path is a path to a builtin ressource. + * @param string $path The path that should be checked + * @return bool True if the path is pointing to a builtin ressource. + */ + public static function checkIfBuiltin(string $path) : bool + { + //After the %PLACEHOLDER% comes a slash, so we can check if we have a placholder via explode + $tmp = explode('/', $path); + //Builtins must have a %PLACEHOLDER% construction + if (empty($tmp)) { + return false; + } + return in_array($tmp[0], static::BUILTIN_PLACEHOLDER, false); + } + /** * Check if a string is a URL and is valid. * @param $string string The string which should be checked. diff --git a/src/EntityListeners/AttachmentDeleteListener.php b/src/EntityListeners/AttachmentDeleteListener.php index 239ef65e..b2572063 100644 --- a/src/EntityListeners/AttachmentDeleteListener.php +++ b/src/EntityListeners/AttachmentDeleteListener.php @@ -66,6 +66,11 @@ class AttachmentDeleteListener public function preUpdateHandler(Attachment $attachment, PreUpdateEventArgs $event) { if ($event->hasChangedField('path')) { + //Dont delete file if the attachment uses a builtin ressource: + if (Attachment::checkIfBuiltin($event->getOldValue('path'))) { + return; + } + $file = new \SplFileInfo($this->attachmentHelper->placeholderToRealPath($event->getOldValue('path'))); $this->attachmentReverseSearch->deleteIfNotUsed($file); } @@ -81,6 +86,11 @@ class AttachmentDeleteListener */ public function postRemoveHandler(Attachment $attachment, LifecycleEventArgs $event) { + //Dont delete file if the attachment uses a builtin ressource: + if (Attachment::checkIfBuiltin($event->getOldValue('path'))) { + return; + } + $file = $this->attachmentHelper->attachmentToFile($attachment); //Only delete if the attachment has a valid file. if ($file !== null) { diff --git a/src/Form/AttachmentFormType.php b/src/Form/AttachmentFormType.php index 61bf0054..d3edd9ec 100644 --- a/src/Form/AttachmentFormType.php +++ b/src/Form/AttachmentFormType.php @@ -37,6 +37,7 @@ use App\Entity\Attachments\AttachmentType; use App\Entity\Base\StructuralDBElement; use App\Form\Type\StructuralEntityType; use App\Services\AttachmentHelper; +use App\Validator\Constraints\UrlOrBuiltin; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\FileType; @@ -75,11 +76,11 @@ class AttachmentFormType extends AbstractType 'attr' => ['class' => 'form-control-sm'], 'label_attr' => ['class' => 'checkbox-custom']]); - $builder->add('url', UrlType::class, [ + $builder->add('url', TextType::class, [ 'label' => $this->trans->trans('attachment.edit.url'), 'required' => false, 'constraints' => [ - new Url() + $options['allow_builtins'] ? new UrlOrBuiltin() : new Url() ] ]); @@ -101,7 +102,8 @@ class AttachmentFormType extends AbstractType { $resolver->setDefaults([ 'data_class' => Attachment::class, - 'max_file_size' => '16M' + 'max_file_size' => '16M', + 'allow_builtins' => true ]); } diff --git a/src/Validator/Constraints/UrlOrBuiltin.php b/src/Validator/Constraints/UrlOrBuiltin.php new file mode 100644 index 00000000..dcfcabc7 --- /dev/null +++ b/src/Validator/Constraints/UrlOrBuiltin.php @@ -0,0 +1,46 @@ +allowed_placeholders, false)) { + return; + } + + parent::validate($value, $constraint); // TODO: Change the autogenerated stub + } + + +} \ No newline at end of file diff --git a/tests/Entity/AttachmentTest.php b/tests/Entity/AttachmentTest.php index b02cf98a..998d9888 100644 --- a/tests/Entity/AttachmentTest.php +++ b/tests/Entity/AttachmentTest.php @@ -105,6 +105,27 @@ class AttachmentTest extends TestCase $this->assertTrue($attachment->isPicture()); } + public function testIsBuiltIn() + { + $attachment = new PartAttachment(); + $this->setProtectedProperty($attachment, 'path', '%MEDIA%/foo/bar.txt'); + $this->assertFalse($attachment->isBuiltIn()); + + $this->setProtectedProperty($attachment, 'path', '%BASE%/foo/bar.txt'); + $this->assertFalse($attachment->isBuiltIn()); + + $this->setProtectedProperty($attachment, 'path', '/'); + $this->assertFalse($attachment->isBuiltIn()); + + $this->setProtectedProperty($attachment, 'path', 'https://google.de'); + $this->assertFalse($attachment->isBuiltIn()); + + $this->setProtectedProperty($attachment, 'path', '%FOOTPRINTS%/foo/bar.txt'); + $this->assertTrue($attachment->isBuiltIn()); + + + } + public function testGetHost() { $attachment = new PartAttachment();