From ffbddd8f3a24737d00c0dc94cd636558d30e416d Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Sun, 4 May 2025 13:40:49 +0530 Subject: [PATCH] [client] Create publinks --- .../action_resource_publink_create.dart | 78 +++++++++++++++++++ .../lib/libphylum/actions/deserializers.dart | 2 + .../lib/ui/explorer/create_publink_view.dart | 6 +- .../lib/ui/explorer/resource_info_view.dart | 10 ++- 4 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 client/lib/libphylum/actions/action_resource_publink_create.dart diff --git a/client/lib/libphylum/actions/action_resource_publink_create.dart b/client/lib/libphylum/actions/action_resource_publink_create.dart new file mode 100644 index 00000000..5f2bc0ce --- /dev/null +++ b/client/lib/libphylum/actions/action_resource_publink_create.dart @@ -0,0 +1,78 @@ +import 'package:offtheline/offtheline.dart'; +import 'package:phylum/libphylum/actions/action_resource_create.dart'; +import 'package:phylum/libphylum/phylum_api_types.dart'; +import 'package:phylum/libphylum/responses/responses.dart'; + +import 'action_resource.dart'; + +class ResourcePublinkCreateAction extends ResourceAction with JsonApiAction { + static const kActionName = 'publinkCreate'; + @override + String get actionName => kActionName; + + @override + String get method => 'POST'; + + @override + String get endpoint => '/api/v1/fs/publinks/$resourceId/create'; + + @override + Map? get requestBody => { + 'name': publinkName, + if (password.isNotEmpty) 'password': password, + if (expires != null) 'expires': expires!.toIso8601String(), + if (accessLimit != 0) 'access_limit': accessLimit, + }; + + @override + ResponseParser get parseResponse => (_, response) => parseJsonMapResponse(response, EmptyResponse.fromResponse); + + @override + List get localChanges => []; + + @override + String get description => 'Creating Public Share: $publinkName'; + + @override + Map get props => { + 'resourceId': resourceId, + 'publinkName': resourceId, + 'password': password, + 'expires': expires?.millisecondsSinceEpoch, + 'accessLimit': accessLimit, + 'timestamp': timestamp.millisecondsSinceEpoch, + }; + + final String publinkName; + final String password; + final DateTime? expires; + final int accessLimit; + final DateTime timestamp; + + ResourcePublinkCreateAction({ + required super.resourceId, + required this.publinkName, + required this.password, + required DateTime? expires, + required this.accessLimit, + DateTime? timestamp, + }) : expires = expires?.toUtc(), + timestamp = timestamp ?? DateTime.now(); + + factory ResourcePublinkCreateAction.fromMap(Map map) { + return ResourcePublinkCreateAction( + resourceId: map['resourceId'], + publinkName: map['publinkName'], + password: map['password'], + expires: map['expires'] == null ? null : DateTime.fromMillisecondsSinceEpoch(map['expires']), + accessLimit: map['accessLimit'], + timestamp: DateTime.fromMillisecondsSinceEpoch(map['timestamp']), + ); + } + + @override + bool dependsOn(PhylumAction action) => + action is ResourceAction && + (action is ResourceCreateAction || action is ResourcePublinkCreateAction) && + action.resourceId == resourceId; +} diff --git a/client/lib/libphylum/actions/deserializers.dart b/client/lib/libphylum/actions/deserializers.dart index c7ad2acd..4b42631d 100644 --- a/client/lib/libphylum/actions/deserializers.dart +++ b/client/lib/libphylum/actions/deserializers.dart @@ -2,6 +2,7 @@ import 'package:phylum/libphylum/actions/action_resource_copy.dart'; import 'package:phylum/libphylum/actions/action_resource_delete.dart'; import 'package:phylum/libphylum/actions/action_resource_mkdir.dart'; import 'package:phylum/libphylum/actions/action_resource_move.dart'; +import 'package:phylum/libphylum/actions/action_resource_publink_create.dart'; import 'package:phylum/libphylum/actions/action_resource_restore.dart'; import 'package:phylum/libphylum/actions/action_resource_share.dart'; import 'package:phylum/libphylum/actions/action_resource_upload.dart'; @@ -16,6 +17,7 @@ const actionDeserializers = { ResourceMkdirAction.kActionName: ResourceMkdirAction.fromMap, ResourceMoveAction.kActionName: ResourceMoveAction.fromMap, ResourceRestoreAction.kActionName: ResourceRestoreAction.fromMap, + ResourcePublinkCreateAction.kActionName: ResourcePublinkCreateAction.fromMap, ResourceShareAction.kActionName: ResourceShareAction.fromMap, ResourceUploadAction.kActionName: ResourceUploadAction.fromMap, }; diff --git a/client/lib/ui/explorer/create_publink_view.dart b/client/lib/ui/explorer/create_publink_view.dart index 8ed2c791..56c5fdd3 100644 --- a/client/lib/ui/explorer/create_publink_view.dart +++ b/client/lib/ui/explorer/create_publink_view.dart @@ -3,6 +3,8 @@ import 'package:flutter/services.dart'; import 'package:phylum/util/time.dart'; import 'package:provider/provider.dart'; +final TextInputFormatter validNameFormatter = FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_\-]')); + class PublinkInfo with ChangeNotifier { String _name = ''; String get name => _name.trim(); @@ -26,7 +28,7 @@ class PublinkInfo with ChangeNotifier { } int? _accessLimit; - int? get accessLimit => _accessLimit; + int get accessLimit => _accessLimit ?? 0; set accessLimit(int? value) { _accessLimit = value; notifyListeners(); @@ -97,8 +99,10 @@ class _CreatePublinkViewState extends State { leading: const Icon(Icons.public), title: TextField( decoration: InputDecoration(label: Text('Name')), + inputFormatters: [validNameFormatter], enableSuggestions: false, autocorrect: false, + autofocus: true, onChanged: (value) => context.read().name = value, ), ), diff --git a/client/lib/ui/explorer/resource_info_view.dart b/client/lib/ui/explorer/resource_info_view.dart index 7c024e27..010b7379 100644 --- a/client/lib/ui/explorer/resource_info_view.dart +++ b/client/lib/ui/explorer/resource_info_view.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:offtheline/offtheline.dart'; import 'package:phylum/libphylum/actions/action_resource.dart'; +import 'package:phylum/libphylum/actions/action_resource_publink_create.dart'; import 'package:phylum/libphylum/db/db.dart'; import 'package:phylum/libphylum/phylum_account.dart'; import 'package:phylum/ui/common/responsive_dialog.dart'; @@ -111,9 +112,16 @@ class ResourceInfoView extends StatelessWidget { trailing: IconButton( icon: const Icon(Icons.add), onPressed: () async { + final account = context.read(); final info = await CreatePublinkView.show(context, resource.id); if (info == null) return; - print('Created'); + account.addAction(ResourcePublinkCreateAction( + resourceId: resource.id, + publinkName: info.name, + password: info.password, + expires: info.expiration, + accessLimit: info.accessLimit, + )); }, ), ),