Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
361e958
feat: first simple DEI import
trenc Apr 23, 2026
18ece6f
test: add feature test cases for DEI importer
trenc Apr 23, 2026
40ef716
test: add JsonLdParser unit tests
trenc Apr 23, 2026
fca31c9
build: ignore raw imports
trenc Apr 23, 2026
b7ec914
refactor: split responsibilities and use a DTO
trenc Apr 23, 2026
a6975ac
test: Parsed data is now a DTO
trenc Apr 23, 2026
7457f61
refactor: split responsibility even more, use Formrequest validation
trenc Apr 23, 2026
a9a21c4
Merge branch 'main' into feat/DEI
trenc Apr 24, 2026
bc4016d
fix: no strict returns on expections
trenc Apr 24, 2026
76b52eb
refactor: use PHP 8.3 compatible readonly classes now
trenc Apr 24, 2026
651391a
build: install a PHPStan as static analyzer
trenc Apr 27, 2026
2a26d96
fix: set correct logic and use argument with correct type
trenc Apr 27, 2026
4f64ba4
fix: use Exception class
trenc Apr 27, 2026
f21327d
fix: no 4 arguments
trenc Apr 27, 2026
f47a1e4
build: add folders for PHPStan
trenc Apr 27, 2026
e856236
refactor: make variable meaningful
trenc Apr 27, 2026
3f2e46d
refactor: make variable meaningful
trenc Apr 27, 2026
3baf4bc
refactor: restructure importer
trenc Apr 27, 2026
dac7af6
fix: abort if manifest is not existent, readable
trenc Apr 27, 2026
6814007
refactor: fetch manifest only once
trenc Apr 27, 2026
08faf22
test: enhance tests
trenc Apr 27, 2026
1a2ee8d
refactor: remove unused
trenc Apr 27, 2026
26197c7
refactor: remove obsolete converted
trenc Apr 27, 2026
e719ade
test: remove obsolete converted
trenc Apr 27, 2026
873d132
refactor: avoid useless string checks but keep generic URL validation
trenc Apr 27, 2026
3d1743c
refactor: rename to be more precise
trenc Apr 27, 2026
7811483
refactor: create indexer for resolving references and refactor structure
trenc Apr 30, 2026
17a36ec
test: enhance the unit test with more cases
trenc Apr 30, 2026
82ac589
feat: introduce tiny literal and deduplicate feature
trenc Apr 30, 2026
0ce7204
test: test for nested references and deduplicate
trenc Apr 30, 2026
d24e266
test: add fixture test case
trenc Apr 30, 2026
95b48ab
docs: update stoplight elements
trenc Apr 30, 2026
9610ef4
docs: describe new endpoint for dei import
trenc Apr 30, 2026
f85b155
fix: remove unused parts
trenc Apr 30, 2026
9b3eebb
fix: check for valid IIIF manifest
trenc Apr 30, 2026
5b5d665
fix: return status 400 if token based fetch fails
trenc May 5, 2026
0ace734
test: test for status 400 on token fetch
trenc May 5, 2026
b39532d
fix: values should be comma replaced
trenc May 5, 2026
c092ae2
test: test for comma replace regression
trenc May 5, 2026
9548e94
test: test for actual @id resolving
trenc May 5, 2026
d37454f
fix: skip the object if it just reference
trenc May 5, 2026
90bd249
fix: don't add @id to agent if label exists
trenc May 5, 2026
1df769e
test: update test cases without @id
trenc May 5, 2026
df3e995
fix: store only one language value (english or first) otherwise all
trenc May 5, 2026
dc8a05a
test: change test for english values
trenc May 5, 2026
0ea6bd4
fix: add headers to fetch to prevent status 403
trenc May 5, 2026
9e3f1f9
fix: extract correct manifest from edm:WebResource
trenc May 5, 2026
f7c845f
test: test for extracting IIIF manifest
trenc May 5, 2026
5ed7ef4
fix: store Manifest in Story table
trenc May 5, 2026
d972441
fix: ad:agent is also scalar
trenc May 5, 2026
cc0a67f
test: test on deduplicate edm:agent
trenc May 5, 2026
93de736
refactor: split to focused classes with distinct responsibilities
trenc May 6, 2026
98a6a4a
test: add distinct test cases for IiifManifestClioent
trenc May 6, 2026
738467b
feat: support for manifest v2 and v3
trenc May 6, 2026
8497e80
test: enhance test for manifest v3 and v2
trenc May 6, 2026
7ab094e
refactor: PER style
trenc May 6, 2026
347ddde
refactor: use DB class explicitly
trenc May 6, 2026
a84c812
refactor: remove comment
trenc May 6, 2026
1f314db
refactor: repsonse different message on story update
trenc May 6, 2026
faf8264
docs: describe DEI import endpoint
trenc May 6, 2026
e457e33
build: DEI importer marks version 2
trenc May 6, 2026
384b51d
docs: add new vars to env
trenc May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/src/public/storage
/src/storage/*.key
/src/storage/export_cache
/src/storage/imports
/src/vendor
/local-data
.env*
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ test: serve
@clear
@bash docker_artisan.sh test --without-tty --colors=always --filter "$(FILTER)"

stan: serve
@clear
./src/vendor/bin/phpstan analyze src/app src/database src/config src/routes --level "$(LEVEL)"

lint: serve
@clear
./src/vendor/bin/pint --test -v src/app src/tests src/routes --preset per
Expand Down
4 changes: 4 additions & 0 deletions src/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ MAIL_PASSWORD=password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="no-reply@example.com"
MAIL_FROM_NAME="Transcribathon"

ENRICH_EUROPEANA_IIIF_SSO_URL=sso_url
ENRICH_EUROPEANA_IIIF_CLIENT_SECRET=secret
ENRICH_EUROPEANA_IIIF_CLIENT_ID=client
2 changes: 1 addition & 1 deletion src/app/Console/Commands/GenerateAuthToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class GenerateAuthToken extends Command
{--ro : Shorthand for read-only}
{--rw : Shorthand for full access}';

protected $description = 'Generates an api client auth token for api usage';
protected $description = 'Generates an api client auth token for api usage';

public function handle(): int
{
Expand Down
2 changes: 1 addition & 1 deletion src/app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected function schedule(Schedule $schedule)
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
$this->load(__DIR__ . '/Commands');

require base_path('routes/console.php');
}
Expand Down
5 changes: 2 additions & 3 deletions src/app/Exceptions/AltoNotPreparedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@

final class AltoNotPreparedException extends RuntimeException
{

public function __construct(
private readonly int $storyId,
string $message = 'The ALTO export has not been prepared.',
int $code = 0,
?Throwable $previous = null
?Throwable $previous = null,
) {
parent::__construct($message, $code, $previous);
}
Expand All @@ -27,7 +26,7 @@ public function render($_request): JsonResponse
'prepare_post_url' => url("/stories/{$this->storyId}/items/export/mets"),
$this->getMessage(),
],
409
409,
);
}
}
8 changes: 2 additions & 6 deletions src/app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@

namespace App\Exceptions;

use App\Exceptions\AltoNotPreparedException;
use App\Http\Controllers\ResponseController;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Validation\ValidationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Response;
use Throwable;


class Handler extends ExceptionHandler
{
/**
Expand Down Expand Up @@ -44,12 +40,12 @@ public function register(): void
});
}

protected function unauthenticated($request, AuthenticationException $exception): JsonResponse
protected function unauthenticated($request, AuthenticationException $exception)
{
return ResponseController::sendError($exception->getMessage(), '', 401);
}

public function render($request, Throwable $exception): Response
public function render($request, Throwable $exception)
{
if ($exception instanceof AuthenticationException) {
return ResponseController::sendError($exception->getMessage(), '', 401);
Expand Down
29 changes: 15 additions & 14 deletions src/app/Http/Controllers/AutoEnrichmentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace App\Http\Controllers;

use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\ResponseController;
use App\Models\AutoEnrichment;
use App\Models\Item;
use App\Models\Story;
Expand All @@ -18,7 +18,7 @@ public function index(Request $request): JsonResponse
'Name' => 'Name',
'Type' => 'Type',
'StoryId' => 'StoryId',
'ItemId' => 'ItemId'
'ItemId' => 'ItemId',
];

$initialSortColumn = 'AutoEnrichmentId';
Expand All @@ -27,8 +27,8 @@ public function index(Request $request): JsonResponse

$data = $this->getDataByRequest($request, $model, $queryColumns, $initialSortColumn);

if(!$data) {
return $this->sendError('Invalid data', $request, ' not valid', 400);
if (!$data) {
return $this->sendError('Invalid data', $request . ' not valid', 400);
}

$collection = AutoEnrichmentResource::collection($data);
Expand All @@ -48,7 +48,7 @@ public function store(Request $request): JsonResponse
$resource = new AutoEnrichmentResource($data);

return $this->sendResponse($resource, 'Auto Enrichment inserted.');
} catch (\Exception $exception) {
} catch (Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand Down Expand Up @@ -76,22 +76,23 @@ public function storeBulk(Request $request): JsonResponse
}

$instertedResource = new AutoEnrichmentResource($inserted);
$errorResource = new AutoEnrichmentResource($errors);

$insertedCount = count($inserted);
$errorsCount = count($errors);

if ($insertedCount === 0 && $errorsCount > 0) {
return $this->sendError('Invalid data', $errors, 400);
if ($errorsCount > 0 && $insertedCount > 0) {
return $this->sendPartlyResponse($instertedResource, $errors, 'Some Auto Enrichments inserted.');
}

if ($insertedCount > 0 && $errorsCount === 0) {
return $this->sendResponse($instertedResource, 'All Auto Enrichments inserted.');
if ($errorsCount > 0) {
return $this->sendError('Invalid data', $errors, 400);
}

if ($insertedCount > 0 && $errorsCount > 0) {
return $this->sendPartlyResponse($instertedResource, $errorResource, 'Some Auto Enrichments inserted.');
if ($insertedCount === 0) {
return $this->sendError('Invalid data', 'Nothing imported.', 400);
}

return $this->sendResponse($instertedResource, 'All Auto Enrichments inserted.');
}

public function show(int $id): JsonResponse
Expand Down Expand Up @@ -134,7 +135,7 @@ public function update(Request $request, int $id): JsonResponse
$autoEnrichmentData->save();

return $this->sendResponse(new AutoEnrichmentResource($autoEnrichmentData), 'Auto Enrichment updated.');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand All @@ -148,7 +149,7 @@ public function destroy(int $id): JsonResponse
$autoEnrichmentData->delete();

return $this->sendResponse($resource, 'Auto Enrichment deleted.');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/app/Http/Controllers/CampaignController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\ResponseController;
use App\Models\Campaign;
use App\Http\Resources\CampaignResource;

Expand All @@ -14,7 +13,7 @@ public function index(Request $request): JsonResponse
{
$queryColumns = [
'Name' => 'Name',
'DatasetId' => 'DatasetId'
'DatasetId' => 'DatasetId',
];

$initialSortColumn = 'CampaignId';
Expand Down Expand Up @@ -81,7 +80,7 @@ public function update(Request $request, int $id): JsonResponse
}

return $this->sendResponse(new CampaignResource($campaign), 'Campaign updated.');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand All @@ -95,7 +94,7 @@ public function destroy(int $id): JsonResponse
$campaign->delete();

return $this->sendResponse($resource, 'Campaign deleted.');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand Down
9 changes: 4 additions & 5 deletions src/app/Http/Controllers/CampaignStatsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace App\Http\Controllers;

use App\Http\Controllers\ResponseController;
use App\Http\Resources\CampaignStatsResource;
use App\Models\Campaign;
use App\Models\Score;
Expand Down Expand Up @@ -43,7 +42,7 @@ public function show(int $id): JsonResponse
'CampaignId' => $id,
'Summary' => $summary,
'Teams' => $teams,
'Users' => $users
'Users' => $users,
];

$resource = new CampaignStatsResource($grouped);
Expand All @@ -67,7 +66,7 @@ protected function buildTeamStatistics(int $campaignId): array
foreach ($campaign->teams as $team) {
$teamStats = [
'TeamId' => $team['TeamId'],
'Miles' => 0
'Miles' => 0,
];

$teamScoreIds = DB::table('TeamScore')
Expand Down Expand Up @@ -99,7 +98,7 @@ protected function buildTeamStatistics(int $campaignId): array
->filter(function ($story) use ($teamCampaignScores) {
$itemIds = array_merge(
$story->ItemIds->all(),
$teamCampaignScores->pluck('ItemId')->all()
$teamCampaignScores->pluck('ItemId')->all(),
);
return count(array_unique($itemIds)) > 0 ? true : false;
})
Expand Down Expand Up @@ -132,7 +131,7 @@ protected function buildStatistics(Collection $collection): array
'Enrichments' => $collection->pluck('Enrichments')->sum(),
'Descriptions' => $collection->pluck('Descriptions')->sum(),
'HTRTranscriptions' => $collection->pluck('HTRTranscriptions')->sum(),
'Miles' => ceil($collection->pluck('Miles')->sum())
'Miles' => ceil($collection->pluck('Miles')->sum()),
];
}
}
4 changes: 3 additions & 1 deletion src/app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@

class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
use AuthorizesRequests;
use DispatchesJobs;
use ValidatesRequests;
}
7 changes: 3 additions & 4 deletions src/app/Http/Controllers/DatasetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\ResponseController;
use App\Models\Dataset;
use App\Http\Resources\DatasetResource;

Expand All @@ -14,7 +13,7 @@ public function index(Request $request): JsonResponse
{
$queryColumns = [
'Name' => 'Name',
'ProjectId' => 'ProjectId'
'ProjectId' => 'ProjectId',
];

$initialSortColumn = 'DatasetId';
Expand Down Expand Up @@ -71,7 +70,7 @@ public function update(Request $request, int $id): JsonResponse
$dataset->save();

return $this->sendResponse(new DatasetResource($dataset), 'Dataset updated.');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand All @@ -90,7 +89,7 @@ public function destroy(int $id): JsonResponse
$dataset->delete();

return $this->sendResponse($resource, 'Dataset deleted.');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
return $this->sendError('Invalid data', $exception->getMessage(), 400);
}
}
Expand Down
16 changes: 9 additions & 7 deletions src/app/Http/Controllers/HealthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

namespace App\Http\Controllers;

use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\ResponseController;
use App\Http\Resources\HealthResource;

class HealthController extends ResponseController
Expand Down Expand Up @@ -66,7 +66,7 @@ protected function checkDatabaseConnection(): array

$data['conected'] = 'Ok' ;
$data['time'] = round(($end - $start) * 1000);
} catch (\Exception $exception) {
} catch (Exception $exception) {
$data['conected'] = 'Failed';
$data['time'] = 0;
}
Expand All @@ -82,7 +82,7 @@ protected function checkDatabaseExecutionTime(): int
$end = microtime(true);

return round(($end - $start) * 1000);
} catch (\Exception $exception) {
} catch (Exception $exception) {
return 0;
}
}
Expand All @@ -102,7 +102,8 @@ protected function checkNetworkConnection(): array
$data['conected'] = 'Ok';
$data['time'] = round(($end - $start) * 1000);
}
} catch(Exception $exception) { }
} catch (Exception $exception) {
}

return $data;
}
Expand All @@ -117,8 +118,8 @@ protected function checkApiV1Connection(): array
$start = microtime(true);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'http://transcribathon.eu/tp-api/projects/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_URL, 'http://transcribathon.eu/tp-api/projects/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

Expand All @@ -134,7 +135,8 @@ protected function checkApiV1Connection(): array
}

curl_close($ch);
} catch (Exception $exception) { }
} catch (Exception $exception) {
}

return $data;
}
Expand Down
Loading
Loading