license: built full stack, test and documentation
Some checks failed
docs / build (push) Has been cancelled
docs / deploy (push) Has been cancelled

This commit is contained in:
Giuseppe Naponiello
2026-07-03 12:47:47 +02:00
parent f8206b5840
commit 271acacb1d
39 changed files with 4078 additions and 57 deletions

View File

@@ -0,0 +1,63 @@
<?php
namespace Database\Factories\Lists;
use App\Enums\LicenseKind;
use App\Models\Lists\License;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<License>
*/
class LicenseFactory extends Factory
{
protected $model = License::class;
/**
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => ucfirst(fake()->unique()->words(3, true)),
'acronym' => strtoupper(fake()->unique()->bothify('??-#.#')),
'spdx_id' => null,
'kind' => LicenseKind::License,
'description' => fake()->sentence(),
'uri' => fake()->url(),
'file' => null,
'for_record' => false,
'for_media' => true,
'sort_order' => fake()->numberBetween(0, 100),
'active' => true,
];
}
/**
* Licenza aperta ammessa anche per i record.
*/
public function forRecord(): static
{
return $this->state(fn () => ['for_record' => true]);
}
/**
* Rights statement (nessun testo legale, nessun id SPDX).
*/
public function rightsStatement(): static
{
return $this->state(fn () => [
'kind' => LicenseKind::RightsStatement,
'spdx_id' => null,
'file' => null,
]);
}
/**
* Licenza ritirata dagli admin (esclusa dalle select dei form).
*/
public function inactive(): static
{
return $this->state(fn () => ['active' => false]);
}
}

View File

@@ -0,0 +1,49 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Vocabolario delle licenze applicabili a record (artifact/model) e media.
*
* - `spdx_id`: identificatore SPDX ufficiale, NULL per marchi e rights
* statement (che non stanno nella SPDX License List) mai inventarne.
* - `uri`: URI canonico della licenza (creativecommons.org /
* rightsstatements.org), usato anche nel JSON-LD Linked Art.
* - `file`: nome del testo legale in LICENSES/media/ da includere nello
* zip di download; NULL dove un testo non esiste (mark/statement).
* - `for_record`/`for_media`: scope della licenza, filtrano le select dei
* form (i record ammettono solo licenze aperte, i media tutte).
* - `active`: disattivazione soft da parte degli admin senza rompere le
* FK dei contenuti già licenziati.
*/
public function up(): void
{
Schema::create('licenses', function (Blueprint $table) {
$table->id();
$table->string('name', 200)->unique();
$table->string('acronym', 50)->unique();
$table->string('spdx_id', 50)->nullable()->unique();
$table->string('kind', 20)->default('license');
$table->text('description')->nullable();
$table->string('uri', 2000)->nullable();
$table->string('file', 512)->nullable();
$table->boolean('for_record')->default(false);
$table->boolean('for_media')->default(true);
$table->unsignedInteger('sort_order')->default(0);
$table->boolean('active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('licenses');
}
};

View File

@@ -20,6 +20,7 @@ class DatabaseSeeder extends Seeder
SystemUserSeeder::class,
InstitutionCategorySeeder::class,
UserPositionSeeder::class,
LicenseSeeder::class,
]);
}
}

View File

