mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-03-04 06:19:36 +00:00
Compare commits
10 commits
247fed7d74
...
7054c51490
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7054c51490 | ||
|
|
808af0d3cd | ||
|
|
b14fc0e22a | ||
|
|
f7259a118b | ||
|
|
be60c4363c | ||
|
|
631db7df31 | ||
|
|
781ea45633 | ||
|
|
0eee161630 | ||
|
|
7a1b9b8ce1 | ||
|
|
3fcb5ce82e |
19 changed files with 1653 additions and 1229 deletions
|
|
@ -13,8 +13,8 @@
|
|||
"ext-mbstring": "*",
|
||||
"amphp/http-client": "^5.1",
|
||||
"api-platform/doctrine-orm": "^4.1",
|
||||
"api-platform/symfony": "^4.0.0",
|
||||
"api-platform/json-api": "^4.0.0",
|
||||
"api-platform/symfony": "^4.0.0",
|
||||
"beberlei/doctrineextensions": "^1.2",
|
||||
"brick/math": "^0.13.1",
|
||||
"composer/ca-bundle": "^1.5",
|
||||
|
|
@ -25,16 +25,16 @@
|
|||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||
"doctrine/orm": "^3.2.0",
|
||||
"dompdf/dompdf": "^v3.0.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"florianv/swap": "^4.0",
|
||||
"florianv/swap-bundle": "dev-master",
|
||||
"gregwar/captcha-bundle": "^2.1.0",
|
||||
"hshn/base64-encoded-file": "^5.0",
|
||||
"jbtronics/2fa-webauthn": "^v2.2.0",
|
||||
"jbtronics/2fa-webauthn": "^3.0.0",
|
||||
"jbtronics/dompdf-font-loader-bundle": "^1.0.0",
|
||||
"jbtronics/settings-bundle": "^v2.6.0",
|
||||
"jfcherng/php-diff": "^6.14",
|
||||
"knpuniversity/oauth2-client-bundle": "^2.15",
|
||||
"league/commonmark": "^2.7",
|
||||
"league/csv": "^9.8.0",
|
||||
"league/html-to-markdown": "^5.0.1",
|
||||
"liip/imagine-bundle": "^2.2",
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
"twig/intl-extra": "^3.8",
|
||||
"twig/markdown-extra": "^3.8",
|
||||
"twig/string-extra": "^3.8",
|
||||
"web-auth/webauthn-symfony-bundle": "^4.0.0"
|
||||
"web-auth/webauthn-symfony-bundle": "^5.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dama/doctrine-test-bundle": "^v8.0.0",
|
||||
|
|
|
|||
1075
composer.lock
generated
1075
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -32,5 +32,5 @@ return [
|
|||
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
|
||||
Jbtronics\SettingsBundle\JbtronicsSettingsBundle::class => ['all' => true],
|
||||
Jbtronics\TranslationEditorBundle\JbtronicsTranslationEditorBundle::class => ['dev' => true],
|
||||
\ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
||||
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@ doctrine:
|
|||
tinyint:
|
||||
class: App\Doctrine\Types\TinyIntType
|
||||
|
||||
# This was removed in doctrine/orm 4.0 but we need it for the WebauthnKey entity
|
||||
array:
|
||||
class: App\Doctrine\Types\ArrayType
|
||||
|
||||
schema_filter: ~^(?!internal)~
|
||||
# Only enable this when needed
|
||||
profiling_collect_backtrace: false
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ security:
|
|||
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js|\.well-known)/
|
||||
security: false
|
||||
main:
|
||||
provider: app_user_provider
|
||||
|
|
|
|||
27
docs/upgrade/1_to_2.md
Normal file
27
docs/upgrade/1_to_2.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
layout: default
|
||||
title: Upgrade from Part-DB 1.x to 2.x
|
||||
nav_order: 1
|
||||
has_children: false
|
||||
---
|
||||
|
||||
# Upgrade from Part-DB 1.x to 2.x
|
||||
|
||||
Part-DB 2.0 is a major release that changes a lot of things internally, but it is still compatible with Part-DB 1.x.
|
||||
Depending on your preferences, you will have to do some changes to your Part-DB installation, this document will guide
|
||||
you through the upgrade process.
|
||||
|
||||
## New requirements
|
||||
*If you are running Part-DB inside a docker container, you can skip this section, as the new requirements are already
|
||||
fulfilled by the official Part-DB docker image.*
|
||||
|
||||
Part-DB 2.0 requires at least PHP 8.2 (newer versions are recommended). So if your existing Part-DB installation is still
|
||||
running PHP 8.1, you will have to upgrade your PHP version first.
|
||||
The minimum required version of node.js is now 20.0 or newer, so if you are using 18.0, you will have to upgrade it too.
|
||||
|
||||
Most distributions should have the possibility to get backports for PHP 8.4 and modern nodejs, so you should be able to
|
||||
easily upgrade your system to the new requirements. Otherwise, you can use the official Part-DB docker image, which
|
||||
ships all required dependencies and is always up to date with the latest requirements, so that you do not have to worry
|
||||
about the requirements at all.
|
||||
|
||||
|
||||
9
docs/upgrade/index.md
Normal file
9
docs/upgrade/index.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
layout: default
|
||||
title: Upgrade
|
||||
nav_order: 7
|
||||
has_children: true
|
||||
---
|
||||
|
||||
This section provides information on how to upgrade Part-DB to the latest version.
|
||||
This is intended for major release upgrades, where requirements or things changes significantly.
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
layout: default
|
||||
title: Upgrade from legacy Part-DB version (<1.0)
|
||||
nav_order: 100
|
||||
redirect_from: /upgrade_legacy
|
||||
---
|
||||
|
||||
# Upgrade from legacy Part-DB version
|
||||
75
migrations/Version20250813214628.php
Normal file
75
migrations/Version20250813214628.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use App\Migration\AbstractMultiPlatformMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20250813214628 extends AbstractMultiPlatformMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Migrate webauthn_keys transports and other_ui fields to JSON type';
|
||||
}
|
||||
|
||||
public function convertArrayToJson(): void
|
||||
{
|
||||
$connection = $this->connection;
|
||||
$rows = $connection->fetchAllAssociative('SELECT id, transports, other_ui FROM webauthn_keys');
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$id = $row['id'];
|
||||
$new_transports = json_encode(unserialize($row['transports'], ['allowed_classes' => false]),
|
||||
JSON_THROW_ON_ERROR);
|
||||
$new_other_ui = json_encode(unserialize($row['other_ui'], ['allowed_classes' => false]),
|
||||
JSON_THROW_ON_ERROR);
|
||||
|
||||
$connection->executeStatement(
|
||||
'UPDATE webauthn_keys SET transports = :transports, other_ui = :other_ui WHERE id = :id',
|
||||
[
|
||||
'transports' => $new_transports,
|
||||
'other_ui' => $new_other_ui,
|
||||
'id' => $id,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function mySQLUp(Schema $schema): void
|
||||
{
|
||||
$this->convertArrayToJson();
|
||||
$this->addSql('ALTER TABLE webauthn_keys CHANGE transports transports JSON NOT NULL, CHANGE other_ui other_ui JSON DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function mySQLDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE webauthn_keys CHANGE transports transports LONGTEXT NOT NULL, CHANGE other_ui other_ui LONGTEXT DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function sqLiteUp(Schema $schema): void
|
||||
{
|
||||
//As there is no JSON type in SQLite, we only need to convert the data.
|
||||
$this->convertArrayToJson();
|
||||
}
|
||||
|
||||
public function sqLiteDown(Schema $schema): void
|
||||
{
|
||||
//Nothing to do here, as SQLite does not support JSON type and we are not changing the column type.
|
||||
}
|
||||
|
||||
public function postgreSQLUp(Schema $schema): void
|
||||
{
|
||||
$this->convertArrayToJson();
|
||||
$this->addSql('ALTER TABLE webauthn_keys ALTER transports TYPE JSON USING transports::JSON');
|
||||
$this->addSql('ALTER TABLE webauthn_keys ALTER other_ui TYPE JSON USING other_ui::JSON');
|
||||
}
|
||||
|
||||
public function postgreSQLDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE webauthn_keys ALTER transports TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE webauthn_keys ALTER other_ui TYPE TEXT');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Doctrine\Types;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Types\Exception\SerializationFailed;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\Deprecations\Deprecation;
|
||||
|
||||
use function is_resource;
|
||||
use function restore_error_handler;
|
||||
use function serialize;
|
||||
use function set_error_handler;
|
||||
use function stream_get_contents;
|
||||
use function unserialize;
|
||||
|
||||
use const E_DEPRECATED;
|
||||
use const E_USER_DEPRECATED;
|
||||
|
||||
/**
|
||||
* This class is taken from doctrine ORM 3.8. https://github.com/doctrine/dbal/blob/3.8.x/src/Types/ArrayType.php
|
||||
*
|
||||
* It was removed in doctrine ORM 4.0. However, we require it for backward compatibility with WebauthnKey.
|
||||
* Therefore, we manually added it here as a custom type as a forward compatibility layer.
|
||||
*/
|
||||
class ArrayType extends Type
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
|
||||
{
|
||||
return $platform->getClobTypeDeclarationSQL($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): string
|
||||
{
|
||||
return serialize($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = is_resource($value) ? stream_get_contents($value) : $value;
|
||||
|
||||
set_error_handler(function (int $code, string $message): bool {
|
||||
if ($code === E_DEPRECATED || $code === E_USER_DEPRECATED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Change to original code. Use SerializationFailed instead of ConversionException.
|
||||
throw new SerializationFailed("Serialization failed (Code $code): " . $message);
|
||||
});
|
||||
|
||||
try {
|
||||
//Change to original code. Use false for allowed_classes, to avoid unsafe unserialization of objects.
|
||||
return unserialize($value, ['allowed_classes' => false]);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
|
||||
{
|
||||
Deprecation::triggerIfCalledFromOutside(
|
||||
'doctrine/dbal',
|
||||
'https://github.com/doctrine/dbal/pull/5509',
|
||||
'%s is deprecated.',
|
||||
__METHOD__,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -100,16 +100,19 @@ class WebauthnKey extends BasePublicKeyCredentialSource implements TimeStampable
|
|||
public static function fromRegistration(BasePublicKeyCredentialSource $registration): self
|
||||
{
|
||||
return new self(
|
||||
$registration->getPublicKeyCredentialId(),
|
||||
$registration->getType(),
|
||||
$registration->getTransports(),
|
||||
$registration->getAttestationType(),
|
||||
$registration->getTrustPath(),
|
||||
$registration->getAaguid(),
|
||||
$registration->getCredentialPublicKey(),
|
||||
$registration->getUserHandle(),
|
||||
$registration->getCounter(),
|
||||
$registration->getOtherUI()
|
||||
publicKeyCredentialId: $registration->publicKeyCredentialId,
|
||||
type: $registration->type,
|
||||
transports: $registration->transports,
|
||||
attestationType: $registration->attestationType,
|
||||
trustPath: $registration->trustPath,
|
||||
aaguid: $registration->aaguid,
|
||||
credentialPublicKey: $registration->credentialPublicKey,
|
||||
userHandle: $registration->userHandle,
|
||||
counter: $registration->counter,
|
||||
otherUI: $registration->otherUI,
|
||||
backupEligible: $registration->backupEligible,
|
||||
backupStatus: $registration->backupStatus,
|
||||
uvInitialized: $registration->uvInitialized,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\TwoFactorProviderInterface
|
|||
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
|
||||
use Webauthn\PublicKeyCredential;
|
||||
|
||||
/**
|
||||
* This class decorates the Webauthn TwoFactorProvider and adds additional logic which allows us to set a last used date
|
||||
|
|
@ -88,10 +89,12 @@ class WebauthnKeyLastUseTwoFactorProvider implements TwoFactorProviderInterface
|
|||
|
||||
private function getWebauthnKeyFromCode(string $authenticationCode): ?WebauthnKey
|
||||
{
|
||||
$publicKeyCredentialLoader = $this->webauthnProvider->getPublicKeyCredentialLoader();
|
||||
$serializer = $this->webauthnProvider->getWebauthnSerializer();
|
||||
|
||||
//Try to load the public key credential from the code
|
||||
$publicKeyCredential = $publicKeyCredentialLoader->load($authenticationCode);
|
||||
$publicKeyCredential = $serializer->deserialize($authenticationCode, PublicKeyCredential::class, 'json', [
|
||||
'json_decode_options' => JSON_THROW_ON_ERROR
|
||||
]);
|
||||
|
||||
//Find the credential source for the given credential id
|
||||
$publicKeyCredentialSource = $this->publicKeyCredentialSourceRepository->findOneByCredentialId($publicKeyCredential->rawId);
|
||||
|
|
@ -103,4 +106,4 @@ class WebauthnKeyLastUseTwoFactorProvider implements TwoFactorProviderInterface
|
|||
|
||||
return $publicKeyCredentialSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ class AttachmentURLGenerator
|
|||
/**
|
||||
* Returns a URL to a thumbnail of the attachment file.
|
||||
* For external files the original URL is returned.
|
||||
* @return string|null The URL or null if the attachment file is not existing
|
||||
* @return string|null The URL or null if the attachment file is not existing or is invalid
|
||||
*/
|
||||
public function getThumbnailURL(Attachment $attachment, string $filter_name = 'thumbnail_sm'): ?string
|
||||
{
|
||||
if (!$attachment->isPicture()) {
|
||||
throw new InvalidArgumentException('Thumbnail creation only works for picture attachments!');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$attachment->hasInternal()){
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class EntityImporter
|
|||
/**
|
||||
* Creates many entries at once, based on a (text) list of name.
|
||||
* The created entities are not persisted to database yet, so you have to do it yourself.
|
||||
* It returns all entities in the hierachy chain (even if they are already persisted).
|
||||
*
|
||||
* @template T of AbstractNamedDBElement
|
||||
* @param string $lines The list of names seperated by \n
|
||||
|
|
@ -132,32 +133,38 @@ class EntityImporter
|
|||
//We can only use the getNewEntityFromPath function, if the repository is a StructuralDBElementRepository
|
||||
if ($repo instanceof StructuralDBElementRepository) {
|
||||
$entities = $repo->getNewEntityFromPath($new_path);
|
||||
$entity = end($entities);
|
||||
if ($entity === false) {
|
||||
if ($entities === []) {
|
||||
throw new InvalidArgumentException('getNewEntityFromPath returned an empty array!');
|
||||
}
|
||||
} else { //Otherwise just create a new entity
|
||||
$entity = new $class_name;
|
||||
$entity->setName($name);
|
||||
$entities = [$entity];
|
||||
}
|
||||
|
||||
|
||||
//Validate entity
|
||||
$tmp = $this->validator->validate($entity);
|
||||
//If no error occured, write entry to DB:
|
||||
if (0 === count($tmp)) {
|
||||
$valid_entities[] = $entity;
|
||||
} else { //Otherwise log error
|
||||
$errors[] = [
|
||||
'entity' => $entity,
|
||||
'violations' => $tmp,
|
||||
];
|
||||
foreach ($entities as $entity) {
|
||||
$tmp = $this->validator->validate($entity);
|
||||
//If no error occured, write entry to DB:
|
||||
if (0 === count($tmp)) {
|
||||
$valid_entities[] = $entity;
|
||||
} else { //Otherwise log error
|
||||
$errors[] = [
|
||||
'entity' => $entity,
|
||||
'violations' => $tmp,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$last_element = $entity;
|
||||
$last_element = end($entities);
|
||||
if ($last_element === false) {
|
||||
$last_element = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $valid_entities;
|
||||
//Only return objects once
|
||||
return array_values(array_unique($valid_entities));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ use App\Entity\Parts\Manufacturer;
|
|||
use App\Entity\Parts\Footprint;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Services\Formatters\SIFormatter;
|
||||
use Parsedown;
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
|
||||
use League\CommonMark\MarkdownConverter;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
|
|
@ -54,8 +56,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
*/
|
||||
final class PartProvider implements PlaceholderProviderInterface
|
||||
{
|
||||
private readonly MarkdownConverter $inlineConverter;
|
||||
|
||||
public function __construct(private readonly SIFormatter $siFormatter, private readonly TranslatorInterface $translator)
|
||||
{
|
||||
$environment = new Environment();
|
||||
$environment->addExtension(new InlinesOnlyExtension());
|
||||
$this->inlineConverter = new MarkdownConverter($environment);
|
||||
}
|
||||
|
||||
public function replace(string $placeholder, object $part, array $options = []): ?string
|
||||
|
|
@ -112,22 +119,20 @@ final class PartProvider implements PlaceholderProviderInterface
|
|||
return $this->translator->trans($part->getManufacturingStatus()->toTranslationKey());
|
||||
}
|
||||
|
||||
$parsedown = new Parsedown();
|
||||
|
||||
if ('[[DESCRIPTION]]' === $placeholder) {
|
||||
return $parsedown->line($part->getDescription());
|
||||
return trim($this->inlineConverter->convert($part->getDescription())->getContent());
|
||||
}
|
||||
|
||||
if ('[[DESCRIPTION_T]]' === $placeholder) {
|
||||
return strip_tags((string) $parsedown->line($part->getDescription()));
|
||||
return trim(strip_tags($this->inlineConverter->convert($part->getDescription())->getContent()));
|
||||
}
|
||||
|
||||
if ('[[COMMENT]]' === $placeholder) {
|
||||
return $parsedown->line($part->getComment());
|
||||
return trim($this->inlineConverter->convert($part->getComment())->getContent());
|
||||
}
|
||||
|
||||
if ('[[COMMENT_T]]' === $placeholder) {
|
||||
return strip_tags((string) $parsedown->line($part->getComment()));
|
||||
return trim(strip_tags($this->inlineConverter->convert($part->getComment())->getContent()));
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -133,9 +133,6 @@
|
|||
"ekino/phpstan-banned-code": {
|
||||
"version": "v0.3.1"
|
||||
},
|
||||
"erusev/parsedown": {
|
||||
"version": "1.7.4"
|
||||
},
|
||||
"florianv/exchanger": {
|
||||
"version": "1.4.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ class EntityImporterTest extends WebTestCase
|
|||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$parent = $em->find(AttachmentType::class, 1);
|
||||
$results = $this->service->massCreation($lines, AttachmentType::class, $parent, $errors);
|
||||
$this->assertCount(3, $results);
|
||||
$this->assertSame($parent, $results[0]->getParent());
|
||||
$this->assertCount(4, $results);
|
||||
$this->assertSame("Test 1", $results[1]->getName());
|
||||
|
||||
//Test for addition of existing elements
|
||||
$errors = [];
|
||||
|
|
@ -113,6 +113,31 @@ EOT;
|
|||
|
||||
}
|
||||
|
||||
public function testMassCreationArrow(): void
|
||||
{
|
||||
$input = <<<EOT
|
||||
Test1 -> Test1.1
|
||||
Test1 -> Test1.2
|
||||
Test2 -> Test2.1
|
||||
Test1
|
||||
Test1.3
|
||||
EOT;
|
||||
|
||||
$errors = [];
|
||||
$results = $this->service->massCreation($input, AttachmentType::class, null, $errors);
|
||||
|
||||
//We have 6 elements, and 0 errors
|
||||
$this->assertCount(0, $errors);
|
||||
$this->assertCount(6, $results);
|
||||
|
||||
$this->assertEquals('Test1', $results[0]->getName());
|
||||
$this->assertEquals('Test1.1', $results[1]->getName());
|
||||
$this->assertEquals('Test1.2', $results[2]->getName());
|
||||
$this->assertEquals('Test2', $results[3]->getName());
|
||||
$this->assertEquals('Test2.1', $results[4]->getName());
|
||||
$this->assertEquals('Test1.3', $results[5]->getName());
|
||||
}
|
||||
|
||||
public function testMassCreationNested(): void
|
||||
{
|
||||
$input = <<<EOT
|
||||
|
|
@ -132,15 +157,15 @@ EOT;
|
|||
|
||||
//We have 7 elements, and 0 errors
|
||||
$this->assertCount(0, $errors);
|
||||
$this->assertCount(7, $results);
|
||||
$this->assertCount(8, $results);
|
||||
|
||||
$element1 = $results[0];
|
||||
$element11 = $results[1];
|
||||
$element111 = $results[2];
|
||||
$element112 = $results[3];
|
||||
$element12 = $results[4];
|
||||
$element121 = $results[5];
|
||||
$element2 = $results[6];
|
||||
$element1 = $results[1];
|
||||
$element11 = $results[2];
|
||||
$element111 = $results[3];
|
||||
$element112 = $results[4];
|
||||
$element12 = $results[5];
|
||||
$element121 = $results[6];
|
||||
$element2 = $results[7];
|
||||
|
||||
$this->assertSame('Test 1', $element1->getName());
|
||||
$this->assertSame('Test 1.1', $element11->getName());
|
||||
|
|
|
|||
|
|
@ -7157,12 +7157,15 @@ Exampletown</target>
|
|||
</notes>
|
||||
<segment state="translated">
|
||||
<source>mass_creation.lines.placeholder</source>
|
||||
<target>Element 1
|
||||
<target><![CDATA[Element 1
|
||||
Element 1.1
|
||||
Element 1.1.1
|
||||
Element 1.2
|
||||
Element 2
|
||||
Element 3</target>
|
||||
Element 3
|
||||
|
||||
Element 1 -> Element 1.1
|
||||
Element 1 -> Element 1.2]]></target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="TWSqPFi" name="entity.mass_creation.btn">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue