Add logic for checking validity of legal status of objects'
representations This is still missing translations. See #2
This commit is contained in:
parent
55dc362cdb
commit
4454217cc0
237
src/Checks/PlausiForLegalStatus/MDPlausiForLegalStatus.php
Normal file
237
src/Checks/PlausiForLegalStatus/MDPlausiForLegalStatus.php
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* This class provides the logic for checking the expected correctness of the
|
||||||
|
* legal status assigned to an object and its representations based on events
|
||||||
|
* linked to the object (date, date of death of creator).
|
||||||
|
*/
|
||||||
|
declare(strict_types = 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the logic for checking the expected correctness of the
|
||||||
|
* legal status assigned to an object and its representations based on events
|
||||||
|
* linked to the object (date, date of death of creator).
|
||||||
|
*/
|
||||||
|
final class MDPlausiForLegalStatus {
|
||||||
|
|
||||||
|
// Mexico has the longest period, under which creators and their
|
||||||
|
// kin have rights to a work. Death + 100 years.
|
||||||
|
const YEARS_AFTER_DEATH_TO_PUBLIC_DOMAIN = 100;
|
||||||
|
|
||||||
|
// "The Berne Convention states that all works except photographic and
|
||||||
|
// cinematographic shall be protected for at least 50 years after the
|
||||||
|
// author's death, but parties are free to provide longer terms"
|
||||||
|
// - https://en.wikipedia.org/wiki/Berne_Convention
|
||||||
|
const YEARS_AFTER_DEATH_TO_PUBLIC_DOMAIN_CERTAIN = 50;
|
||||||
|
|
||||||
|
/** @var array<MDPlausiEvent> */
|
||||||
|
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<string, MDCopyrightCollective> */
|
||||||
|
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<array{name: string, license: string}> $representations Representations of the object.
|
||||||
|
*
|
||||||
|
* @return array{has_warning: bool, msgs: array<array{name: string, license: string, type: string, additional?: array{representation: MDCopyrightCollective}}>}
|
||||||
|
*/
|
||||||
|
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<array{name: string, license: string}> $representations Representations of the object.
|
||||||
|
*
|
||||||
|
* @return array{has_warning: bool, msgs: array<array{name: string, license: string, type: string, text: string}>}
|
||||||
|
*/
|
||||||
|
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<string, MDCopyrightCollective> $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<MDPlausiEvent> $events Events.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(array $events) {
|
||||||
|
|
||||||
|
$this->_events = $events;
|
||||||
|
|
||||||
|
$this->_categorizeEvents();
|
||||||
|
$this->_expected_status = $this->_determineExpectedStatus();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
149
tests/MDPlausiForLegalStatusTest.php
Normal file
149
tests/MDPlausiForLegalStatusTest.php
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Tests for plausi for legal status.
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||||
|
*/
|
||||||
|
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']);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
49
tests/MDPlausiTest.php
Normal file
49
tests/MDPlausiTest.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Tests for plausi.
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@museum-digital.de>
|
||||||
|
*/
|
||||||
|
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());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user