diff --git a/lib/src/models/connection.dart b/lib/src/models/connection.dart index 2b14295..9ae3a77 100644 --- a/lib/src/models/connection.dart +++ b/lib/src/models/connection.dart @@ -1,6 +1,7 @@ import 'package:json_annotation/json_annotation.dart'; import 'connection_type.dart'; +import 'construction_report.dart'; import 'region.dart'; part 'connection.g.dart'; @@ -32,6 +33,9 @@ class Connection { @JsonKey(name: "doc") final String documentUrl; + @JsonKey(name: "meldungen") + final List reports; + const Connection({ this.id, this.name, @@ -47,6 +51,7 @@ class Connection { this.url, this.icsUrl, this.documentUrl, + this.reports, }); factory Connection.fromJson(Map json) => diff --git a/lib/src/models/connection.g.dart b/lib/src/models/connection.g.dart index 0db8073..a5c95e2 100644 --- a/lib/src/models/connection.g.dart +++ b/lib/src/models/connection.g.dart @@ -26,6 +26,11 @@ Connection _$ConnectionFromJson(Map json) { url: json['url'] as String, icsUrl: json['ics'] as String, documentUrl: json['doc'] as String, + reports: (json['meldungen'] as List) + ?.map((e) => e == null + ? null + : ConstructionReport.fromJson(e as Map)) + ?.toList(), ); } diff --git a/lib/src/models/construction_report.dart b/lib/src/models/construction_report.dart new file mode 100644 index 0000000..28e070e --- /dev/null +++ b/lib/src/models/construction_report.dart @@ -0,0 +1,114 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'construction_report.g.dart'; + +@JsonSerializable(createToJson: false) +class ConstructionReport { + final String id; + @JsonKey(name: "nr", fromJson: int.parse) + final int index; + + @JsonKey(name: "termin", fromJson: _parseListOrString) + final List timePeriodTexts; + @JsonKey(name: "termin_pins", fromJson: _parseListOrString) + final List timePeriodPinsTexts; + @JsonKey(name: "termin_zeit", fromJson: _parseListOrString) + final List timePeriodTimeTexts; + + final String headline; + final String headlinePins; + + @JsonKey(name: "meldung", fromJson: _parseListOrString) + final List messages; + @JsonKey(name: "meldung_pins", fromJson: _parseListOrString) + final List messagesPins; + @JsonKey(name: "meldung_hinweis", fromJson: _parseListOrString) + final List messagesHint; + + @JsonKey(name: "hinweis_tabelle", fromJson: _parseListOrString) + final List hintTable; + + @JsonKey(name: "grund") + final String reason; + + @JsonKey(name: "abschnitt") + final List affectedStations; + + final DateTime lastChange; + + @JsonKey(name: "ics") + final String icsUrl; + + @JsonKey(name: "termine", fromJson: _parseTimeRanges) + final List timeRanges; + + @JsonKey(name: "von") + final DateTime startDate; + @JsonKey(name: "bis") + final DateTime endDate; + + ConstructionReport({ + this.id, + this.index, + this.timePeriodTexts, + this.timePeriodPinsTexts, + this.timePeriodTimeTexts, + this.headline, + this.headlinePins, + this.messages, + this.messagesPins, + this.messagesHint, + this.hintTable, + this.reason, + this.affectedStations, + this.lastChange, + this.icsUrl, + this.timeRanges, + this.startDate, + this.endDate + }); + + factory ConstructionReport.fromJson(Map json) => + _$ConstructionReportFromJson(json); + + static List _parseTimeRanges(List ranges) { + return ranges.map((range) => TimeRange._fromJson(range)).toList(); + } + + static List _parseListOrString(dynamic input) { + switch (input.runtimeType) { + case String: + return [input]; + case List: + return input; + default: + return [input.toString()]; + } + } +} + +class TimeRange { + final DateTime begin; + final DateTime end; + + final bool allDay; + + final List weekdays; + + const TimeRange({this.begin, this.end, this.allDay, this.weekdays}); + + TimeRange._fromJson(Map json) + : begin = _parseTimeStamp(json, "von"), + end = _parseTimeStamp(json, "bis"), + allDay = json["ganztaegig"] == "1", + weekdays = json["wochentage"] is List + ? (json["wochentage"] as List) + .map((day) => int.parse(day)) + .toList() + : null; + + static DateTime _parseTimeStamp(Map json, String suffix) { + return DateTime.parse( + "${json["datum_$suffix"]} ${json["st_$suffix"]}:${json["min_$suffix"]}:00"); + } +} diff --git a/lib/src/models/construction_report.g.dart b/lib/src/models/construction_report.g.dart new file mode 100644 index 0000000..d59f076 --- /dev/null +++ b/lib/src/models/construction_report.g.dart @@ -0,0 +1,37 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'construction_report.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ConstructionReport _$ConstructionReportFromJson(Map json) { + return ConstructionReport( + id: json['id'] as String, + index: int.parse(json['nr'] as String), + timePeriodTexts: ConstructionReport._parseListOrString(json['termin']), + timePeriodPinsTexts: + ConstructionReport._parseListOrString(json['termin_pins']), + timePeriodTimeTexts: + ConstructionReport._parseListOrString(json['termin_zeit']), + headline: json['headline'] as String, + headlinePins: json['headlinePins'] as String, + messages: ConstructionReport._parseListOrString(json['meldung']), + messagesPins: ConstructionReport._parseListOrString(json['meldung_pins']), + messagesHint: + ConstructionReport._parseListOrString(json['meldung_hinweis']), + hintTable: ConstructionReport._parseListOrString(json['hinweis_tabelle']), + reason: json['grund'] as String, + affectedStations: + (json['abschnitt'] as List)?.map((e) => e as String)?.toList(), + lastChange: json['lastChange'] == null + ? null + : DateTime.parse(json['lastChange'] as String), + icsUrl: json['ics'] as String, + timeRanges: ConstructionReport._parseTimeRanges(json['termine'] as List), + startDate: + json['von'] == null ? null : DateTime.parse(json['von'] as String), + endDate: json['bis'] == null ? null : DateTime.parse(json['bis'] as String), + ); +} diff --git a/test/construction_report_test.dart b/test/construction_report_test.dart new file mode 100644 index 0000000..1a5197c --- /dev/null +++ b/test/construction_report_test.dart @@ -0,0 +1,86 @@ +import 'dart:convert'; + +import 'package:db_construction_site/db_construction_site.dart'; +import 'package:db_construction_site/src/models/construction_report.dart'; +import 'package:test/test.dart'; + +void main() { + test('test if json parsing works as expected', () { + const exampleReportJsonString = """ +{ + "id": "5604", + "nr": "1", + "termin": "von Montag, 27. Juli bis Sonntag, 16. August, jeweils ganztägig", + "termin_pins": "", + "termin_zeit": "", + "zusatz": "", + "headline": "Zugausfall Frankfurt-Höchst <> Frankfurt (Main) Hbf", + "headline_pins": "", + "meldung": "Die Züge der Linien RE 4 und RE 14 enden/beginnen in Frankfurt-Höchst und fallen zwischen Frankfurt-Höchst und Frankfurt (Main) Hbf aus. Als Ersatz nutzen Sie bitte die noch verkehrenden Züge in diesem Abschnitt.", + "meldung_pins": "", + "meldung_hinweis": "", + "hinweis_tabelle": "0", + "grund": "Oberleitungsarbeiten", + "von": "2020-07-27 00:00:00", + "bis": "2020-08-16 23:59:00", + "abschnitt": [ + "Frankfurt-Höchst", + "Frankfurt (Main) Hbf" + ], + "abschnitt_hin": "1", + "abschnitt_zurueck": "1", + "online": "1", + "last_change": "2020-06-29 09:35:03", + "termine": [ + { + "datum_von": "2020-07-27", + "datum_bis": "2020-08-16", + "st_von": "00", + "min_von": "00", + "st_bis": "23", + "min_bis": "59", + "jeweils": "0", + "ganztaegig": "1", + "wochentage": [] + } + ], + "ics": "https://bauinfos.deutschebahn.com/docs/hessen/ical-hessen-471-5604.ics", + "infos": [ + { + "TEXT": "Fahrplan Mannheim Hbf – Frankfurt (Main) Hbf 27.07. – 16.08.2020", + "URL": null, + "VERFALL": "2020-08-16 23:00:00", + "HIDDEN": "0", + "PRIORITAET": "1", + "last_change": "2020-06-02 10:25:10", + "url": "https://bauinfos.deutschebahn.com/docs/hessen/infos/471_2707-16082020_fahrplan.pdf" + }, + { + "TEXT": "Plakat Oberleitungsarbeiten Frankfurt-Höchst – Frankfurt (Main) Hbf 24.07. – 17.08.2020", + "URL": null, + "VERFALL": "2020-08-19 03:00:00", + "HIDDEN": "0", + "PRIORITAET": "1", + "last_change": "2020-07-20 14:18:22", + "url": "https://bauinfos.deutschebahn.com/docs/hessen/infos/471_627_645_1_8_2407-17082020.pdf" + } + ] + } + """; + Map json; + try { + json = JsonDecoder().convert(exampleReportJsonString); + assert(json != null); + } catch (e) { + print("JSON decoding failed, skipping test."); + return; + } + final connection = ConstructionReport.fromJson(json); + expect(connection.id, "5604"); + expect(connection.index, 1); + expect(connection.messages, ["Die Züge der Linien RE 4 und RE 14 enden/beginnen in Frankfurt-Höchst und fallen zwischen Frankfurt-Höchst und Frankfurt (Main) Hbf aus. Als Ersatz nutzen Sie bitte die noch verkehrenden Züge in diesem Abschnitt."]); + expect(connection.timeRanges.length, 1); + expect(connection.timeRanges[0].begin, connection.startDate); + expect(connection.affectedStations.length, 2); + }); +}