Finish KeyToken operations
This commit is contained in:
112
flutter/lib/pages/keytoken_view/keytoken_channel_modal.dart
Normal file
112
flutter/lib/pages/keytoken_view/keytoken_channel_modal.dart
Normal file
@@ -0,0 +1,112 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:simplecloudnotifier/models/channel.dart';
|
||||
import 'package:simplecloudnotifier/models/keytoken.dart';
|
||||
|
||||
class EditKeyTokenChannelsDialog extends StatefulWidget {
|
||||
final List<Channel> ownedChannels;
|
||||
final KeyTokenPreview keytoken;
|
||||
|
||||
final void Function(Set<String>) onUpdateChannels;
|
||||
final void Function() onUpdateSetAllChannels;
|
||||
|
||||
const EditKeyTokenChannelsDialog({
|
||||
required this.ownedChannels,
|
||||
required this.keytoken,
|
||||
required this.onUpdateChannels,
|
||||
required this.onUpdateSetAllChannels,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_EditKeyTokenChannelsDialogState createState() => _EditKeyTokenChannelsDialogState();
|
||||
}
|
||||
|
||||
class _EditKeyTokenChannelsDialogState extends State<EditKeyTokenChannelsDialog> {
|
||||
late bool allChannels;
|
||||
late Set<String> selectedEntries;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
allChannels = widget.keytoken.allChannels;
|
||||
selectedEntries = (widget.keytoken.channels).toSet();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var ownChannels = widget.ownedChannels.toList();
|
||||
ownChannels.sort((a, b) => a.displayName.toLowerCase().compareTo(b.displayName.toLowerCase()));
|
||||
|
||||
return AlertDialog(
|
||||
title: const Text('Channels'),
|
||||
content: Container(
|
||||
width: 0,
|
||||
height: 400,
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
visualDensity: VisualDensity(horizontal: 0, vertical: -4),
|
||||
title: Text('All Channels'),
|
||||
leading: Icon(
|
||||
allChannels ? Icons.check_box : Icons.check_box_outline_blank,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
allChannels = !allChannels;
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
if (!allChannels)
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (builder, index) {
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
visualDensity: VisualDensity(horizontal: 0, vertical: -4),
|
||||
title: Text(ownChannels[index].displayName),
|
||||
leading: Icon(
|
||||
selectedEntries.contains(ownChannels[index].channelID) ? Icons.check_box : Icons.check_box_outline_blank,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (selectedEntries.contains(ownChannels[index].channelID)) {
|
||||
selectedEntries.remove(ownChannels[index].channelID);
|
||||
} else {
|
||||
selectedEntries.add(ownChannels[index].channelID);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
itemCount: ownChannels.length,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(textStyle: Theme.of(context).textTheme.labelLarge),
|
||||
child: const Text('Update'),
|
||||
onPressed: () {
|
||||
if (allChannels) {
|
||||
widget.onUpdateSetAllChannels();
|
||||
} else {
|
||||
widget.onUpdateChannels(selectedEntries);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:simplecloudnotifier/models/keytoken.dart';
|
||||
|
||||
class EditKeyTokenPermissionsDialog extends StatefulWidget {
|
||||
final KeyTokenPreview keytoken;
|
||||
|
||||
final void Function(String) onUpdatePermissions;
|
||||
|
||||
const EditKeyTokenPermissionsDialog({
|
||||
required this.keytoken,
|
||||
required this.onUpdatePermissions,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_EditKeyTokenPermissionsDialogState createState() => _EditKeyTokenPermissionsDialogState();
|
||||
}
|
||||
|
||||
class _EditKeyTokenPermissionsDialogState extends State<EditKeyTokenPermissionsDialog> {
|
||||
Set<String> selectedPermissions = new Set<String>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
for (var p in widget.keytoken.permissions.split(';')) {
|
||||
if (p.isNotEmpty) selectedPermissions.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Permissions'),
|
||||
content: Container(
|
||||
width: 0,
|
||||
height: 400,
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (builder, index) {
|
||||
final txt = (['Admin', 'Read messages', 'Send messages', 'Read userdata'])[index];
|
||||
final prm = (['A', 'CR', 'CS', 'UR'])[index];
|
||||
|
||||
return ListTile(
|
||||
contentPadding: EdgeInsets.fromLTRB(8, 0, 8, 0),
|
||||
visualDensity: VisualDensity(horizontal: 0, vertical: -4),
|
||||
title: Text(txt),
|
||||
leading: Icon(
|
||||
selectedPermissions.contains(prm) ? Icons.check_box : Icons.check_box_outline_blank,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (selectedPermissions.contains(prm)) {
|
||||
selectedPermissions.remove(prm);
|
||||
} else {
|
||||
selectedPermissions.add(prm);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
itemCount: 4,
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(textStyle: Theme.of(context).textTheme.labelLarge),
|
||||
child: const Text('Update'),
|
||||
onPressed: () {
|
||||
widget.onUpdatePermissions(selectedPermissions.join(';'));
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:simplecloudnotifier/api/api_client.dart';
|
||||
import 'package:simplecloudnotifier/components/error_display/error_display.dart';
|
||||
import 'package:simplecloudnotifier/components/layout/scaffold.dart';
|
||||
import 'package:simplecloudnotifier/models/channel.dart';
|
||||
import 'package:simplecloudnotifier/models/keytoken.dart';
|
||||
import 'package:simplecloudnotifier/models/user.dart';
|
||||
import 'package:simplecloudnotifier/pages/filtered_message_view/filtered_message_view.dart';
|
||||
import 'package:simplecloudnotifier/pages/keytoken_view/keytoken_channel_modal.dart';
|
||||
import 'package:simplecloudnotifier/pages/keytoken_view/keytoken_permission_modal.dart';
|
||||
import 'package:simplecloudnotifier/state/app_auth.dart';
|
||||
import 'package:simplecloudnotifier/state/app_bar_state.dart';
|
||||
import 'package:simplecloudnotifier/state/application_log.dart';
|
||||
import 'package:simplecloudnotifier/state/scn_data_cache.dart';
|
||||
import 'package:simplecloudnotifier/types/immediate_future.dart';
|
||||
import 'package:simplecloudnotifier/utils/dialogs.dart';
|
||||
import 'package:simplecloudnotifier/utils/navi.dart';
|
||||
import 'package:simplecloudnotifier/utils/toaster.dart';
|
||||
import 'package:simplecloudnotifier/utils/ui.dart';
|
||||
@@ -40,7 +47,11 @@ enum KeyTokenViewPageInitState { loading, okay, error }
|
||||
class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
static final _dateFormat = DateFormat('yyyy-MM-dd HH:mm'); //TODO setting
|
||||
|
||||
late ImmediateFuture<UserPreview> _futureOwner;
|
||||
ImmediateFuture<UserPreview> _futureOwner = ImmediateFuture.ofPending();
|
||||
|
||||
ImmediateFuture<Map<String, ChannelPreview>> _futureAllChannels = ImmediateFuture.ofPending();
|
||||
|
||||
ImmediateFuture<List<Channel>> _futureOwnedChannels = ImmediateFuture.ofPending();
|
||||
|
||||
final TextEditingController _ctrlName = TextEditingController();
|
||||
|
||||
@@ -55,6 +66,9 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
KeyTokenViewPageInitState loadingState = KeyTokenViewPageInitState.loading;
|
||||
String errorMessage = '';
|
||||
|
||||
KeyToken? keytokenUserAccAdmin;
|
||||
KeyToken? keytokenUserAccSend;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_initStateAsync(true);
|
||||
@@ -102,14 +116,48 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
if (this.keytokenPreview!.ownerUserID == userAcc.userID) {
|
||||
var cacheUser = userAcc.getUserOrNull();
|
||||
if (cacheUser != null) {
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofValue(cacheUser.toPreview());
|
||||
_futureOwner = ImmediateFuture.ofValue(cacheUser.toPreview());
|
||||
} else {
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofFuture(_getOwner(userAcc));
|
||||
_futureOwner = ImmediateFuture.ofFuture(_getOwner(userAcc));
|
||||
}
|
||||
} else {
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofFuture(APIClient.getUserPreview(userAcc, this.keytokenPreview!.ownerUserID));
|
||||
_futureOwner = ImmediateFuture.ofFuture(APIClient.getUserPreview(userAcc, this.keytokenPreview!.ownerUserID));
|
||||
}
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_futureAllChannels = ImmediateFuture.ofFuture(APIClient.getChannelList(userAcc, ChannelSelector.allAny).then((lst) async {
|
||||
Map<String, ChannelPreview> result = {};
|
||||
|
||||
for (var c in lst) result[c.channel.channelID] = c.channel.toPreview(c.subscription);
|
||||
|
||||
if (keytokenPreview != null) {
|
||||
for (var cid in keytokenPreview!.channels) {
|
||||
if (!result.containsKey(cid)) {
|
||||
result[cid] = await APIClient.getChannelPreview(userAcc, cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}));
|
||||
});
|
||||
|
||||
setState(() {
|
||||
_futureOwnedChannels = ImmediateFuture.ofFuture(APIClient.getChannelList(userAcc, ChannelSelector.owned).then((p) => p.map((c) => c.channel).toList()));
|
||||
});
|
||||
|
||||
SCNDataCache().getOrQueryTokenByValue(userAcc.userID!, userAcc.tokenAdmin!).then((token) {
|
||||
setState(() {
|
||||
keytokenUserAccAdmin = token;
|
||||
});
|
||||
});
|
||||
|
||||
SCNDataCache().getOrQueryTokenByValue(userAcc.userID!, userAcc.tokenSend!).then((token) {
|
||||
setState(() {
|
||||
keytokenUserAccSend = token;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -158,18 +206,22 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidIdCardClip,
|
||||
title: 'KeyTokenID',
|
||||
values: [keytoken.keytokenID],
|
||||
values: [
|
||||
keytoken.keytokenID,
|
||||
if (keytokenUserAccAdmin?.keytokenID == keytoken.keytokenID) '(Currently used as Admin-Token)',
|
||||
if (keytokenUserAccSend?.keytokenID == keytoken.keytokenID) '(Currently used as Send-Token)',
|
||||
],
|
||||
),
|
||||
_buildNameCard(context, true),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.clock,
|
||||
icon: FontAwesomeIcons.solidClock,
|
||||
title: 'Created',
|
||||
values: [_KeyTokenViewPageState._dateFormat.format(DateTime.parse(keytoken.timestampCreated).toLocal())],
|
||||
),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.clockTwo,
|
||||
icon: FontAwesomeIcons.solidClockTwo,
|
||||
title: 'Last Used',
|
||||
values: [(keytoken.timestampLastUsed == null) ? 'Never' : _KeyTokenViewPageState._dateFormat.format(DateTime.parse(keytoken.timestampLastUsed!).toLocal())],
|
||||
),
|
||||
@@ -297,7 +349,6 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
setState(() {
|
||||
_ctrlName.text = _nameOverride ?? keytokenPreview?.name ?? '';
|
||||
_editName = EditState.editing;
|
||||
if (_editName == EditState.editing) _editName = EditState.none;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -355,7 +406,7 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
if (isOwned) {
|
||||
w1 = UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.shieldKeyhole,
|
||||
icon: FontAwesomeIcons.solidShieldKeyhole,
|
||||
title: 'Permissions',
|
||||
values: _formatPermissions(keyToken.permissions),
|
||||
iconActions: [(FontAwesomeIcons.penToSquare, null, _editPermissions)],
|
||||
@@ -363,28 +414,53 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
} else {
|
||||
w1 = UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.shieldKeyhole,
|
||||
icon: FontAwesomeIcons.solidShieldKeyhole,
|
||||
title: 'Permissions',
|
||||
values: _formatPermissions(keyToken.permissions),
|
||||
);
|
||||
}
|
||||
|
||||
if (isOwned) {
|
||||
w2 = UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channels',
|
||||
values: (keyToken.allChannels) ? ['All Channels'] : keyToken.channels, //TODO show channel names
|
||||
iconActions: [(FontAwesomeIcons.penToSquare, null, _editChannels)],
|
||||
);
|
||||
} else {
|
||||
w2 = UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channels',
|
||||
values: (keyToken.allChannels) ? ['All Channels'] : keyToken.channels, //TODO show channel names
|
||||
);
|
||||
}
|
||||
w2 = FutureBuilder(
|
||||
future: _futureAllChannels.future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
var cmap = snapshot.data!;
|
||||
if (isOwned) {
|
||||
return UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channels',
|
||||
values: (keyToken.allChannels) ? (['All Channels']) : (keyToken.channels.isEmpty ? ['(None)'] : (keyToken.channels.map((c) => cmap[c]?.displayName ?? c).toList())),
|
||||
iconActions: [(FontAwesomeIcons.penToSquare, null, _editChannels)],
|
||||
);
|
||||
} else {
|
||||
return UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channels',
|
||||
values: (keyToken.allChannels) ? (['All Channels']) : (keyToken.channels.isEmpty ? ['(None)'] : (keyToken.channels.map((c) => cmap[c]?.displayName ?? c).toList())),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (isOwned) {
|
||||
return UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channels',
|
||||
values: (keyToken.allChannels) ? ['All Channels'] : (keyToken.channels.isEmpty ? ['(None)'] : keyToken.channels),
|
||||
iconActions: [(FontAwesomeIcons.penToSquare, null, _editChannels)],
|
||||
);
|
||||
} else {
|
||||
return UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channels',
|
||||
values: (keyToken.allChannels) ? ['All Channels'] : (keyToken.channels.isEmpty ? ['(None)'] : keyToken.channels),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return [w1, w2];
|
||||
}
|
||||
@@ -404,33 +480,138 @@ class _KeyTokenViewPageState extends State<KeyTokenViewPage> {
|
||||
return result;
|
||||
}
|
||||
|
||||
void _editPermissions() {
|
||||
void _editPermissions() async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
//TODO prevent editing current admin/read token
|
||||
if (keytokenUserAccAdmin == null || keytokenUserAccAdmin!.keytokenID == keytokenPreview!.keytokenID) {
|
||||
Toaster.error("Error", "You cannot edit the currently used token");
|
||||
return;
|
||||
}
|
||||
if (keytokenUserAccSend == null || keytokenUserAccSend!.keytokenID == keytokenPreview!.keytokenID) {
|
||||
Toaster.error("Error", "You cannot edit the currently used token");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
Toaster.info("Not implemented", "Currently not implemented");
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => EditKeyTokenPermissionsDialog(
|
||||
keytoken: keytokenPreview!,
|
||||
onUpdatePermissions: _updatePermissions,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _editChannels() {
|
||||
void _editChannels() async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
//TODO prevent editing current admin/read token
|
||||
if (keytokenUserAccAdmin == null || keytokenUserAccAdmin!.keytokenID == keytokenPreview!.keytokenID) {
|
||||
Toaster.error("Error", "You cannot edit the currently used token");
|
||||
return;
|
||||
}
|
||||
if (keytokenUserAccSend == null || keytokenUserAccSend!.keytokenID == keytokenPreview!.keytokenID) {
|
||||
Toaster.error("Error", "You cannot edit the currently used token");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO
|
||||
var ownChannels = (await _futureOwnedChannels.future);
|
||||
ownChannels.sort((a, b) => a.displayName.toLowerCase().compareTo(b.displayName.toLowerCase()));
|
||||
|
||||
Toaster.info("Not implemented", "Currently not implemented");
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => EditKeyTokenChannelsDialog(
|
||||
ownedChannels: ownChannels,
|
||||
keytoken: keytokenPreview!,
|
||||
onUpdateChannels: _updateChannelsSelected,
|
||||
onUpdateSetAllChannels: _updateChannelsAll,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _deleteKey() {
|
||||
void _deleteKey() async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
//TODO prevent deleting current admin/read token
|
||||
if (keytokenUserAccAdmin == null || keytokenUserAccAdmin!.keytokenID == keytokenPreview!.keytokenID) {
|
||||
Toaster.error("Error", "You cannot delete the currently used token");
|
||||
return;
|
||||
}
|
||||
if (keytokenUserAccSend == null || keytokenUserAccSend!.keytokenID == keytokenPreview!.keytokenID) {
|
||||
Toaster.error("Error", "You cannot delete the currently used token");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO
|
||||
try {
|
||||
final r = await UIDialogs.showConfirmDialog(context, 'Really (permanently) delete this Key?', okText: 'Unsubscribe', cancelText: 'Cancel');
|
||||
if (!r) return;
|
||||
|
||||
Toaster.info("Not implemented", "Currently not implemented");
|
||||
await APIClient.deleteKeyToken(acc, keytokenPreview!.keytokenID);
|
||||
widget.needsReload?.call();
|
||||
|
||||
Toaster.info('Logout', 'Successfully deleted the key');
|
||||
|
||||
Navi.pop(context);
|
||||
} catch (exc, trace) {
|
||||
Toaster.error("Error", 'Failed to delete key');
|
||||
ApplicationLog.error('Failed to delete key: ' + exc.toString(), trace: trace);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateChannelsSelected(Set<String> selectedEntries) async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
try {
|
||||
final r = await APIClient.updateKeyToken(acc, widget.keytokenID, channels: selectedEntries.toList(), allChannels: false);
|
||||
|
||||
setState(() {
|
||||
keytoken = r;
|
||||
keytokenPreview = r.toPreview();
|
||||
});
|
||||
|
||||
Toaster.info("Success", "Key updated");
|
||||
|
||||
widget.needsReload?.call();
|
||||
} catch (exc, trace) {
|
||||
ApplicationLog.error('Failed to update key: ' + exc.toString(), trace: trace);
|
||||
Toaster.error("Error", 'Failed to update key');
|
||||
}
|
||||
}
|
||||
|
||||
void _updateChannelsAll() async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
try {
|
||||
final r = await APIClient.updateKeyToken(acc, widget.keytokenID, channels: [], allChannels: true);
|
||||
|
||||
setState(() {
|
||||
keytoken = r;
|
||||
keytokenPreview = r.toPreview();
|
||||
});
|
||||
|
||||
Toaster.info("Success", "Key updated");
|
||||
|
||||
widget.needsReload?.call();
|
||||
} catch (exc, trace) {
|
||||
ApplicationLog.error('Failed to update key: ' + exc.toString(), trace: trace);
|
||||
Toaster.error("Error", 'Failed to update key');
|
||||
}
|
||||
}
|
||||
|
||||
void _updatePermissions(String perm) async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
try {
|
||||
final r = await APIClient.updateKeyToken(acc, widget.keytokenID, permissions: perm);
|
||||
|
||||
setState(() {
|
||||
keytoken = r;
|
||||
keytokenPreview = r.toPreview();
|
||||
});
|
||||
|
||||
Toaster.info("Success", "Key updated");
|
||||
|
||||
widget.needsReload?.call();
|
||||
} catch (exc, trace) {
|
||||
ApplicationLog.error('Failed to update key: ' + exc.toString(), trace: trace);
|
||||
Toaster.error("Error", 'Failed to update key');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user