diff --git a/.idea/trwl.iml b/.idea/trwl.iml
index d2eeaea44..d2bc5e7d8 100644
--- a/.idea/trwl.iml
+++ b/.idea/trwl.iml
@@ -189,4 +189,4 @@
-
\ No newline at end of file
+
diff --git a/app/Http/Controllers/API/v1/Controller.php b/app/Http/Controllers/API/v1/Controller.php
index 2a1e42626..e408bdf8e 100644
--- a/app/Http/Controllers/API/v1/Controller.php
+++ b/app/Http/Controllers/API/v1/Controller.php
@@ -10,7 +10,8 @@
* title="Träwelling API",
* description="Träwelling user API description. This is an incomplete documentation with still many errors. The
* API is currently not yet stable. Endpoints are still being restructured. Both the URL and the request or body
- * can be changed. Breaking changes will be announced on the Discord server: https://discord.gg/72t7564ZbV",
+ * can be changed. Breaking changes will be announced on GitHub:
+ * https://github.com/Traewelling/traewelling/blob/develop/API_CHANGELOG.md",
* @OA\Contact(
* email="support@traewelling.de"
* ),
@@ -90,7 +91,11 @@ public function sendResponse(
int $code = 200,
array $additional = null
): JsonResponse {
- $disclaimer = 'APIv1 is not officially released for use and is also not fully documented. You can find the documentation at https://traewelling.de/api/documentation. Use at your own risk. Data fields may change at any time without notice.';
+ $disclaimer = [
+ 'message' => 'APIv1 is not officially released for use and is also not fully documented. Use at your own risk. Data fields may change at any time without notice.',
+ 'documentation' => 'https://traewelling.de/api/documentation',
+ 'changelog' => 'https://github.com/Traewelling/traewelling/blob/develop/API_CHANGELOG.md',
+ ];
if ($data === null) {
return response()->json(
data: [
diff --git a/app/Http/Controllers/API/v1/StatusController.php b/app/Http/Controllers/API/v1/StatusController.php
index e6dbd080e..952581549 100644
--- a/app/Http/Controllers/API/v1/StatusController.php
+++ b/app/Http/Controllers/API/v1/StatusController.php
@@ -289,9 +289,9 @@ public function getLivePositionForStatus($ids): AnonymousResourceCollection {
*
* @param int $id
*
- * @return StatusResource|Response
+ * @return StatusResource
*/
- public function show(int $id): StatusResource|Response {
+ public function show(int $id): StatusResource {
$status = StatusBackend::getStatus($id);
try {
$this->authorize('view', $status);
diff --git a/app/Http/Controllers/StatusController.php b/app/Http/Controllers/StatusController.php
index a80a7fdd4..0b0338477 100644
--- a/app/Http/Controllers/StatusController.php
+++ b/app/Http/Controllers/StatusController.php
@@ -60,22 +60,22 @@ public static function getStatus(int $statusId): Status {
*/
public static function getActiveStatuses(): ?Collection {
return Status::with([
- 'event', 'likes', 'user.blockedByUsers', 'user.blockedUsers', 'user.followers',
- 'checkin.originStation', 'checkin.destinationStation',
- 'checkin.Trip.stopovers.station',
- 'checkin.Trip.polyline',
- ])
- ->whereHas('checkin', function($query) {
- $query->where('departure', '<', date('Y-m-d H:i:s'))
- ->where('arrival', '>', date('Y-m-d H:i:s'));
- })
- ->get()
- ->filter(function(Status $status) {
- return Gate::allows('view', $status) && !$status->user->shadow_banned && $status->visibility !== StatusVisibility::UNLISTED;
- })
- ->sortByDesc(function(Status $status) {
- return $status->checkin->departure;
- })->values();
+ 'event', 'likes', 'user.blockedByUsers', 'user.blockedUsers', 'user.followers',
+ 'checkin.originStation', 'checkin.destinationStation',
+ 'checkin.Trip.stopovers.station',
+ 'checkin.Trip.polyline',
+ ])
+ ->whereHas('checkin', function($query) {
+ $query->where('departure', '<', date('Y-m-d H:i:s'))
+ ->where('arrival', '>', date('Y-m-d H:i:s'));
+ })
+ ->get()
+ ->filter(function(Status $status) {
+ return Gate::allows('view', $status) && !$status->user->shadow_banned && $status->visibility !== StatusVisibility::UNLISTED;
+ })
+ ->sortByDesc(function(Status $status) {
+ return $status->checkin->departure;
+ })->values();
}
public static function getLivePositions(): array {
@@ -283,7 +283,8 @@ public static function createStatus(
'body' => $body,
'business' => $business,
'visibility' => $visibility,
- 'event_id' => $event?->id
+ 'event_id' => $event?->id,
+ 'client_id' => request()?->user()?->token()?->client?->id,
]);
}
}
diff --git a/app/Http/Resources/ClientResource.php b/app/Http/Resources/ClientResource.php
new file mode 100644
index 000000000..ca2087ba2
--- /dev/null
+++ b/app/Http/Resources/ClientResource.php
@@ -0,0 +1,19 @@
+ OAuthClient
+ */
+class ClientResource extends JsonResource
+{
+ public function toArray($request) {
+ return [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'privacyPolicyUrl' => $this->privacy_policy_url,
+ ];
+ }
+}
diff --git a/app/Http/Resources/StatusResource.php b/app/Http/Resources/StatusResource.php
index e5fbde6e0..b35d0c272 100644
--- a/app/Http/Resources/StatusResource.php
+++ b/app/Http/Resources/StatusResource.php
@@ -30,22 +30,23 @@ public function toArray($request): array {
'likes' => (int) $this->likes->count(),
'liked' => (bool) $this->favorited,
'isLikable' => Gate::allows('like', $this->resource),
+ 'client' => new ClientResource($this->client),
'createdAt' => $this->created_at->toIso8601String(),
'train' => [
- 'trip' => (int) $this->checkin->trip->id,
- 'hafasId' => (string) $this->checkin->trip->trip_id,
- 'category' => (string) $this->checkin->trip->category->value,
- 'number' => (string) $this->checkin->trip->number,
- 'lineName' => (string) $this->checkin->trip->linename,
- 'journeyNumber' => $this->checkin->trip->journey_number,
- 'distance' => (int) $this->checkin->distance,
- 'points' => (int) $this->checkin->points,
- 'duration' => (int) $this->checkin->duration,
- 'manualDeparture' => $this->checkin->manual_departure?->toIso8601String(),
- 'manualArrival' => $this->checkin->manual_arrival?->toIso8601String(),
- 'origin' => new StopoverResource($this->checkin->originStopover),
- 'destination' => new StopoverResource($this->checkin->destinationStopover),
- 'operator' => new OperatorResource($this?->checkin->trip->operator)
+ 'trip' => (int) $this->checkin->trip->id,
+ 'hafasId' => (string) $this->checkin->trip->trip_id,
+ 'category' => (string) $this->checkin->trip->category->value,
+ 'number' => (string) $this->checkin->trip->number,
+ 'lineName' => (string) $this->checkin->trip->linename,
+ 'journeyNumber' => $this->checkin->trip->journey_number,
+ 'distance' => (int) $this->checkin->distance,
+ 'points' => (int) $this->checkin->points,
+ 'duration' => (int) $this->checkin->duration,
+ 'manualDeparture' => $this->checkin->manual_departure?->toIso8601String(),
+ 'manualArrival' => $this->checkin->manual_arrival?->toIso8601String(),
+ 'origin' => new StopoverResource($this->checkin->originStopover),
+ 'destination' => new StopoverResource($this->checkin->destinationStopover),
+ 'operator' => new OperatorResource($this?->checkin->trip->operator)
],
'event' => new EventResource($this?->event),
];
diff --git a/app/Models/Status.php b/app/Models/Status.php
index 6c1959b02..31d607734 100644
--- a/app/Models/Status.php
+++ b/app/Models/Status.php
@@ -16,8 +16,10 @@
* @property int user_id
* @property string body
* @property Business business
- * @property int event_id
* @property StatusVisibility visibility
+ * @property int event_id
+ * @property string tweet_id
+ * @property string mastodon_post_id
* @property Checkin $checkin
*
* @todo merge model with "Checkin" (later only "Checkin") because the difference between trip sources (HAFAS,
@@ -28,7 +30,7 @@ class Status extends Model
use HasFactory;
- protected $fillable = ['user_id', 'body', 'business', 'visibility', 'event_id', 'tweet_id', 'mastodon_post_id'];
+ protected $fillable = ['user_id', 'body', 'business', 'visibility', 'event_id', 'tweet_id', 'mastodon_post_id', 'client_id'];
protected $hidden = ['user_id', 'business'];
protected $appends = ['favorited', 'socialText', 'statusInvisibleToMe', 'description'];
protected $casts = [
@@ -39,6 +41,7 @@ class Status extends Model
'event_id' => 'integer',
'tweet_id' => 'string',
'mastodon_post_id' => 'string',
+ 'client_id' => 'integer'
];
public function user(): BelongsTo {
@@ -53,6 +56,10 @@ public function checkin(): HasOne {
return $this->hasOne(Checkin::class);
}
+ public function client(): BelongsTo {
+ return $this->belongsTo(OAuthClient::class, 'client_id', 'id');
+ }
+
/**
* @return HasOne
* @deprecated use ->checkin instead
diff --git a/app/Virtual/Models/Client.php b/app/Virtual/Models/Client.php
new file mode 100644
index 000000000..8a7e72eff
--- /dev/null
+++ b/app/Virtual/Models/Client.php
@@ -0,0 +1,49 @@
+unsignedBigInteger('client_id')->nullable()->after('tweet_id');
+ $table->foreign('client_id')->references('id')->on('oauth_clients')->nullOnDelete();
+ });
+ }
+
+ public function down(): void {
+ Schema::table('statuses', function(Blueprint $table) {
+ $table->dropForeign(['client_id']);
+ $table->dropColumn('client_id');
+ });
+ }
+};
diff --git a/resources/views/admin/status/edit.blade.php b/resources/views/admin/status/edit.blade.php
index eb1e8b10c..79f073fc1 100644
--- a/resources/views/admin/status/edit.blade.php
+++ b/resources/views/admin/status/edit.blade.php
@@ -34,11 +34,21 @@
@isset($status->checkin->trip->operator?->name)
(Betreiber: {{$status->checkin->trip->operator?->name}})
@endisset
-
+
{{ $status->checkin->trip_id }}
+
+
+
+
+
+ @isset($status?->client)
+ {{$status->client->name}} (#{{$status->client->id}})
+ @endisset
+
+