-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ let user fetch wikidata entity for station (#2858)
- Loading branch information
1 parent
31c0533
commit 2e85d73
Showing
8 changed files
with
297 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace App\Exceptions\Wikidata; | ||
|
||
use Exception; | ||
|
||
class FetchException extends Exception | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php | ||
|
||
namespace App\Http\Controllers\API\v1; | ||
|
||
use App\Exceptions\Wikidata\FetchException; | ||
use App\Models\Station; | ||
use App\Services\Wikidata\WikidataImportService; | ||
use Illuminate\Http\JsonResponse; | ||
use Illuminate\Support\Facades\RateLimiter; | ||
|
||
/** | ||
* undocumented, unstable, experimental endpoints. don't use in external applications! | ||
*/ | ||
class ExperimentalController extends Controller | ||
{ | ||
|
||
public function fetchWikidata(int $stationId): JsonResponse { | ||
if (!self::checkGeneralRateLimit()) { | ||
return response()->json(['error' => 'You are requesting too fast. Please try again later.'], 429); | ||
} | ||
|
||
if (!self::checkStationRateLimit($stationId)) { | ||
return response()->json(['error' => 'This station was already requested recently. Please try again later.'], 429); | ||
} | ||
|
||
$station = Station::findOrFail($stationId); | ||
if ($station->wikidata_id) { | ||
return response()->json(['error' => 'This station already has a wikidata id.'], 400); | ||
} | ||
|
||
try { | ||
WikidataImportService::searchStation($station); | ||
return response()->json(['message' => 'Wikidata information fetched successfully']); | ||
} catch (FetchException $exception) { | ||
return response()->json(['error' => $exception->getMessage()], 422); | ||
} | ||
} | ||
|
||
private static function checkGeneralRateLimit(): bool { | ||
$key = "fetch-wikidata-user:" . auth()->id(); | ||
if (RateLimiter::tooManyAttempts($key, 10)) { | ||
return false; | ||
} | ||
RateLimiter::increment($key); | ||
return true; | ||
} | ||
|
||
private static function checkStationRateLimit(int $stationId): bool { | ||
// request a station 1 time per 5 minutes | ||
|
||
$key = "fetch-wikidata-station:$stationId"; | ||
if (RateLimiter::tooManyAttempts($key, 1)) { | ||
return false; | ||
} | ||
RateLimiter::increment($key, 5 * 60); | ||
return true; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
app/Http/Controllers/Frontend/OpenData/WikidataController.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace App\Http\Controllers\Frontend\OpenData; | ||
|
||
use App\Http\Controllers\Controller; | ||
use App\Models\Station; | ||
use Illuminate\View\View; | ||
|
||
class WikidataController extends Controller | ||
{ | ||
public function indexHelpPage(): View { | ||
|
||
//get stations the user was travelling recently, without a wikidata id | ||
$destinationStationsWithoutWikidata = Station::join('train_stopovers', 'train_stations.id', '=', 'train_stopovers.train_station_id') | ||
->join('train_checkins', 'train_checkins.destination_stopover_id', '=', 'train_stopovers.id') | ||
->where('train_checkins.user_id', auth()->id()) | ||
->whereNull('train_stations.wikidata_id') | ||
->select('train_stations.*') | ||
->limit(50) | ||
->get(); | ||
|
||
return view('open-data.wikidata.index', [ | ||
'destinationStationsWithoutWikidata' => $destinationStationsWithoutWikidata | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
@extends('layouts.app') | ||
|
||
@section('title', 'Open Data: Wikidata') | ||
|
||
@section('content') | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="col-12"> | ||
<h1 class="fs-4"> | ||
Open Data - Wikidata: Missing station information | ||
</h1> | ||
|
||
@if(app()->getLocale() !== 'en') | ||
<div class="alert alert-info" role="alert"> | ||
<i class="fas fa-info-circle"></i> | ||
{{__('page-only-available-in-language', ['language' => __('language.en')])}} | ||
</div> | ||
@endif | ||
|
||
|
||
<div class="alert alert-info" role="alert"> | ||
<i class="fas fa-info-circle"></i> | ||
<b>What is this page for?</b> | ||
<br/> | ||
<p> | ||
This page lists all stations you're träwelled to, that are missing a Wikidata link. | ||
Click the "Fetch" button to fetch the Wikidata information for a station. | ||
<br/> | ||
If no Wikidata object was found, please help us to assign it by maintaining the data at | ||
Wikidata. | ||
We will search for the station using the IBNR known to us. | ||
<br/> | ||
If the station already exists in Wikidata, please add it to the object and "Fetch" again. | ||
If not, please create an object. | ||
</p> | ||
|
||
<hr/> | ||
<i class="fa-solid fa-file-circle-question"></i> | ||
<b>What data is relevant for Träwelling?</b> | ||
|
||
<p> | ||
Träwelling uses the Wikidata object to enrich the station information. | ||
The following properties are relevant for Träwelling: | ||
</p> | ||
<ul> | ||
<li> | ||
<a href="https://www.wikidata.org/wiki/Property:P954" target="P954"> | ||
IBNR | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.wikidata.org/wiki/Property:P12393" target="P12393"> | ||
IFOPT | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.wikidata.org/wiki/Property:P8671" target="P8671"> | ||
Ril 100 (DB-Betriebsstellenabkürzung) | ||
</a> | ||
</li> | ||
<li> | ||
<a href="https://www.wikidata.org/wiki/Property:P1448" target="P1448"> | ||
Official name | ||
</a> | ||
</li> | ||
</ul> | ||
</div> | ||
|
||
<table class="table"> | ||
<thead> | ||
<tr> | ||
<th>Station</th> | ||
<th>IBNR</th> | ||
<th>IFOPT</th> | ||
<th>Ril100</th> | ||
<th>Wikidata</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
@foreach($destinationStationsWithoutWikidata as $station) | ||
<tr id="station-{{$station->id}}"> | ||
<td>{{$station->name}}</td> | ||
<td>{{$station->ibnr}}</td> | ||
<td>{{$station->ifopt}}</td> | ||
<td>{{$station->rilIdentifier}}</td> | ||
<td> | ||
<button class="btn btn-primary btn-sm" onclick="fetchWikidata({{$station->id}})"> | ||
<i class="fas fa-link"></i> | ||
Fetch | ||
</button> | ||
</td> | ||
</tr> | ||
@endforeach | ||
</tbody> | ||
</table> | ||
|
||
<script> | ||
function fetchWikidata(stationId) { | ||
console.log('Fetching Wikidata for station ' + stationId); | ||
fetch('/api/v1/experimental/station/' + stationId + '/wikidata', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content') | ||
} | ||
}) | ||
.then(response => response.json()) | ||
.then(data => { | ||
console.log(data); | ||
if (data.error) { | ||
notyf.error(data.error || 'Error fetching Wikidata'); | ||
} else { | ||
notyf.success(data.message || 'Wikidata fetched'); | ||
document.getElementById('station-' + stationId).remove(); | ||
} | ||
}) | ||
} | ||
</script> | ||
</div> | ||
</div> | ||
</div> | ||
@endsection |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.