diff --git a/packages/neon/neon/lib/src/models/account.dart b/packages/neon/neon/lib/src/models/account.dart index 4c91a3ff..a690483a 100644 --- a/packages/neon/neon/lib/src/models/account.dart +++ b/packages/neon/neon/lib/src/models/account.dart @@ -77,6 +77,28 @@ class Account implements Credentials { // Maybe also show path if it is not '/' ? return '$username@${uri.port != 443 ? '${uri.host}:${uri.port}' : uri.host}'; } + + /// Completes an incomplete [Uri] using the [serverURL]. + /// + /// Some Nextcloud APIs return [Uri]s to resources on the server (e.g. an image) but only give an absolute path. + /// Those [Uri]s need to be completed using the [serverURL] to have a working [Uri]. + /// + /// The paths of the [serverURL] and the [uri] need to be join to get the full path, unless the [uri] path is already an absolute path. + /// In that case an instance hosted at a sub folder will already contain the sub folder part in the [uri]. + Uri completeUri(final Uri uri) { + final result = Uri.parse(serverURL).replace( + queryParameters: uri.queryParameters, + fragment: uri.fragment, + ); + return result.replace( + path: uri.hasAbsolutePath ? uri.path : '${result.path}/${uri.path}', + ); + } + + /// Removes the [serverURL] part from the [uri]. + /// + /// Should be used when trying to push a [uri] from an API to the router as it might contain the scheme, host and sub path of the instance which will not work with the router. + Uri stripUri(final Uri uri) => Uri.parse(uri.toString().replaceFirst(serverURL, '')); } Map _idCache = {}; diff --git a/packages/neon/neon/test/account_test.dart b/packages/neon/neon/test/account_test.dart index 57b7c527..a86b934e 100644 --- a/packages/neon/neon/test/account_test.dart +++ b/packages/neon/neon/test/account_test.dart @@ -2,16 +2,16 @@ import 'package:neon/src/models/account.dart'; import 'package:test/test.dart'; void main() { - const qrCodePath = '/user:JohnDoe&password:super_secret&server:example.com'; - const qrCode = 'nc://login$qrCodePath'; - const invalidUrl = '::Not valid LoginQrcode::'; - const credentials = LoginQrcode( - serverURL: 'example.com', - username: 'JohnDoe', - password: 'super_secret', - ); - group('LoginQrcode', () { + const qrCodePath = '/user:JohnDoe&password:super_secret&server:example.com'; + const qrCode = 'nc://login$qrCodePath'; + const invalidUrl = '::Not valid LoginQrcode::'; + const credentials = LoginQrcode( + serverURL: 'example.com', + username: 'JohnDoe', + password: 'super_secret', + ); + test('parse', () { expect(LoginQrcode.tryParse(qrCode), equals(credentials)); expect(LoginQrcode.tryParse(qrCodePath), equals(credentials)); @@ -22,4 +22,42 @@ void main() { expect(credentials, equals(credentials)); }); }); + + group('URI', () { + const testURL = 'apps/test?123=456#789'; + + for (final (serverURL, path) in [ + ('http://localhost', ''), + ('http://localhost:443', ''), + ('http://localhost:443/nextcloud', '/nextcloud'), + ]) { + group(serverURL, () { + final account = Account( + serverURL: serverURL, + username: 'example', + ); + + test('Complete absolute path', () { + expect( + account.completeUri(Uri.parse('$path/$testURL')), + Uri.parse('$serverURL/$testURL'), + ); + }); + + test('Complete relative path', () { + expect( + account.completeUri(Uri.parse(testURL)), + Uri.parse('$serverURL/$testURL'), + ); + }); + + test('Strip', () { + expect( + account.stripUri(Uri.parse('$serverURL/$testURL')), + Uri.parse('/$testURL'), + ); + }); + }); + } + }); }