diff --git a/src/Checks/PlausiForLegalStatus/MDPlausiForLegalStatus.php b/src/Checks/PlausiForLegalStatus/MDPlausiForLegalStatus.php new file mode 100644 index 0000000..3e6b4fb --- /dev/null +++ b/src/Checks/PlausiForLegalStatus/MDPlausiForLegalStatus.php @@ -0,0 +1,237 @@ + */ + private array $_events; + + # private string $_latest_production_name; + private int $_latest_production; + private string $_last_creator_name; + private int $_death_of_last_creator; + + /** @var 'any'|'pd'|'restricted' */ + private readonly string $_expected_status; + # /** @var 'actor'|'time' */ + # private string $_expected_status_reason; + + /** @var array */ + private array $_representedByCopyrightCollective = []; + + /** + * Determines the expected legal / licensing status of a representation. + * + * @return 'any'|'pd'|'restricted' + */ + private function _determineExpectedStatus():string { + + $currentYear = (int)date("Y"); + + if (!isset($this->_death_of_last_creator)) { + return 'any'; + } + + if ($currentYear - self::YEARS_AFTER_DEATH_TO_PUBLIC_DOMAIN > $this->_death_of_last_creator) { + return 'pd'; + } + + if ($currentYear - self::YEARS_AFTER_DEATH_TO_PUBLIC_DOMAIN_CERTAIN < $this->_death_of_last_creator) { + return 'restricted'; + } + + return 'any'; + + } + + /** + * Setup function for setting event categories. + * + * @return void + */ + private function _categorizeEvents():void { + + foreach ($this->_events as $event) { + + if ($event->event_category !== MDEventCategory::production) continue; + + if ($event->time_end_normalized !== false + && (!isset($this->_latest_production) || $this->_latest_production < $event->time_end_normalized) + ) { + $this->_latest_production = $event->time_end_normalized; + # $this->_latest_production_name = $event->time_name; + } + if ( + $event->actor_death_normalized !== false + && (!isset($this->_death_of_last_creator) || $this->_death_of_last_creator < $event->actor_death_normalized) + ) { + $this->_death_of_last_creator = $event->actor_death_normalized; + $this->_last_creator_name = $event->actor_name; + # $this->_production->latest_time_name = $event->actor_death; + } + + // Actors who have not yet died + if ( + $event->actor_death_normalized === false + && $event->actor_birth_normalized !== false + && (!isset($this->_death_of_last_creator) || $this->_death_of_last_creator < $event->actor_birth_normalized) + ) { + $this->_death_of_last_creator = $event->actor_birth_normalized; + $this->_last_creator_name = $event->actor_name; + # $this->_production->latest_time_name = $event->actor_death; + } + + } + + $this->_determineExpectedStatus(); + + } + + /** + * Evaluates a range of representations and returns a simple answer without translations. + * For translations, use the wrapper function $this->evaluate(). + * + * @param array $representations Representations of the object. + * + * @return array{has_warning: bool, msgs: array} + */ + public function evaluateSimple(array $representations):array { + + if ($this->_expected_status === 'any') { + return ['has_warning' => false, 'msgs' => []]; + } + + if (isset($this->_representedByCopyrightCollective[strtolower($this->_last_creator_name)])) { + $collective = $this->_representedByCopyrightCollective[strtolower($this->_last_creator_name)]; + } + + $msgs = []; + foreach ($representations as $representation) { + + + if ($this->_expected_status === 'pd' + && $representation['license'] !== 'Public Domain Mark' + ) { + $msgs[] = [ + 'name' => $representation['name'], + 'license' => $representation['license'], + 'type' => 'expect_public_domain', + ]; + } + + else if (# $this->_expected_status === 'closed' && + !in_array($representation['license'], MDPuqi::LICENSES_CLOSED_ACCESS, true) + ) { + + if (!empty($collective)) { + $msgs[] = [ + 'name' => $representation['name'], + 'license' => $representation['license'], + 'type' => 'expect_restricted_legal_status', + 'additional' => [ + 'representation' => $collective + ], + ]; + } + else { + $msgs[] = [ + 'name' => $representation['name'], + 'license' => $representation['license'], + 'type' => 'expect_restricted_legal_status', + ]; + } + } + } + + if (empty($msgs)) $has_warning = false; + else $has_warning = true; + + return ['has_warning' => $has_warning, 'msgs' => $msgs]; + + } + + /** + * Evaluates an object's representations' legal / licensing status based on + * the expected values. + * + * @param MDTlLoader $tlLoader Translation loader. + * @param array $representations Representations of the object. + * + * @return array{has_warning: bool, msgs: array} + */ + public function evaluate(MDTlLoader $tlLoader, array $representations):array { + + $evaluation = $this->evaluateSimple($representations); + if ($evaluation['has_warning'] === false) { + return ['has_warning' => false, 'msgs' => []]; + } + + $output = []; + foreach ($evaluation['msgs'] as $msg) { + + throw new Exception("To be implemented"); + $output[] = [ + 'name' => $msg['name'], + 'license' => $msg['license'], + 'type' => $msg['type'], + ]; + + } + + return ['has_warning' => $evaluation['has_warning'], 'msgs' => $output]; + + } + + /** + * Sets creators represented by a copyright collective. The list of people represented by a + * copyright collective needs to be externally loaded. + * + * @param array $represented List of represented people. + * + * @return void + */ + public function setCreatorsRepresentedByCopyrightCollective(array $represented):void { + + foreach ($represented as $name => $collective) { + $this->_representedByCopyrightCollective[strtolower($name)] = $collective; + } + + } + + /** + * Constructor. + * + * @param array $events Events. + * + * @return void + */ + public function __construct(array $events) { + + $this->_events = $events; + + $this->_categorizeEvents(); + $this->_expected_status = $this->_determineExpectedStatus(); + + } + +} diff --git a/tests/MDPlausiForLegalStatusTest.php b/tests/MDPlausiForLegalStatusTest.php new file mode 100644 index 0000000..5baa051 --- /dev/null +++ b/tests/MDPlausiForLegalStatusTest.php @@ -0,0 +1,149 @@ + + */ +declare(strict_types = 1); + +use PHPUnit\Framework\TestCase; + +require_once __DIR__ . '/../src/Checks/PlausiForLegalStatus/MDPlausiForLegalStatus.php'; +require_once __DIR__ . '/../src/Checks/Puqi/MDPuqi.php'; +require_once __DIR__ . '/../src/Checks/Plausi/MDEventCategory.php'; +require_once __DIR__ . '/../src/Checks/Plausi/MDPlausiEvent.php'; +// require_once __DIR__ . '/../../MDTlLoader/src/MDTlLoader.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/MDRequirementsSet.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/MDValueSet.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/MDEventsSet.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/enums/MDCopyrightCollective.php'; + +/** + * Tests for PlausiForLegalStatus. + */ +final class MDPlausiForLegalStatusTest extends TestCase { + /** + * Ensures that no warning is present if no information has been provided. + * + * @return void + */ + public function testNoWarningForObjectWithNoInfo():void { + + $plausiEvent = new MDPlausiEvent(1, + "", + "", + "", + "", + "", + ""); + + $plausiLegal = new MDPlausiForLegalStatus([$plausiEvent]); + $warningStatus = $plausiLegal->evaluateSimple([['name' => 'test.jpg', 'license' => 'RR-F']]); + + self::assertFalse($warningStatus['has_warning']); + self::assertEmpty($warningStatus['msgs']); + + } + + /** + * Ensures that a warning is returned, if the object's representations are published under + * restrictive licenses Checks the integration / evaluation function. + * + * @return void + */ + public function testPublicDomainObjectExpectsPd():void { + + $plausiEvent = new MDPlausiEvent(1, + "1899", + "1899", + "1899", + "Helmut Meyer", + "1859", + "1900"); + + $plausiLegal = new MDPlausiForLegalStatus([$plausiEvent]); + $warningStatus = $plausiLegal->evaluateSimple([['name' => 'test.jpg', 'license' => 'RR-F']]); + + self::assertTrue($warningStatus['has_warning']); + self::assertNotEmpty($warningStatus['msgs']); + self::assertEquals('expect_public_domain', $warningStatus['msgs'][0]['type']); + + } + + /** + * Ensures that a warning is returned if the author / creator died only in the current year. + * + * @return void + */ + public function testCurrentCreatorAsksForRestrictedLicense():void { + + $plausiEvent = new MDPlausiEvent(1, + date("Y"), + date("Y"), + date("Y"), + "Helmut Meyer", + strval((int)date("Y") - 20), + date("Y")); + + $plausiLegal = new MDPlausiForLegalStatus([$plausiEvent]); + $warningStatus = $plausiLegal->evaluateSimple([['name' => 'test.jpg', 'license' => 'Public Domain Mark']]); + + self::assertTrue($warningStatus['has_warning']); + self::assertNotEmpty($warningStatus['msgs']); + self::assertEquals('expect_restricted_legal_status', $warningStatus['msgs'][0]['type']); + + } + + /** + * Ensures that a warning is returned if the creator is still alive. + * + * @return void + */ + public function testCreatorsWhoAreStillAliveAsksForRestrictedLicense():void { + + $plausiEvent = new MDPlausiEvent(1, + date("Y"), + date("Y"), + date("Y"), + "Helmut Meyer", + strval((int)date("Y") - 20), + ""); + + $plausiLegal = new MDPlausiForLegalStatus([$plausiEvent]); + $warningStatus = $plausiLegal->evaluateSimple([['name' => 'test.jpg', 'license' => 'Public Domain Mark']]); + + self::assertTrue($warningStatus['has_warning'], var_export($plausiLegal, true)); + self::assertNotEmpty($warningStatus['msgs']); + self::assertEquals('expect_restricted_legal_status', $warningStatus['msgs'][0]['type']); + + } + + /** + * Ensures that a warning is returned if the creator is represented by a copyright collective. + * + * @return void + */ + public function testCreatorsInCopyrightCollectiveAsksForRestrictedLicense():void { + + $plausiEvent = new MDPlausiEvent(1, + date("Y"), + date("Y"), + date("Y"), + "Helmut Meyer", + strval((int)date("Y") - 20), + ""); + + $plausiLegal = new MDPlausiForLegalStatus([$plausiEvent]); + $plausiLegal->setCreatorsRepresentedByCopyrightCollective(["Helmut Meyer" => MDCopyrightCollective::vg_bildkunst]); + + $warningStatus = $plausiLegal->evaluateSimple([['name' => 'test.jpg', 'license' => 'Public Domain Mark']]); + + self::assertTrue($warningStatus['has_warning']); + self::assertNotEmpty($warningStatus['msgs']); + self::assertEquals('expect_restricted_legal_status', $warningStatus['msgs'][0]['type']); + + self::assertArrayHasKey('additional', $warningStatus['msgs'][0]); + self::assertEquals(MDCopyrightCollective::vg_bildkunst, $warningStatus['msgs'][0]['additional']['representation']); + + } +} diff --git a/tests/MDPlausiTest.php b/tests/MDPlausiTest.php new file mode 100644 index 0000000..9de19a7 --- /dev/null +++ b/tests/MDPlausiTest.php @@ -0,0 +1,49 @@ + + */ +declare(strict_types = 1); + +use PHPUnit\Framework\TestCase; + +require_once __DIR__ . '/../src/Checks/Plausi/MDPlausi.php'; +require_once __DIR__ . '/../src/Checks/Plausi/MDEventCategory.php'; +require_once __DIR__ . '/../src/Checks/Plausi/MDPlausiEventCategory.php'; +require_once __DIR__ . '/../src/Checks/Plausi/MDPlausiEvent.php'; +require_once __DIR__ . '/../../MDTlLoader/src/MDTlLoader.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/MDRequirementsSet.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/MDValueSet.php'; +require_once __DIR__ . '/../../importer/dependencies/MDAllowedValueSets/src/MDEventsSet.php'; + +/** + * Tests for plausi. + */ +final class MDPlausiTest extends TestCase { + /** + * Ensures that a warning is returned, Checks the integration / evaluation function. + * + * @return void + */ + public function testActorProducingObjectAfterOwnDeathResultsInWarning():void { + + $tlLoader = $this->createMock(MDTlLoader::class); + $tlLoader->method('tl')->willReturn('foo'); + + $plausiEvent = new MDPlausiEvent(1, + "1912", + "1912", + "1912", + "Helmut Meyer", + "1859", + "1900"); + + $plausi = new MDPlausi($tlLoader, [$plausiEvent]); + $plausi->evaluate(); + + self::assertTrue($plausi->getWarningStatus()); + + + } +}