From 4a7c514a7886b86e6df9c64f44f9c05c774046c6 Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Wed, 11 Dec 2024 18:57:04 +0700 Subject: [PATCH 01/13] [import] Fix measurement replacements --- app/Enums/FrontendEnum.php | 1 + app/Import.php | 8 ++ app/Importers/UpmImporter.php | 144 ++++++++++++++++++++++++ database/seeders/DatabaseSeeder.php | 1 + database/seeders/ImportsTableSeeder.php | 21 ++++ lang/cs/item.php | 59 +++++----- lang/en/item.php | 59 +++++----- lang/sk/item.php | 59 +++++----- tests/Importers/UpmImporterTest.php | 113 +++++++++++++++++++ 9 files changed, 375 insertions(+), 90 deletions(-) create mode 100644 app/Importers/UpmImporter.php create mode 100644 database/seeders/ImportsTableSeeder.php create mode 100644 tests/Importers/UpmImporterTest.php diff --git a/app/Enums/FrontendEnum.php b/app/Enums/FrontendEnum.php index e5e550622..1f92a3ece 100644 --- a/app/Enums/FrontendEnum.php +++ b/app/Enums/FrontendEnum.php @@ -6,4 +6,5 @@ enum FrontendEnum: string { case WEBUMENIA = 'webumenia'; case MORAVSKA_GALERIE = 'moravska-galerie'; + case UPM = 'upm'; } diff --git a/app/Import.php b/app/Import.php index b6c821708..e65ea7080 100644 --- a/app/Import.php +++ b/app/Import.php @@ -30,6 +30,14 @@ class Import extends Model 'completed_at' => 'datetime', ]; + protected $fillable = [ + 'name', + 'dir_path', + 'iip_dir_path', + 'class_name', + 'disk', + ]; + public function user() { return $this->belongsTo(User::class); diff --git a/app/Importers/UpmImporter.php b/app/Importers/UpmImporter.php new file mode 100644 index 000000000..756c6d7b7 --- /dev/null +++ b/app/Importers/UpmImporter.php @@ -0,0 +1,144 @@ + 'Inventárníčíslo', + 'title:cs' => 'Název', + 'title:sk' => 'Název', + 'title:en' => 'Název EN', + 'dating:cs' => 'Datace', + 'dating:sk' => 'Datace', + 'date_earliest' => 'Od', + 'date_latest' => 'Do', + 'work_type:cs' => 'Výtvarný druh', + 'work_type:sk' => 'Výtvarný druh', + 'object_type:cs' => 'Typ', + 'object_type:sk' => 'Typ', + 'medium:cs' => 'Materiál', + 'medium:sk' => 'Materiál', + 'technique:cs' => 'Technika', + 'technique:sk' => 'Technika', + 'topic:cs' => 'Námět', + 'topic:sk' => 'Námět', + 'inscription:cs' => 'Značení', + 'inscription:sk' => 'Značení', + 'related_work:sk' => 'Sbírka', + 'related_work:cs' => 'Sbírka', + 'acquisition_date' => 'Datum akvizice', + ]; + + protected $defaults = [ + 'relationship_type:sk' => 'zo súboru', + 'relationship_type:cs' => 'ze souboru', + 'relationship_type:en' => 'collection', + 'gallery:cs' => 'Uměleckoprůmyslové museum v Praze, UPM', + 'gallery:sk' => 'Umeleckopriemyselné múzeum v Prahe, UPM', + 'frontends' => [ + FrontendEnum::UPM, + FrontendEnum::WEBUMENIA, + ], + ]; + + protected static $options = [ + 'delimiter' => ';', + 'enclosure' => '"', + 'escape' => '\\', + 'newline' => "\n", + ]; + + protected function init() + { + $this->sanitizers[] = function ($value) { + return empty_to_null(trim($value)); + }; + } + + protected function getItemId(array $record) + { + return 'CZE:UPM.' . str($record['ID']) + ->explode('_') + ->transform(fn ($part) => str($part) + ->replaceMatches('/\W/', '-') + ->trim('-') + ) + ->join('_'); + } + + protected function getItemImageFilenameFormat(array $record): string + { + return str($record['ID']) + ->explode('_') + ->transform(fn ($part) => '0*' . preg_quote($part)) + ->join('_') . '(_.*)?'; + } + + protected function hydrateAuthor(array $record): string + { + $authors = str($record['Autor']); + if ($authors->isEmpty()) { + return 'Neznámý autor'; + } + + return $authors + ->split('/\s*;\s*/') + ->map(function (string $author) { + preg_match('/^(?[^–]*)(\s–\s(?.*))?$/', $author, $matches); + + if (!isset($matches['name'], $matches['role'])) { + return $author; + } + + return sprintf('%s (%s)', formatName($matches['name']), $matches['role']); + }) + ->join('; '); + } + + protected function hydratePlace(array $record, string $locale): ?string + { + if (!in_array($locale, ['cs', 'sk'])) { + return null; + } + + $place = str($record['Vznik'])->match('/^([^;]+)/'); + return $place->isNotEmpty() ? $place->toString() : null; + } + + protected function hydrateAdditionals(array $record, string $locale): ?array + { + if ($locale !== 'cs') { + return null; + } + + $additionals = []; + + if ($record['Způsob akvizice'] !== null) { + $additionals['acquisition'] = $record['Způsob akvizice']; + } + + if ($record['Výstava'] !== null) { + $additionals['exhibition'] = $record['Výstava']; + } + + $producer = str($record['Vznik'])->match('/;(.+)/'); + if ($producer->isNotEmpty()) { + $additionals['producer'] = $producer->toString(); + } + + return $additionals ?: null; + } + + protected function hydrateMeasurement(array $record, $locale): ?string + { + if (empty($record['Rozměry'])) { + return null; + } + + $replacements = trans('item.measurement_replacements', [], $locale); + return strtr($record['Rozměry'], $replacements); + } +} \ No newline at end of file diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 78b93ca72..037ceb127 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -19,6 +19,7 @@ public function run() $this->call(CollectionsTableSeeder::class); $this->call(CategoriesTableSeeder::class); $this->call(ArticlesTableSeeder::class); + $this->call(ImportsTableSeeder::class); // $this->call(SketchbooksTableSeeder::class); } diff --git a/database/seeders/ImportsTableSeeder.php b/database/seeders/ImportsTableSeeder.php new file mode 100644 index 000000000..f0bbc26c0 --- /dev/null +++ b/database/seeders/ImportsTableSeeder.php @@ -0,0 +1,21 @@ + 'UPM', + 'dir_path' => 'UPM', + 'iip_dir_path' => 'UPM', + 'class_name' => UpmImporter::class, + 'disk' => 'import_iip', + ]); + } +} \ No newline at end of file diff --git a/lang/cs/item.php b/lang/cs/item.php index 22b433810..f0c14ec46 100644 --- a/lang/cs/item.php +++ b/lang/cs/item.php @@ -108,36 +108,35 @@ ], ], 'measurement_replacements' => [ - 'a' => 'výška hlavní části', - 'a.' => 'výška hlavní části', - 'b' => 'výška vedlejší části', - 'b.' => 'výška vedlejší části', - 'čas' => 'čas', - 'd' => 'délka', - 'd.' => 'délka', - 'h' => 'hloubka/tloušťka', - 'h.' => 'hloubka/tloušťka', - 'hmot' => 'hmotnost', - 'hmot.' => 'hmotnost', - 'hr' => 'hloubka s rámem', - 'jiný' => 'jiný nespecifikovaný', - 'p' => 'průměr/ráže', - 'p.' => 'průměr/ráže', - 'r.' => 'ráže', - 'ryz' => 'ryzost', - 's' => 'šířka', - 's.' => 'šířka', - 'sd.' => 'šířka grafické desky', - 'sp' => 'šířka s paspartou', - 'sp.' => 'šířka s paspartou', - 'sr' => 'šířka s rámem', - 'v' => 'celková výška/délka', - 'v.' => 'celková výška/délka', - 'vd.' => 'výška grafické desky', - 'vp' => 'výška s paspartou', - 'vp.' => 'výška s paspartou', - 'vr' => 'výška s rámem', - '=' => ' ', + 'a=' => 'výška hlavní části ', + 'a.=' => 'výška hlavní části ', + 'b=' => 'výška vedlejší části ', + 'b.=' => 'výška vedlejší části ', + 'čas=' => 'čas ', + 'd=' => 'délka ', + 'd.=' => 'délka ', + 'h=' => 'hloubka/tloušťka ', + 'h.=' => 'hloubka/tloušťka ', + 'hmot=' => 'hmotnost ', + 'hmot.=' => 'hmotnost ', + 'hr=' => 'hloubka s rámem ', + 'jiný=' => 'jiný nespecifikovaný ', + 'p=' => 'průměr/ráže ', + 'p.=' => 'průměr/ráže ', + 'r.=' => 'ráže ', + 'ryz=' => 'ryzost ', + 's=' => 'šířka ', + 's.=' => 'šířka ', + 'sd.=' => 'šířka grafické desky ', + 'sp=' => 'šířka s paspartou ', + 'sp.=' => 'šířka s paspartou ', + 'sr=' => 'šířka s rámem ', + 'v=' => 'celková výška/délka ', + 'v.=' => 'celková výška/délka ', + 'vd.=' => 'výška grafické desky ', + 'vp=' => 'výška s paspartou ', + 'vp.=' => 'výška s paspartou ', + 'vr=' => 'výška s rámem ', ], 'untitled' => 'bez názvu', 'authority_roles' => [ diff --git a/lang/en/item.php b/lang/en/item.php index 486ab7b7a..ff5404e59 100644 --- a/lang/en/item.php +++ b/lang/en/item.php @@ -105,36 +105,35 @@ ], ], 'measurement_replacements' => [ - 'a' => 'height of the main part', - 'a.' => 'height of the main part', - 'b' => 'height of the secondary part', - 'b.' => 'height of the secondary part', - 'čas' => 'time', - 'd' => 'length', - 'd.' => 'length', - 'h' => 'depth/thickness', - 'h.' => 'depth/thickness', - 'hmot' => 'mass', - 'hmot.' => 'mass', - 'hr' => 'depth with frame', - 'jiný' => 'other, unspecified', - 'p' => 'diameter, calibre/gauge', - 'p.' => 'diameter, calibre/gauge', - 'r.' => 'calibre/gauge', - 'ryz' => 'purity', - 's' => 'width', - 's.' => 'width', - 'sd.' => 'width of the printing plate', - 'sp' => 'width with mount', - 'sp.' => 'width with mount', - 'sr' => 'width with frame', - 'v' => 'overall height/length', - 'v.' => 'overall height/length', - 'vd.' => 'height of the printing plate', - 'vp' => 'height with mount', - 'vp.' => 'height with mount', - 'vr' => 'height with frame', - '=' => ' ', + 'a=' => 'height of the main part ', + 'a.=' => 'height of the main part ', + 'b=' => 'height of the secondary part ', + 'b.=' => 'height of the secondary part ', + 'čas=' => 'time ', + 'd=' => 'length ', + 'd.=' => 'length ', + 'h=' => 'depth/thickness ', + 'h.=' => 'depth/thickness ', + 'hmot=' => 'mass ', + 'hmot.=' => 'mass ', + 'hr=' => 'depth with frame ', + 'jiný=' => 'other, unspecified ', + 'p=' => 'diameter, calibre/gauge ', + 'p.=' => 'diameter, calibre/gauge ', + 'r.=' => 'calibre/gauge ', + 'ryz=' => 'purity ', + 's=' => 'width ', + 's.=' => 'width ', + 'sd.=' => 'width of the printing plate ', + 'sp=' => 'width with mount ', + 'sp.=' => 'width with mount ', + 'sr=' => 'width with frame ', + 'v=' => 'overall height/length ', + 'v.=' => 'overall height/length ', + 'vd.=' => 'height of the printing plate ', + 'vp=' => 'height with mount ', + 'vp.=' => 'height with mount ', + 'vr=' => 'height with frame ', ], 'untitled' => 'untitled', 'authority_roles' => [ diff --git a/lang/sk/item.php b/lang/sk/item.php index f15b18ba6..ae0634767 100644 --- a/lang/sk/item.php +++ b/lang/sk/item.php @@ -105,36 +105,35 @@ ], ], 'measurement_replacements' => [ - 'a' => 'výška hlavnej časti', - 'a.' => 'výška hlavnej časti', - 'b' => 'výška vedľajšej časti', - 'b.' => 'výška vedľajšej časti', - 'čas' => 'čas', - 'd' => 'dĺžka', - 'd.' => 'dĺžka', - 'h' => 'hĺbka/hrúbka', - 'h.' => 'hĺbka/hrúbka', - 'hmot' => 'hmotnosť', - 'hmot.' => 'hmotnosť', - 'hr' => 'hĺbka s rámom', - 'jiný' => 'nešpecifikované', - 'p' => 'priemer', - 'p.' => 'priemer', - 'r.' => 'ráž', - 'ryz' => 'rýdzosť', - 's' => 'šírka', - 's.' => 'šírka', - 'sd.' => 'šírka grafickej plochy', - 'sp' => 'šírka s paspartou', - 'sp.' => 'šírka s paspartou', - 'sr' => 'šírka s rámom', - 'v' => 'celková výška/dĺžka', - 'v.' => 'celková výška/dĺžka', - 'vd.' => 'výška grafickej dosky', - 'vp' => 'výška s paspartou', - 'vp.' => 'výška s paspartou', - 'vr' => 'výška s rámom', - '=' => ' ', + 'a=' => 'výška hlavnej časti ', + 'a.=' => 'výška hlavnej časti ', + 'b=' => 'výška vedľajšej časti ', + 'b.=' => 'výška vedľajšej časti ', + 'čas=' => 'čas ', + 'd=' => 'dĺžka ', + 'd.=' => 'dĺžka ', + 'h=' => 'hĺbka/hrúbka ', + 'h.=' => 'hĺbka/hrúbka ', + 'hmot=' => 'hmotnosť ', + 'hmot.=' => 'hmotnosť ', + 'hr=' => 'hĺbka s rámom' , + 'jiný=' => 'nešpecifikované ', + 'p=' => 'priemer ', + 'p.=' => 'priemer ', + 'r.=' => 'ráž ', + 'ryz=' => 'rýdzosť ', + 's=' => 'šírka ', + 's.=' => 'šírka ', + 'sd.=' => 'šírka grafickej plochy ', + 'sp=' => 'šírka s paspartou ', + 'sp.=' => 'šírka s paspartou ', + 'sr=' => 'šírka s rámom ', + 'v=' => 'celková výška/dĺžka ', + 'v.=' => 'celková výška/dĺžka ', + 'vd.=' => 'výška grafickej dosky ', + 'vp=' => 'výška s paspartou ', + 'vp.=' => 'výška s paspartou ', + 'vr=' => 'výška s rámom ', ], 'untitled' => 'bez názvu', 'authority_roles' => [ diff --git a/tests/Importers/UpmImporterTest.php b/tests/Importers/UpmImporterTest.php new file mode 100644 index 000000000..ca3a88da9 --- /dev/null +++ b/tests/Importers/UpmImporterTest.php @@ -0,0 +1,113 @@ +repositoryMock = $this->createMock(CsvRepository::class); + $this->importer = new UpmImporter( + app(AuthorityMatcher::class), + $this->repositoryMock, + app(Translator::class) + ); + } + + public function testImport() + { + $this->importData(); + + $item = Item::find('CZE:UPM.GK_11090'); + + $this->assertEquals('GK 11090/E', $item->identifier); + $this->assertEquals('Luboš Kopáč (návrh vazby)', $item->author); + $this->assertEquals(1928, $item->date_earliest); + $this->assertEquals(1928, $item->date_latest); + $this->assertEquals('1986', $item->acquisition_date); + $this->assertEquals('Vazba knihy', $item->translate('sk')->title); + $this->assertEquals('Vazba knihy', $item->translate('cs')->title); + $this->assertEquals('Binding design', $item->translate('en')->title); + $this->assertEquals('celková výška/dĺžka 16,5cm (konvice čajová s víčkem větší); celková výška/dĺžka 13,5-14cm (konvice čajová s víčkem menší)', $item->translate('sk')->measurement); + $this->assertEquals('celková výška/délka 16,5cm (konvice čajová s víčkem větší); celková výška/délka 13,5-14cm (konvice čajová s víčkem menší)', $item->translate('cs')->measurement); + $this->assertEquals('overall height/length 16,5cm (konvice čajová s víčkem větší); overall height/length 13,5-14cm (konvice čajová s víčkem menší)', $item->translate('en')->measurement); + $this->assertEquals('zo súboru', $item->translate('sk')->relationship_type); + $this->assertEquals('ze souboru', $item->translate('cs')->relationship_type); + $this->assertEquals('collection', $item->translate('en')->relationship_type); + $this->assertEquals('Sbírka užité grafiky', $item->translate('cs')->related_work); + $this->assertEquals('užité umění;grafický design', $item->translate('cs')->work_type); // todo translate + $this->assertEquals('celokožená vazba, zlacení', $item->translate('cs')->technique); // todo translate + $this->assertEquals('kniha', $item->translate('cs')->object_type); // todo translate + $this->assertEquals('kůže;papír', $item->translate('cs')->medium); // todo translate + $this->assertEquals('ornament', $item->translate('cs')->topic); // todo translate + $this->assertEquals('1928', $item->translate('cs')->dating); + $this->assertEquals('Praha', $item->translate('cs')->place); + $this->assertEquals('Rösller', $item->translate('cs')->inscription); + $this->assertEquals('VŠUP atelier V.H.Brunnera (vazba)', $item->translate('cs')->additionals['producer']); + $this->assertEquals('převod', $item->translate('cs')->additionals['acquisition']); + $this->assertEquals('Japonsko design, 2019-2020', $item->translate('cs')->additionals['exhibition']); + } + + private function importData(array $data = []): ImportRecord + { + $data = $this->fakeData($data); + + $this->repositoryMock->method('getFiltered')->willReturn(new \ArrayIterator([$data])); + + $importRecord = ImportRecord::factory() + ->for(Import::factory()) + ->create(); + $this->importer->import($importRecord, stream: null); + return $importRecord; + } + + private function fakeData(array $overrides = []): array + { + return $overrides + [ + "Inventárníčíslo" => "GK 11090/E", + "ID" => "GK_11090", + "Název" => "Vazba knihy", + "Název EN" => "Binding design", + "Autor" => "Kopáč, Luboš – návrh vazby", + "Vznik" => "Praha;VŠUP atelier V.H.Brunnera (vazba)", + "Datace" => "1928", + "Od" => "1928", + "Do" => "1928", + "Výtvarný druh" => "užité umění;grafický design", + "Typ" => "kniha", + "Materiál" => "kůže;papír", + "Technika" => "celokožená vazba, zlacení", + "Rozměry" => "v=16,5cm (konvice čajová s víčkem větší); v=13,5-14cm (konvice čajová s víčkem menší)", + "Námět" => "ornament", + "tagy" => "", + "Značení" => "Rösller", + "Způsob akvizice" => "převod", + "Datum akvizice" => "1986", + "Výstava" => "Japonsko design, 2019-2020", + "Publikovat" => "Y", + "Sbírka" => "Sbírka užité grafiky", + "" => "Kolbersb", + ]; + } +} \ No newline at end of file From 2400f62899a991cf3d364ac6991aac4478663f31 Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 13 Dec 2024 15:12:35 +0700 Subject: [PATCH 02/13] [import] Change item title type to text --- ...0914_expand_title_in_item_translations.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 database/migrations/2024_12_13_090914_expand_title_in_item_translations.php diff --git a/database/migrations/2024_12_13_090914_expand_title_in_item_translations.php b/database/migrations/2024_12_13_090914_expand_title_in_item_translations.php new file mode 100644 index 000000000..dce2d5baa --- /dev/null +++ b/database/migrations/2024_12_13_090914_expand_title_in_item_translations.php @@ -0,0 +1,28 @@ +string('title', 512)->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('item_translations', function (Blueprint $table) { + $table->string('title')->change(); + }); + } +}; From dbc18c31f9a9d20f9400977b5e33ea6cbcb1be7a Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 13 Dec 2024 15:28:38 +0700 Subject: [PATCH 03/13] [import] Run tests without indexing --- tests/Importers/GmuRnlImporterTest.php | 3 ++- tests/Importers/OglImporterTest.php | 3 ++- tests/Importers/PnpImporterTest.php | 3 ++- tests/Importers/PnpKarasekImporterTest.php | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/Importers/GmuRnlImporterTest.php b/tests/Importers/GmuRnlImporterTest.php index 35861ea86..083f703da 100644 --- a/tests/Importers/GmuRnlImporterTest.php +++ b/tests/Importers/GmuRnlImporterTest.php @@ -9,10 +9,11 @@ use Illuminate\Contracts\Translation\Translator; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; +use Tests\WithoutSearchIndexing; class GmuRnlImporterTest extends TestCase { - use RefreshDatabase; + use RefreshDatabase, WithoutSearchIndexing; public function testImport() { diff --git a/tests/Importers/OglImporterTest.php b/tests/Importers/OglImporterTest.php index e56e11158..b13e0ec4a 100644 --- a/tests/Importers/OglImporterTest.php +++ b/tests/Importers/OglImporterTest.php @@ -9,10 +9,11 @@ use Illuminate\Contracts\Translation\Translator; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; +use Tests\WithoutSearchIndexing; class OglImporterTest extends TestCase { - use RefreshDatabase; + use RefreshDatabase, WithoutSearchIndexing; public function testId() { diff --git a/tests/Importers/PnpImporterTest.php b/tests/Importers/PnpImporterTest.php index 816785936..97f178172 100644 --- a/tests/Importers/PnpImporterTest.php +++ b/tests/Importers/PnpImporterTest.php @@ -9,10 +9,11 @@ use Illuminate\Contracts\Translation\Translator; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; +use Tests\WithoutSearchIndexing; class PnpImporterTest extends TestCase { - use RefreshDatabase; + use RefreshDatabase, WithoutSearchIndexing; public function testId() { diff --git a/tests/Importers/PnpKarasekImporterTest.php b/tests/Importers/PnpKarasekImporterTest.php index 4dbc43bfc..25aa98542 100644 --- a/tests/Importers/PnpKarasekImporterTest.php +++ b/tests/Importers/PnpKarasekImporterTest.php @@ -9,10 +9,11 @@ use Illuminate\Contracts\Translation\Translator; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; +use Tests\WithoutSearchIndexing; class PnpKarasekImporterTest extends TestCase { - use RefreshDatabase; + use RefreshDatabase, WithoutSearchIndexing; public function testId() { From d3615db9721cecd7fd2614aa639ba62202474afd Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 13 Dec 2024 16:08:25 +0700 Subject: [PATCH 04/13] [import] Fix comma in role --- app/Helpers/general.php | 2 +- app/Importers/UpmImporter.php | 2 +- tests/Importers/UpmImporterTest.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Helpers/general.php b/app/Helpers/general.php index 12e7ad3f3..8d5c6ea02 100644 --- a/app/Helpers/general.php +++ b/app/Helpers/general.php @@ -325,7 +325,7 @@ function convertEmptyStringsToNull($array) { } function formatName($name) { - return preg_replace('/^([^,]*),\s*(.*)$/', '$2 $1', $name); + return preg_replace('/^([^,–]*),\s*(.*)$/', '$2 $1', $name); } function starts_with_upper($str) { diff --git a/app/Importers/UpmImporter.php b/app/Importers/UpmImporter.php index 756c6d7b7..392d25578 100644 --- a/app/Importers/UpmImporter.php +++ b/app/Importers/UpmImporter.php @@ -93,7 +93,7 @@ protected function hydrateAuthor(array $record): string return $author; } - return sprintf('%s (%s)', formatName($matches['name']), $matches['role']); + return sprintf('%s – %s', formatName($matches['name']), $matches['role']); }) ->join('; '); } diff --git a/tests/Importers/UpmImporterTest.php b/tests/Importers/UpmImporterTest.php index ca3a88da9..35357c326 100644 --- a/tests/Importers/UpmImporterTest.php +++ b/tests/Importers/UpmImporterTest.php @@ -42,7 +42,7 @@ public function testImport() $item = Item::find('CZE:UPM.GK_11090'); $this->assertEquals('GK 11090/E', $item->identifier); - $this->assertEquals('Luboš Kopáč (návrh vazby)', $item->author); + $this->assertEquals('Jiří Rathouský – grafická úprava, design vazby a přebalu', $item->author); $this->assertEquals(1928, $item->date_earliest); $this->assertEquals(1928, $item->date_latest); $this->assertEquals('1986', $item->acquisition_date); @@ -89,7 +89,7 @@ private function fakeData(array $overrides = []): array "ID" => "GK_11090", "Název" => "Vazba knihy", "Název EN" => "Binding design", - "Autor" => "Kopáč, Luboš – návrh vazby", + "Autor" => "Rathouský, Jiří – grafická úprava, design vazby a přebalu", "Vznik" => "Praha;VŠUP atelier V.H.Brunnera (vazba)", "Datace" => "1928", "Od" => "1928", From a25508089eb4ead895006d10168007993b8f416f Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 13 Dec 2024 16:15:39 +0700 Subject: [PATCH 05/13] [import] Match author role separated by dash --- app/Matchers/AuthorityMatcher.php | 4 ++-- tests/Matchers/AuthorityMatcherTest.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Matchers/AuthorityMatcher.php b/app/Matchers/AuthorityMatcher.php index 58e5e5b68..10b0215b1 100644 --- a/app/Matchers/AuthorityMatcher.php +++ b/app/Matchers/AuthorityMatcher.php @@ -97,14 +97,14 @@ protected function findByFullname($fullname) public static function parse($author) { - if (!preg_match('/^((?.*?)\s*(?\(.*\))?(?\s+-\s+.*)?,\s+)?(?.*?)\s*(?\(.*\)|\/.*)?$/', $author, $matches)) { + if (!preg_match('/^((?.*?)\s*(?\(.*\))?(?\s+[-–]\s+.*)?,\s+)?(?.*?)\s*(?\(.*\)|\/.*)?$/', $author, $matches)) { return null; } return [ 'surname' => $matches['surname'] ?: null, 'alt_surname' => trim($matches['alt_surname'], '()') ?: null, - 'role' => ltrim($matches['role'], ' -') ?: null, + 'role' => ltrim($matches['role'], ' -–') ?: null, 'name' => $matches['name'] ?: null, 'alt_name' => trim($matches['alt_name'] ?? '', '()/') ?: null, ]; diff --git a/tests/Matchers/AuthorityMatcherTest.php b/tests/Matchers/AuthorityMatcherTest.php index 3af7844f1..1490a9db6 100644 --- a/tests/Matchers/AuthorityMatcherTest.php +++ b/tests/Matchers/AuthorityMatcherTest.php @@ -7,10 +7,11 @@ use App\Matchers\AuthorityMatcher; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; +use Tests\WithoutSearchIndexing; class AuthorityMatcherTest extends TestCase { - use RefreshDatabase; + use RefreshDatabase, WithoutSearchIndexing; public function testMatchAll() { From 5b3cde84fb8ba9dd4f2ee767749073c8ec11d9ae Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Sat, 14 Dec 2024 19:39:17 +0700 Subject: [PATCH 06/13] [import] Translate attributes --- app/Importers/UpmImporter.php | 103 +++++++++++++++++++++++++--- app/Item.php | 1 + lang/cs/item.php | 4 ++ lang/en/item.php | 4 ++ lang/sk/item.php | 4 ++ tests/Importers/UpmImporterTest.php | 24 +++++-- 6 files changed, 123 insertions(+), 17 deletions(-) diff --git a/app/Importers/UpmImporter.php b/app/Importers/UpmImporter.php index 392d25578..590bb75b1 100644 --- a/app/Importers/UpmImporter.php +++ b/app/Importers/UpmImporter.php @@ -15,16 +15,6 @@ class UpmImporter extends AbstractImporter 'dating:sk' => 'Datace', 'date_earliest' => 'Od', 'date_latest' => 'Do', - 'work_type:cs' => 'Výtvarný druh', - 'work_type:sk' => 'Výtvarný druh', - 'object_type:cs' => 'Typ', - 'object_type:sk' => 'Typ', - 'medium:cs' => 'Materiál', - 'medium:sk' => 'Materiál', - 'technique:cs' => 'Technika', - 'technique:sk' => 'Technika', - 'topic:cs' => 'Námět', - 'topic:sk' => 'Námět', 'inscription:cs' => 'Značení', 'inscription:sk' => 'Značení', 'related_work:sk' => 'Sbírka', @@ -51,11 +41,24 @@ class UpmImporter extends AbstractImporter 'newline' => "\n", ]; + private array $workTypeTranslationKeys; + private array $techniqueTranslationKeys; + private array $mediumTranslationKeys; + private array $objectTypeTranslationKeys; + private array $topicTranslationKeys; + + protected function init() { $this->sanitizers[] = function ($value) { return empty_to_null(trim($value)); }; + + $this->workTypeTranslationKeys = array_flip(trans('item.work_types', locale: 'cs')); + $this->techniqueTranslationKeys = array_flip(trans('item.techniques', locale: 'cs')); + $this->mediumTranslationKeys = array_flip(trans('item.media', locale: 'cs')); + $this->objectTypeTranslationKeys = array_flip(trans('item.object_types', locale: 'cs')); + $this->topicTranslationKeys = array_flip(trans('item.topics', locale: 'cs')); } protected function getItemId(array $record) @@ -98,6 +101,86 @@ protected function hydrateAuthor(array $record): string ->join('; '); } + protected function hydrateWorkType(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Výtvarný druh']; + } + + return str($record['Výtvarný druh']) + ->split('/\s*;\s*/') + ->map(function (string $workType) use ($locale) { + $key = $this->workTypeTranslationKeys[$workType] ?? null; + return $key ? trans("item.work_types.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateTechnique(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Technika']; + } + + return str($record['Technika']) + ->split('/\s*;\s*/') + ->map(function (string $technique) use ($locale) { + $key = $this->techniqueTranslationKeys[$technique] ?? null; + return $key ? trans("item.techniques.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateMedium(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Materiál']; + } + + return str($record['Materiál']) + ->split('/\s*;\s*/') + ->map(function (string $medium) use ($locale) { + $key = $this->mediumTranslationKeys[$medium] ?? null; + return $key ? trans("item.media.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateObjectType(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Typ']; + } + + return str($record['Typ']) + ->split('/\s*;\s*/') + ->map(function (string $objectType) use ($locale) { + $key = $this->objectTypeTranslationKeys[$objectType] ?? null; + return $key ? trans("item.object_types.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateTopic(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Námět']; + } + + return str($record['Námět']) + ->split('/\s*;\s*/') + ->map(function (string $topic) use ($locale) { + $key = $this->topicTranslationKeys[$topic] ?? null; + return $key ? trans("item.topics.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + protected function hydratePlace(array $record, string $locale): ?string { if (!in_array($locale, ['cs', 'sk'])) { diff --git a/app/Item.php b/app/Item.php index b77eb6231..1865fd875 100644 --- a/app/Item.php +++ b/app/Item.php @@ -108,6 +108,7 @@ class Item extends Model implements IndexableModel, TranslatableContract 'exhibition', 'box', 'location', + 'object_type', ]; public static $rules = array( diff --git a/lang/cs/item.php b/lang/cs/item.php index f0c14ec46..be8ea2903 100644 --- a/lang/cs/item.php +++ b/lang/cs/item.php @@ -294,8 +294,12 @@ 'zväčšovanie' => 'zvětšování', 'čiernobiela fotografia' => 'černobílá fotografie', ], + 'object_types' => [ + 'kniha' => 'kniha', + ], 'topics' => [ 'figurálna kompozícia' => 'figurální kompozice', + 'ornament' => 'ornament', ], 'state_editions' => [ 'autorizovaný pozitív' => 'autorizovaný pozitiv', diff --git a/lang/en/item.php b/lang/en/item.php index ff5404e59..a09ecee7b 100644 --- a/lang/en/item.php +++ b/lang/en/item.php @@ -291,8 +291,12 @@ 'zväčšovanie' => 'enlarging', 'čiernobiela fotografia' => 'black-and-white photograph', ], + 'object_types' => [ + 'kniha' => 'book', + ], 'topics' => [ 'figurálna kompozícia' => 'figurative composition', + 'ornament' => 'ornament', ], 'state_editions' => [ 'autorizovaný pozitív' => 'authorized photographic print', diff --git a/lang/sk/item.php b/lang/sk/item.php index ae0634767..09bd12a05 100644 --- a/lang/sk/item.php +++ b/lang/sk/item.php @@ -291,8 +291,12 @@ 'zväčšovanie' => 'zväčšovanie', 'čiernobiela fotografia' => 'čiernobiela fotografia', ], + 'object_types' => [ + 'kniha' => 'kniha', + ], 'topics' => [ 'figurálna kompozícia' => 'figurálna kompozícia', + 'ornament' => 'ornament', ], 'state_editions' => [ 'autorizovaný pozitív' => 'autorizovaný pozitív', diff --git a/tests/Importers/UpmImporterTest.php b/tests/Importers/UpmImporterTest.php index 35357c326..358a904ac 100644 --- a/tests/Importers/UpmImporterTest.php +++ b/tests/Importers/UpmImporterTest.php @@ -56,11 +56,21 @@ public function testImport() $this->assertEquals('ze souboru', $item->translate('cs')->relationship_type); $this->assertEquals('collection', $item->translate('en')->relationship_type); $this->assertEquals('Sbírka užité grafiky', $item->translate('cs')->related_work); - $this->assertEquals('užité umění;grafický design', $item->translate('cs')->work_type); // todo translate - $this->assertEquals('celokožená vazba, zlacení', $item->translate('cs')->technique); // todo translate - $this->assertEquals('kniha', $item->translate('cs')->object_type); // todo translate - $this->assertEquals('kůže;papír', $item->translate('cs')->medium); // todo translate - $this->assertEquals('ornament', $item->translate('cs')->topic); // todo translate + $this->assertEquals('úžitkové umenie; grafický dizajn', $item->translate('sk')->work_type); + $this->assertEquals('užité umění;grafický design', $item->translate('cs')->work_type); + $this->assertEquals('applied arts; graphic design', $item->translate('en')->work_type); + $this->assertEquals('kresba', $item->translate('sk')->technique); + $this->assertEquals('kresba', $item->translate('cs')->technique); + $this->assertEquals('drawing', $item->translate('en')->technique); + $this->assertEquals('kniha', $item->translate('sk')->object_type); + $this->assertEquals('kniha', $item->translate('cs')->object_type); + $this->assertEquals('book', $item->translate('en')->object_type); + $this->assertEquals('papier', $item->translate('sk')->medium); + $this->assertEquals('papír', $item->translate('cs')->medium); + $this->assertEquals('paper', $item->translate('en')->medium); + $this->assertEquals('ornament', $item->translate('sk')->topic); + $this->assertEquals('ornament', $item->translate('cs')->topic); + $this->assertEquals('ornament', $item->translate('en')->topic); $this->assertEquals('1928', $item->translate('cs')->dating); $this->assertEquals('Praha', $item->translate('cs')->place); $this->assertEquals('Rösller', $item->translate('cs')->inscription); @@ -96,8 +106,8 @@ private function fakeData(array $overrides = []): array "Do" => "1928", "Výtvarný druh" => "užité umění;grafický design", "Typ" => "kniha", - "Materiál" => "kůže;papír", - "Technika" => "celokožená vazba, zlacení", + "Materiál" => "papír", + "Technika" => "kresba", "Rozměry" => "v=16,5cm (konvice čajová s víčkem větší); v=13,5-14cm (konvice čajová s víčkem menší)", "Námět" => "ornament", "tagy" => "", From f0c259e10c169ef5ab4243bf36ab50eaddb2f79f Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Sat, 14 Dec 2024 19:42:23 +0700 Subject: [PATCH 07/13] [item] Add command for dumping untranslated attributes --- .../Commands/DumpUntranslatedAttributes.php | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 app/Console/Commands/DumpUntranslatedAttributes.php diff --git a/app/Console/Commands/DumpUntranslatedAttributes.php b/app/Console/Commands/DumpUntranslatedAttributes.php new file mode 100644 index 000000000..4d93581b4 --- /dev/null +++ b/app/Console/Commands/DumpUntranslatedAttributes.php @@ -0,0 +1,59 @@ + 'item.work_types', + 'technique' => 'item.techniques', + 'medium' => 'item.media', + 'object_type' => 'item.object_types', + 'topic' => 'item.topics', + ]; + + public function handle(): int + { + $attribute = $this->choice('Select attribute', array_keys($this->attributes)); + $locale = $this->choice('Select locale', config('translatable.locales')); + $prefix = $this->option('prefix'); + + $rows = $this->getUntranslatedAttributes($attribute, $locale, $prefix) + ->map(fn ($count, $value) => [$value, $count]); + + $header = sprintf('%s (%s)', Str::ucfirst(trans("item.$attribute")), Str::upper($locale)); + $this->table([$header, 'Count'], $rows); + + return self::SUCCESS; + } + + private function getUntranslatedAttributes(string $attribute, string $locale, ?string $prefix): LazyCollection + { + $translations = trans($this->attributes[$attribute], locale: $locale); + + return $this->getValuesWithCounts($attribute, $locale, $prefix) + ->reject(fn ($count, $value) => in_array($value, $translations)) + ->sortDesc(); + } + + private function getValuesWithCounts(string $attribute, string $locale, ?string $prefix): LazyCollection + { + return ItemTranslation::query() + ->select($attribute) + ->where('locale', $locale) + ->when($prefix, fn ($query) => $query->where('item_id', 'like', "$prefix%")) + ->lazy() + ->pluck($attribute) + ->flatMap(fn ($value) => str($value)->split('/\s*;\s*/')) + ->filter() + ->countBy(); + } +} \ No newline at end of file From c0764471528f808ee19f40bcf8eeb3c9d95ca4fa Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Sat, 14 Dec 2024 23:50:02 +0700 Subject: [PATCH 08/13] [item] Allow output of untranslated attributes to csv file --- .../Commands/DumpUntranslatedAttributes.php | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/Console/Commands/DumpUntranslatedAttributes.php b/app/Console/Commands/DumpUntranslatedAttributes.php index 4d93581b4..065102381 100644 --- a/app/Console/Commands/DumpUntranslatedAttributes.php +++ b/app/Console/Commands/DumpUntranslatedAttributes.php @@ -6,11 +6,13 @@ use Illuminate\Console\Command; use Illuminate\Support\LazyCollection; use Illuminate\Support\Str; +use League\Csv\Writer; class DumpUntranslatedAttributes extends Command { protected $signature = 'items:dump-untranslated-attributes - {--prefix= : Filter by prefix}'; + {--prefix= : Filter by prefix} + {--output= : Output to CSV file}'; private array $attributes = [ 'work_type' => 'item.work_types', @@ -25,12 +27,25 @@ public function handle(): int $attribute = $this->choice('Select attribute', array_keys($this->attributes)); $locale = $this->choice('Select locale', config('translatable.locales')); $prefix = $this->option('prefix'); + $output = $this->option('output'); $rows = $this->getUntranslatedAttributes($attribute, $locale, $prefix) ->map(fn ($count, $value) => [$value, $count]); - $header = sprintf('%s (%s)', Str::ucfirst(trans("item.$attribute")), Str::upper($locale)); - $this->table([$header, 'Count'], $rows); + $header = [ + sprintf('%s (%s)', Str::ucfirst(trans("item.$attribute")), Str::upper($locale)), + 'Count', + ]; + + if ($output) { + $writer = Writer::createFromPath($output, 'w+'); + $writer->insertOne($header); + $writer->insertAll($rows); + + $this->info("Data has been exported to $output"); + } else { + $this->table($header, $rows); + } return self::SUCCESS; } From bb89f4691b23bede7cfd4befd2041121491725ba Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Thu, 19 Dec 2024 16:26:32 +0700 Subject: [PATCH 09/13] [import] Add MMP importer --- app/Importers/MmpImporter.php | 148 ++++++++++++++++++++++++++++ tests/Importers/MmpImporterTest.php | 96 ++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 app/Importers/MmpImporter.php create mode 100644 tests/Importers/MmpImporterTest.php diff --git a/app/Importers/MmpImporter.php b/app/Importers/MmpImporter.php new file mode 100644 index 000000000..1397525f5 --- /dev/null +++ b/app/Importers/MmpImporter.php @@ -0,0 +1,148 @@ + 'Inventární číslo', + 'title' => 'Titul', + 'dating' => 'Datace vzniku', + 'inscription' => 'Signatura', + ]; + + protected $defaults = [ + 'gallery:sk' => 'Múzeum Prahy, MMP', + 'gallery:cs' => 'Muzeum Prahy, MMP', + ]; + + private array $workTypeTranslationKeys; + private array $techniqueTranslationKeys; + private array $mediumTranslationKeys; + private array $topicTranslationKeys; + + protected function init(): void + { + $this->sanitizers[] = function ($value) { + return empty_to_null(trim($value)); + }; + + $this->workTypeTranslationKeys = array_flip(trans('item.work_types', locale: 'cs')); + $this->techniqueTranslationKeys = array_flip(trans('item.techniques', locale: 'cs')); + $this->mediumTranslationKeys = array_flip(trans('item.media', locale: 'cs')); + $this->topicTranslationKeys = array_flip(trans('item.topics', locale: 'cs')); + } + + protected function getItemId(array $record): string + { + return str($record['Inventární číslo']) + ->swap([ + ' ' => '_', + '/' => '-', + ]) + ->prepend('CZE:MP.'); + } + + protected function getItemImageFilenameFormat(array $record): string + { + return str($record['Inventární číslo']) + ->replace('/', '_') + ->append('(-.*)?'); + } + + protected function hydrateAuthor(array $record): string + { + if ($record['Autor'] === 'Anonym') { + return 'Neznámy autor'; + } + + return $record['Autor']; + } + + protected function hydrateWorkType(array $record, string $locale): ?string + { + $replacements = [ + 'malba' => 'malířství', + ]; + + return str($record['Výtvarný druh']) + ->split('/\s*;\s*/') + ->map(fn (string $workType) => $replacements[$workType] ?? $workType) + ->when($locale !== 'cs', fn ($workTypes) => $workTypes->map(function (string $workType) use ($locale) { + $key = $this->workTypeTranslationKeys[$workType] ?? null; + return $key ? trans("item.work_types.$key", locale: $locale) : null; + })) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateTechnique(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Technika']; + } + + return str($record['Technika']) + ->split('/\s*;\s*/') + ->map(function (string $technique) use ($locale) { + $key = $this->techniqueTranslationKeys[$technique] ?? null; + return $key ? trans("item.techniques.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateMedium(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Materiál']; + } + + return str($record['Materiál']) + ->split('/\s*;\s*/') + ->map(function (string $medium) use ($locale) { + $key = $this->mediumTranslationKeys[$medium] ?? null; + return $key ? trans("item.media.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateTopic(array $record, string $locale): ?string + { + if ($locale === 'cs') { + return $record['Námět/téma']; + } + + return str($record['Námět/téma']) + ->split('/\s*;\s*/') + ->map(function (string $topic) use ($locale) { + $key = $this->topicTranslationKeys[$topic] ?? null; + return $key ? trans("item.topics.$key", locale: $locale) : null; + }) + ->filter() + ->join('; ') ?: null; + } + + protected function hydrateMeasurement(array $record, $locale): ?string + { + if (empty($record['Rozměr'])) { + return null; + } + + $replacements = trans('item.measurement_replacements', [], $locale); + return strtr($record['Rozměr'], $replacements); + } + + protected function hydrateDateEarliest(array $record): int + { + return Date::createFromFormat('d.m.Y', $record['(n) Datace OD'])->year; + } + + protected function hydrateDateLatest(array $record): int + { + return Date::createFromFormat('d.m.Y', $record['(n) Datace DO'])->year; + } +} \ No newline at end of file diff --git a/tests/Importers/MmpImporterTest.php b/tests/Importers/MmpImporterTest.php new file mode 100644 index 000000000..0279c2709 --- /dev/null +++ b/tests/Importers/MmpImporterTest.php @@ -0,0 +1,96 @@ +repositoryMock = $this->createMock(CsvRepository::class); + $this->importer = new MmpImporter( + app(AuthorityMatcher::class), + $this->repositoryMock, + app(Translator::class) + ); + } + + public function testImport() + { + $this->importData(); + + $item = Item::find('CZE:MP.H_014_487'); + + $this->assertEquals('H 014 487', $item->identifier); + $this->assertEquals('Neznámy autor', $item->author); + $this->assertEquals(1701, $item->date_earliest); + $this->assertEquals(1800, $item->date_latest); + $this->assertEquals('Panna Marie Karlovská', $item->title); + $this->assertEquals('počátek 18.stol.', $item->dating); + $this->assertEquals('maliarstvo', $item->translate('sk')->work_type); + $this->assertEquals('malířství', $item->translate('cs')->work_type); + $this->assertEquals('painting', $item->translate('en')->work_type); + $this->assertEquals('olej', $item->translate('sk')->technique); + $this->assertEquals('olej', $item->translate('cs')->technique); + $this->assertEquals('oil', $item->translate('en')->technique); + $this->assertEquals('drevo', $item->translate('sk')->medium); + $this->assertEquals('dřevo', $item->translate('cs')->medium); + $this->assertEquals('wood', $item->translate('en')->medium); + $this->assertEquals(null, $item->translate('sk')->topic); + $this->assertEquals('obraz náboženský', $item->translate('cs')->topic); + $this->assertEquals(null, $item->translate('en')->topic); + $this->assertEquals('', $item->translate('sk')->measurement); + $this->assertEquals('', $item->translate('cs')->measurement); + $this->assertEquals('', $item->translate('en')->measurement); + } + + private function importData(array $data = []): ImportRecord + { + $data = $this->fakeData($data); + + $this->repositoryMock->method('getFiltered')->willReturn(new \ArrayIterator([$data])); + + $importRecord = ImportRecord::factory() + ->for(Import::factory()) + ->create(); + $this->importer->import($importRecord, stream: null); + return $importRecord; + } + + private function fakeData(array $overrides = []): array + { + return $overrides + [ + "Řada" => "H", + "Inventární číslo" => "H 014 487", + "Titul" => "Panna Marie Karlovská", + "Autor" => "Anonym", + "Datace vzniku" => "počátek 18.stol.", + "(n) Datace OD" => "1.1.1701", + "(n) Datace DO" => "31.12.1800", + "Výtvarný druh" => "malba", + "Materiál" => "dřevo", + "Technika" => "olej", + "Rozměr" => "rv.=31cm; rš.=21,5cm; v-cm=24,5cm; š-cm=14,5cm", + "Námět/téma" => "obraz náboženský", + "Signatura" => "", + ]; + } +} \ No newline at end of file From b75efd937734b04bae6d594d5258a280e283410a Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 20 Dec 2024 10:48:55 +0700 Subject: [PATCH 10/13] [import] fix spaces in webdav paths --- app/Filesystem/WebDAVAdapter.php | 18 ++++++++++++++++++ app/Providers/AppServiceProvider.php | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 app/Filesystem/WebDAVAdapter.php diff --git a/app/Filesystem/WebDAVAdapter.php b/app/Filesystem/WebDAVAdapter.php new file mode 100644 index 000000000..c0be9fd66 --- /dev/null +++ b/app/Filesystem/WebDAVAdapter.php @@ -0,0 +1,18 @@ +encodePath($path); + return parent::lastModified($path); + } +} \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 243d63348..e58cfe713 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,5 +1,6 @@ Date: Fri, 20 Dec 2024 15:27:54 +0700 Subject: [PATCH 11/13] [import] accept jpf files --- app/Importers/AbstractImporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Importers/AbstractImporter.php b/app/Importers/AbstractImporter.php index b46230fa6..49a4def53 100644 --- a/app/Importers/AbstractImporter.php +++ b/app/Importers/AbstractImporter.php @@ -263,7 +263,7 @@ protected function getJp2Files( return $this->iipFilesMap[$import_record] ->filter( fn(SplFileInfo $file) => preg_match( - sprintf('#^%s\.jp2$#', $image_filename_format), + sprintf('#^%s\.jp[2f]$#', $image_filename_format), $file->getBasename() ) ) From f4d572ea801a048185c077504936eca285560411 Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 20 Dec 2024 15:37:56 +0700 Subject: [PATCH 12/13] [import] add comma after author's surname --- app/Importers/MmpImporter.php | 4 +++- tests/Importers/MmpImporterTest.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Importers/MmpImporter.php b/app/Importers/MmpImporter.php index 1397525f5..88ce653d0 100644 --- a/app/Importers/MmpImporter.php +++ b/app/Importers/MmpImporter.php @@ -58,7 +58,9 @@ protected function hydrateAuthor(array $record): string return 'Neznámy autor'; } - return $record['Autor']; + return str($record['Autor']) + ->trim() + ->replaceMatches('/(.*?) /', '$1, ', 1); } protected function hydrateWorkType(array $record, string $locale): ?string diff --git a/tests/Importers/MmpImporterTest.php b/tests/Importers/MmpImporterTest.php index 0279c2709..129310ace 100644 --- a/tests/Importers/MmpImporterTest.php +++ b/tests/Importers/MmpImporterTest.php @@ -40,7 +40,7 @@ public function testImport() $item = Item::find('CZE:MP.H_014_487'); $this->assertEquals('H 014 487', $item->identifier); - $this->assertEquals('Neznámy autor', $item->author); + $this->assertEquals('Beisch, Josef Antonín', $item->author); $this->assertEquals(1701, $item->date_earliest); $this->assertEquals(1800, $item->date_latest); $this->assertEquals('Panna Marie Karlovská', $item->title); @@ -81,7 +81,7 @@ private function fakeData(array $overrides = []): array "Řada" => "H", "Inventární číslo" => "H 014 487", "Titul" => "Panna Marie Karlovská", - "Autor" => "Anonym", + "Autor" => "Beisch Josef Antonín", "Datace vzniku" => "počátek 18.stol.", "(n) Datace OD" => "1.1.1701", "(n) Datace DO" => "31.12.1800", From 19a6c4b9f4952e51246a24cfbf35da752a1ffb9a Mon Sep 17 00:00:00 2001 From: Rastislav Chynoransky Date: Fri, 20 Dec 2024 16:11:19 +0700 Subject: [PATCH 13/13] [import] add measurement replacements --- lang/cs/item.php | 4 ++++ lang/en/item.php | 4 ++++ lang/sk/item.php | 4 ++++ tests/Importers/MmpImporterTest.php | 6 +++--- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lang/cs/item.php b/lang/cs/item.php index be8ea2903..34df452d5 100644 --- a/lang/cs/item.php +++ b/lang/cs/item.php @@ -137,6 +137,10 @@ 'vp=' => 'výška s paspartou ', 'vp.=' => 'výška s paspartou ', 'vr=' => 'výška s rámem ', + 'rv.=' => 'výška s rámem ', + 'rš.=' => 'šířka s rámem ', + 'v-cm=' => 'výška ', + 'š-cm=' => 'šířka ', ], 'untitled' => 'bez názvu', 'authority_roles' => [ diff --git a/lang/en/item.php b/lang/en/item.php index a09ecee7b..90369c0c6 100644 --- a/lang/en/item.php +++ b/lang/en/item.php @@ -134,6 +134,10 @@ 'vp=' => 'height with mount ', 'vp.=' => 'height with mount ', 'vr=' => 'height with frame ', + 'rv.=' => 'height with frame ', + 'rš.=' => 'width with frame ', + 'v-cm=' => 'height ', + 'š-cm=' => 'width ', ], 'untitled' => 'untitled', 'authority_roles' => [ diff --git a/lang/sk/item.php b/lang/sk/item.php index 09bd12a05..c755e2b3e 100644 --- a/lang/sk/item.php +++ b/lang/sk/item.php @@ -134,6 +134,10 @@ 'vp=' => 'výška s paspartou ', 'vp.=' => 'výška s paspartou ', 'vr=' => 'výška s rámom ', + 'rv.=' => 'výška s rámom ', + 'rš.=' => 'šírka s rámom ', + 'v-cm=' => 'výška ', + 'š-cm=' => 'šírka ', ], 'untitled' => 'bez názvu', 'authority_roles' => [ diff --git a/tests/Importers/MmpImporterTest.php b/tests/Importers/MmpImporterTest.php index 129310ace..8f7fa329e 100644 --- a/tests/Importers/MmpImporterTest.php +++ b/tests/Importers/MmpImporterTest.php @@ -57,9 +57,9 @@ public function testImport() $this->assertEquals(null, $item->translate('sk')->topic); $this->assertEquals('obraz náboženský', $item->translate('cs')->topic); $this->assertEquals(null, $item->translate('en')->topic); - $this->assertEquals('', $item->translate('sk')->measurement); - $this->assertEquals('', $item->translate('cs')->measurement); - $this->assertEquals('', $item->translate('en')->measurement); + $this->assertEquals('výška s rámom 31cm; šírka s rámom 21,5cm; výška 24,5cm; šírka 14,5cm', $item->translate('sk')->measurement); + $this->assertEquals('výška s rámem 31cm; šířka s rámem 21,5cm; výška 24,5cm; šířka 14,5cm', $item->translate('cs')->measurement); + $this->assertEquals('height with frame 31cm; width with frame 21,5cm; height 24,5cm; width 14,5cm', $item->translate('en')->measurement); } private function importData(array $data = []): ImportRecord