@@ -0,0 +1,223 @@
<?php
namespace Database\Seeders;
use App\Enums\LicenseKind;
use App\Models\Lists\License;
use Illuminate\Database\Seeder;
/**
* Vocabolario delle licenze. Idempotente, gira in installazione (la tabella
* NON è popolata dall'ETL).
*
* Gli id 1-3 sono FISSI e coincidono con il DB legacy (v1: 1=Public Domain,
* 2=CC0, 3=CC BY) così l'ETL mapperà le FK di artifact/media 1:1.
*
* Set iniziale: famiglia Creative Commons 4.0 + Public Domain Mark + i tre
* rights statement più comuni (InC, InC-EDU, CNE). Gli altri statement di
* RightsStatements.org (InC-NC, NoC-NC, NKC, UND, ...) si aggiungono al
* bisogno dal pannello admin.
*
* `file` è il nome del testo legale in storage/app/public/licenses/ (incluso
* nello zip di download dei media e servito al frontend via storage:link);
* NULL per mark e rights statement, che non hanno un testo legale. I testi CC
* sono dedicati al pubblico dominio da Creative Commons:
* https://creativecommons.org/policies/#license
*/
class LicenseSeeder extends Seeder
{
public function run(): void
{
foreach ($this->licenses() as $id => $license) {
License::updateOrCreate(['id' => $id], $license);
}
}
/**
* @return array<int, array<string, mixed>>
*/
private function licenses(): array
{
return $this->openLicenses() + $this->rightsStatements();
}
/**
* Public Domain Mark + famiglia Creative Commons 4.0.
*
* @return array<int, array<string, mixed>>
*/
private function openLicenses(): array
{
return [
1 => [
'name' => 'Public Domain Mark 1.0',
'acronym' => 'PDM 1.0',
'spdx_id' => null,
'kind' => LicenseKind::Mark,
'description' => 'Marks works that are already free of known copyright worldwide (for '
.'instance because copyright has expired). It is not a license: it declares '
.'an existing status and grants no new permission.',
'uri' => 'https://creativecommons.org/publicdomain/mark/1.0/',
'file' => null,
'for_record' => false,
'for_media' => true,
'sort_order' => 10,
'active' => true,
],
2 => [
'name' => 'CC0 1.0 Universal',
'acronym' => 'CC0 1.0',
'spdx_id' => 'CC0-1.0',
'kind' => LicenseKind::License,
'description' => 'Public domain dedication: the rights holder waives all copyright and '
.'related rights worldwide. The work can be copied, modified and reused for '
.'any purpose, even commercially, without attribution.',
'uri' => 'https://creativecommons.org/publicdomain/zero/1.0/',
'file' => 'CC0-1.0.txt',
'for_record' => true,
'for_media' => true,
'sort_order' => 20,
'active' => true,
],
3 => [
'name' => 'Attribution 4.0 International',
'acronym' => 'CC BY 4.0',
'spdx_id' => 'CC-BY-4.0',
'kind' => LicenseKind::License,
'description' => 'Reuse, redistribution and modification allowed for any purpose, including '
.'commercial, provided that credit is given to the creator.',
'uri' => 'https://creativecommons.org/licenses/by/4.0/',
'file' => 'CC-BY-4.0.txt',
'for_record' => true,
'for_media' => true,
'sort_order' => 30,
'active' => true,
],
4 => [
'name' => 'Attribution-ShareAlike 4.0 International',
'acronym' => 'CC BY-SA 4.0',
'spdx_id' => 'CC-BY-SA-4.0',
'kind' => LicenseKind::License,
'description' => 'Same permissions as CC BY, but derivative works must be distributed under '
.'the same license (share-alike).',
'uri' => 'https://creativecommons.org/licenses/by-sa/4.0/',
'file' => 'CC-BY-SA-4.0.txt',
'for_record' => false,
'for_media' => true,
'sort_order' => 40,
'active' => true,
],
5 => [
'name' => 'Attribution-NonCommercial 4.0 International',
'acronym' => 'CC BY-NC 4.0',
'spdx_id' => 'CC-BY-NC-4.0',
'kind' => LicenseKind::License,
'description' => 'Reuse and modification allowed with attribution, for non-commercial '
.'purposes only.',
'uri' => 'https://creativecommons.org/licenses/by-nc/4.0/',
'file' => 'CC-BY-NC-4.0.txt',
'for_record' => false,
'for_media' => true,
'sort_order' => 50,
'active' => true,
],
6 => [
'name' => 'Attribution-NonCommercial-ShareAlike 4.0 International',
'acronym' => 'CC BY-NC-SA 4.0',
'spdx_id' => 'CC-BY-NC-SA-4.0',
'kind' => LicenseKind::License,
'description' => 'Non-commercial reuse and modification with attribution; derivative works '
.'must keep the same license.',
'uri' => 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
'file' => 'CC-BY-NC-SA-4.0.txt',
'for_record' => false,
'for_media' => true,
'sort_order' => 60,
'active' => true,
],
7 => [
'name' => 'Attribution-NoDerivatives 4.0 International',
'acronym' => 'CC BY-ND 4.0',
'spdx_id' => 'CC-BY-ND-4.0',
'kind' => LicenseKind::License,
'description' => 'Redistribution allowed, even commercially, with attribution, but the work '
.'must remain unmodified: no derivative works.',
'uri' => 'https://creativecommons.org/licenses/by-nd/4.0/',
'file' => 'CC-BY-ND-4.0.txt',
'for_record' => false,
'for_media' => true,
'sort_order' => 70,
'active' => true,
],
8 => [
'name' => 'Attribution-NonCommercial-NoDerivatives 4.0 International',
'acronym' => 'CC BY-NC-ND 4.0',
'spdx_id' => 'CC-BY-NC-ND-4.0',
'kind' => LicenseKind::License,
'description' => 'The most restrictive CC license: the work can be shared with attribution, '
.'but cannot be modified nor used commercially.',
'uri' => 'https://creativecommons.org/licenses/by-nc-nd/4.0/',
'file' => 'CC-BY-NC-ND-4.0.txt',
'for_record' => false,
'for_media' => true,
'sort_order' => 80,
'active' => true,
],
];
}
/**
* Statement di RightsStatements.org: etichettano lo stato dei diritti dei
* media chiusi o incerti, non concedono permessi (nessun testo legale,
* nessun id SPDX).
*
* @return array<int, array<string, mixed>>
*/
private function rightsStatements(): array
{
return [
9 => [
'name' => 'In Copyright',
'acronym' => 'InC',
'spdx_id' => null,
'kind' => LicenseKind::RightsStatement,
'description' => 'The item is protected by copyright and all rights are reserved. Any reuse '
.'beyond legal exceptions requires permission from the rights holder.',
'uri' => 'https://rightsstatements.org/vocab/InC/1.0/',
'file' => null,
'for_record' => false,
'for_media' => true,
'sort_order' => 90,
'active' => true,
],
10 => [
'name' => 'In Copyright - Educational Use Permitted',
'acronym' => 'InC-EDU',
'spdx_id' => null,
'kind' => LicenseKind::RightsStatement,
'description' => 'The item is protected by copyright, but the rights holder allows reuse for '
.'educational purposes without further permission.',
'uri' => 'https://rightsstatements.org/vocab/InC-EDU/1.0/',
'file' => null,
'for_record' => false,
'for_media' => true,
'sort_order' => 100,
'active' => true,
],
11 => [
'name' => 'Copyright Not Evaluated',
'acronym' => 'CNE',
'spdx_id' => null,
'kind' => LicenseKind::RightsStatement,
'description' => 'The copyright status of the item has not been evaluated yet. The item '
.'should be treated as potentially protected: reuse may require permission.',
'uri' => 'https://rightsstatements.org/vocab/CNE/1.0/',
'file' => null,
'for_record' => false,
'for_media' => true,
'sort_order' => 110,
'active' => true,
],
];
}
}