Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions assets/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
"occupiedUntil": "Belegt bis {}",
"rooms": "Räume",
"roomDetails": "Raumdetails",
"openInNavigaTum": "In NavigaTUM öffnen",
"openRoomCalendar": "Raumkalender öffnen",
"building": "Gebäude",
"nFreeRooms": {
"zero": "Keine freien Räume",
Expand Down
2 changes: 2 additions & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
"occupiedUntil": "Occupied until {}",
"rooms": "Rooms",
"roomDetails": "Room Details",
"openInNavigaTum": "Open in NavigaTUM",
"openRoomCalendar": "Open room calendar",
"building": "Building",
"nFreeRooms": {
"zero": "No free rooms",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ part 'navigatum_navigation_additional_properties.g.dart';
class NavigaTumNavigationAdditionalProperties {
@JsonKey(name: "computed")
final List<NavigaTumNavigationProperty> properties;
@JsonKey(name: "calendar_url")
final String? calendarUrl;

NavigaTumNavigationAdditionalProperties(this.properties);
NavigaTumNavigationAdditionalProperties(this.properties, this.calendarUrl);

factory NavigaTumNavigationAdditionalProperties.fromJson(
Map<String, dynamic> json,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions lib/navigaTumComponent/model/navigatum_navigation_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ class NavigaTumNavigationDetails {
bool get hasCoordinates =>
coordinates.latitude != null && coordinates.longitude != null;

Uri get navigaTumUri =>
Uri(scheme: "https", host: "nav.tum.de", pathSegments: ["room", id]);

Uri? get calendarUri {
final uri = additionalProperties.calendarUrl != null
? Uri.tryParse(additionalProperties.calendarUrl!)
: null;
if (uri == null || uri.scheme != "https" || uri.host != "campus.tum.de") {
return null;
}
return uri;
}

NavigaTumNavigationDetails(
this.id,
this.name,
Expand Down
29 changes: 27 additions & 2 deletions lib/navigaTumComponent/views/navigatum_room_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:campus_flutter/base/util/custom_back_button.dart';
import 'package:campus_flutter/base/util/delayed_loading_indicator.dart';
import 'package:campus_flutter/base/errorHandling/error_handling_router.dart';
import 'package:campus_flutter/base/util/map_launcher.dart';
import 'package:campus_flutter/base/util/url_launcher.dart';
import 'package:campus_flutter/navigaTumComponent/model/navigatum_navigation_details.dart';
import 'package:campus_flutter/navigaTumComponent/viewModels/navigatum_details_viewmodel.dart';
import 'package:campus_flutter/navigaTumComponent/views/navigatum_room_details_view.dart';
Expand All @@ -29,8 +30,8 @@ class NavigaTumRoomScaffold extends ConsumerWidget {
StreamBuilder(
stream: ref.watch(navigaTumDetailsViewModel(id)).details,
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data!.hasCoordinates) {
return _directionsButton(snapshot.data!, context);
if (snapshot.hasData) {
return _actionButtons(snapshot.data!, context, ref);
} else {
return const SizedBox.shrink();
}
Expand All @@ -42,6 +43,30 @@ class NavigaTumRoomScaffold extends ConsumerWidget {
);
}

Widget _actionButtons(
NavigaTumNavigationDetails details,
BuildContext context,
WidgetRef ref,
) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () => UrlLauncher.url(details.navigaTumUri, ref),
tooltip: context.tr("openInNavigaTum"),
icon: Icon(Icons.open_in_new, color: context.theme.primaryColor),
),
if (details.calendarUri != null)
IconButton(
onPressed: () => UrlLauncher.url(details.calendarUri!, ref),
tooltip: context.tr("openRoomCalendar"),
icon: Icon(Icons.calendar_month, color: context.theme.primaryColor),
),
if (details.hasCoordinates) _directionsButton(details, context),
],
);
}

Widget _directionsButton(
NavigaTumNavigationDetails details,
BuildContext context,
Expand Down
48 changes: 47 additions & 1 deletion test/navigaTumApi/navigatum_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ void main() {
"computed": [
{"name": "Seats", "text": "200"},
{"name": "Building", "text": "MI"}
]
],
"calendar_url": "https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12543&cReadonly=J"
},
"coords": {
"lat": 48.26244,
Expand Down Expand Up @@ -163,6 +164,12 @@ void main() {
expect(details.additionalProperties.properties.length, 2);
expect(details.additionalProperties.properties[0].name, 'Seats');
expect(details.additionalProperties.properties[0].text, '200');
expect(
details.additionalProperties.calendarUrl,
'https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12543&cReadonly=J',
);
expect(details.calendarUri?.host, 'campus.tum.de');
expect(details.navigaTumUri.toString(), 'https://nav.tum.de/room/5606.EG.001');

// Maps
expect(details.maps.defaultMapId, 'rf142');
Expand Down Expand Up @@ -190,5 +197,44 @@ void main() {

expect(details.hasCoordinates, isFalse);
});

test('navigaTumUri encodes the room id as a single path segment', () {
final json = j('''
{
"id": "5500/01?A",
"name": "Test Room",
"parent_names": ["Garching"],
"type": "room",
"type_common_name": "Room",
"props": {"computed": []},
"coords": {},
"maps": {"default": "rf000"}
}
''');
final details = NavigaTumNavigationDetails.fromJson(json);

expect(details.navigaTumUri.toString(), 'https://nav.tum.de/room/5500%2F01%3FA');
});

test('calendarUri rejects untrusted schemes', () {
final json = j('''
{
"id": "5606.EG.001",
"name": "Test Room",
"parent_names": ["Garching"],
"type": "room",
"type_common_name": "Room",
"props": {
"computed": [],
"calendar_url": "javascript:alert(1)"
},
"coords": {},
"maps": {"default": "rf000"}
}
''');
final details = NavigaTumNavigationDetails.fromJson(json);

expect(details.calendarUri, isNull);
});
});
}
Loading