diff --git a/client/lib/libphylum/actions/action_resource_share.dart b/client/lib/libphylum/actions/action_resource_share.dart index d29f0a1f..d3e1e9c4 100644 --- a/client/lib/libphylum/actions/action_resource_share.dart +++ b/client/lib/libphylum/actions/action_resource_share.dart @@ -1,5 +1,6 @@ import 'package:offtheline/offtheline.dart'; import 'package:phylum/libphylum/actions/changes/update_resource_permissions_change.dart'; +import 'package:phylum/libphylum/db/db.dart'; import 'package:phylum/libphylum/phylum_api_types.dart'; import 'action_resource.dart'; @@ -19,7 +20,7 @@ class ResourceShareAction extends ResourceAction with JsonApiAction { @override Map? get requestBody => { 'path': '$resourceId:', - 'username': username, + 'email': userEmail, 'permission': permission, }; @@ -27,7 +28,7 @@ class ResourceShareAction extends ResourceAction with JsonApiAction { List get localChanges => [ UpdateResourcePermissionsChange( objectId: resourceId, - username: username, + userId: userId, permission: permission, timestamp: modified, ), @@ -39,19 +40,22 @@ class ResourceShareAction extends ResourceAction with JsonApiAction { @override Map get props => { 'resourceId': resourceId, - 'username': username, + 'userId': userId, + 'userEmail': userEmail, 'permission': permission, 'modified': modified.millisecondsSinceEpoch, 'description': description, }; - final String username; + final int userId; + final String userEmail; final int permission; final DateTime modified; ResourceShareAction._({ required super.resourceId, - required this.username, + required this.userId, + required this.userEmail, required this.permission, required this.modified, required this.description, @@ -60,20 +64,22 @@ class ResourceShareAction extends ResourceAction with JsonApiAction { ResourceShareAction({ required String resourceId, required String resourceName, - required String username, + required User user, required int permission, }) : this._( resourceId: resourceId, - username: username, + userId: user.id, + userEmail: user.email, permission: permission, modified: DateTime.now(), - description: 'Sharing $resourceName with $username', + description: 'Sharing $resourceName with ${user.displayName}', ); static ResourceShareAction fromMap(Map map) { return ResourceShareAction._( resourceId: map['resourceId'], - username: map['username'], + userId: map['userId'], + userEmail: map['userEmail'], permission: map['permission'], modified: DateTime.fromMillisecondsSinceEpoch(map['modified']), description: map['description'], @@ -83,5 +89,5 @@ class ResourceShareAction extends ResourceAction with JsonApiAction { @override bool dependsOn(PhylumAction action) => (action is ResourceCreateAction && action.resourceId == resourceId) || - (action is ResourceShareAction && action.resourceId == resourceId && action.username == username); + (action is ResourceShareAction && action.resourceId == resourceId && action.userEmail == userEmail); } diff --git a/client/lib/libphylum/actions/changes/update_resource_permissions_change.dart b/client/lib/libphylum/actions/changes/update_resource_permissions_change.dart index e41fd0d5..fdb203c8 100644 --- a/client/lib/libphylum/actions/changes/update_resource_permissions_change.dart +++ b/client/lib/libphylum/actions/changes/update_resource_permissions_change.dart @@ -7,7 +7,7 @@ import 'package:phylum/libphylum/db/db.dart'; class UpdateResourcePermissionsChange extends LocalChange { @override final String objectId; - final String username; + final int userId; final int permission; final DateTime timestamp; @@ -16,7 +16,7 @@ class UpdateResourcePermissionsChange extends LocalChange { const UpdateResourcePermissionsChange({ required this.objectId, - required this.username, + required this.userId, required this.permission, required this.timestamp, }); @@ -24,22 +24,22 @@ class UpdateResourcePermissionsChange extends LocalChange { @override Resource? apply(Resource? data) { if (data == null) return null; - var p = data.grants == null ? const {} : (jsonDecode(data.grants!) as Map).cast(); - if ((p[username]?['p'] ?? 0) == permission) { + var p = data.grants == null ? const {} : (jsonDecode(data.grants!) as Map).cast(); + if ((p[userId]?['p'] ?? 0) == permission) { return data; } if (permission == 0) { - p.remove(username); + p.remove(userId); } else if (p.isEmpty) { // Empty means const map, so we can't add to it p = { - username: { + userId: { 'p': permission, 't': DateTime.now().millisecondsSinceEpoch, }, }; } else { - p[username] = { + p[userId] = { 'p': permission, 't': DateTime.now().millisecondsSinceEpoch, }; diff --git a/client/lib/libphylum/db/db.g.dart b/client/lib/libphylum/db/db.g.dart index d6beeac8..29f84cb0 100644 --- a/client/lib/libphylum/db/db.g.dart +++ b/client/lib/libphylum/db/db.g.dart @@ -8,22 +8,27 @@ class Users extends Table with TableInfo { final GeneratedDatabase attachedDatabase; final String? _alias; Users(this.attachedDatabase, [this._alias]); - static const VerificationMeta _usernameMeta = - const VerificationMeta('username'); - late final GeneratedColumn username = GeneratedColumn( - 'username', aliasedName, false, + static const VerificationMeta _idMeta = const VerificationMeta('id'); + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, + type: DriftSqlType.int, + requiredDuringInsert: false, + $customConstraints: 'NOT NULL PRIMARY KEY'); + static const VerificationMeta _emailMeta = const VerificationMeta('email'); + late final GeneratedColumn email = GeneratedColumn( + 'email', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true, - $customConstraints: 'NOT NULL PRIMARY KEY'); - static const VerificationMeta _displayMeta = - const VerificationMeta('display'); - late final GeneratedColumn display = GeneratedColumn( - 'display', aliasedName, false, + $customConstraints: 'NOT NULL'); + static const VerificationMeta _displayNameMeta = + const VerificationMeta('displayName'); + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', aliasedName, false, type: DriftSqlType.string, requiredDuringInsert: true, $customConstraints: 'NOT NULL'); @override - List get $columns => [username, display]; + List get $columns => [id, email, displayName]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -34,31 +39,38 @@ class Users extends Table with TableInfo { {bool isInserting = false}) { final context = VerificationContext(); final data = instance.toColumns(true); - if (data.containsKey('username')) { - context.handle(_usernameMeta, - username.isAcceptableOrUnknown(data['username']!, _usernameMeta)); - } else if (isInserting) { - context.missing(_usernameMeta); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); } - if (data.containsKey('display')) { - context.handle(_displayMeta, - display.isAcceptableOrUnknown(data['display']!, _displayMeta)); + if (data.containsKey('email')) { + context.handle( + _emailMeta, email.isAcceptableOrUnknown(data['email']!, _emailMeta)); } else if (isInserting) { - context.missing(_displayMeta); + context.missing(_emailMeta); + } + if (data.containsKey('display_name')) { + context.handle( + _displayNameMeta, + displayName.isAcceptableOrUnknown( + data['display_name']!, _displayNameMeta)); + } else if (isInserting) { + context.missing(_displayNameMeta); } return context; } @override - Set get $primaryKey => {username}; + Set get $primaryKey => {id}; @override User map(Map data, {String? tablePrefix}) { final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; return User( - username: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}username'])!, - display: attachedDatabase.typeMapping - .read(DriftSqlType.string, data['${effectivePrefix}display'])!, + id: attachedDatabase.typeMapping + .read(DriftSqlType.int, data['${effectivePrefix}id'])!, + email: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}email'])!, + displayName: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}display_name'])!, ); } @@ -72,21 +84,25 @@ class Users extends Table with TableInfo { } class User extends DataClass implements Insertable { - final String username; - final String display; - const User({required this.username, required this.display}); + final int id; + final String email; + final String displayName; + const User( + {required this.id, required this.email, required this.displayName}); @override Map toColumns(bool nullToAbsent) { final map = {}; - map['username'] = Variable(username); - map['display'] = Variable(display); + map['id'] = Variable(id); + map['email'] = Variable(email); + map['display_name'] = Variable(displayName); return map; } UsersCompanion toCompanion(bool nullToAbsent) { return UsersCompanion( - username: Value(username), - display: Value(display), + id: Value(id), + email: Value(email), + displayName: Value(displayName), ); } @@ -94,96 +110,103 @@ class User extends DataClass implements Insertable { {ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return User( - username: serializer.fromJson(json['username']), - display: serializer.fromJson(json['display']), + id: serializer.fromJson(json['id']), + email: serializer.fromJson(json['email']), + displayName: serializer.fromJson(json['display_name']), ); } @override Map toJson({ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return { - 'username': serializer.toJson(username), - 'display': serializer.toJson(display), + 'id': serializer.toJson(id), + 'email': serializer.toJson(email), + 'display_name': serializer.toJson(displayName), }; } - User copyWith({String? username, String? display}) => User( - username: username ?? this.username, - display: display ?? this.display, + User copyWith({int? id, String? email, String? displayName}) => User( + id: id ?? this.id, + email: email ?? this.email, + displayName: displayName ?? this.displayName, ); User copyWithCompanion(UsersCompanion data) { return User( - username: data.username.present ? data.username.value : this.username, - display: data.display.present ? data.display.value : this.display, + id: data.id.present ? data.id.value : this.id, + email: data.email.present ? data.email.value : this.email, + displayName: + data.displayName.present ? data.displayName.value : this.displayName, ); } @override String toString() { return (StringBuffer('User(') - ..write('username: $username, ') - ..write('display: $display') + ..write('id: $id, ') + ..write('email: $email, ') + ..write('displayName: $displayName') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(username, display); + int get hashCode => Object.hash(id, email, displayName); @override bool operator ==(Object other) => identical(this, other) || (other is User && - other.username == this.username && - other.display == this.display); + other.id == this.id && + other.email == this.email && + other.displayName == this.displayName); } class UsersCompanion extends UpdateCompanion { - final Value username; - final Value display; - final Value rowid; + final Value id; + final Value email; + final Value displayName; const UsersCompanion({ - this.username = const Value.absent(), - this.display = const Value.absent(), - this.rowid = const Value.absent(), + this.id = const Value.absent(), + this.email = const Value.absent(), + this.displayName = const Value.absent(), }); UsersCompanion.insert({ - required String username, - required String display, - this.rowid = const Value.absent(), - }) : username = Value(username), - display = Value(display); + this.id = const Value.absent(), + required String email, + required String displayName, + }) : email = Value(email), + displayName = Value(displayName); static Insertable custom({ - Expression? username, - Expression? display, - Expression? rowid, + Expression? id, + Expression? email, + Expression? displayName, }) { return RawValuesInsertable({ - if (username != null) 'username': username, - if (display != null) 'display': display, - if (rowid != null) 'rowid': rowid, + if (id != null) 'id': id, + if (email != null) 'email': email, + if (displayName != null) 'display_name': displayName, }); } UsersCompanion copyWith( - {Value? username, Value? display, Value? rowid}) { + {Value? id, Value? email, Value? displayName}) { return UsersCompanion( - username: username ?? this.username, - display: display ?? this.display, - rowid: rowid ?? this.rowid, + id: id ?? this.id, + email: email ?? this.email, + displayName: displayName ?? this.displayName, ); } @override Map toColumns(bool nullToAbsent) { final map = {}; - if (username.present) { - map['username'] = Variable(username.value); + if (id.present) { + map['id'] = Variable(id.value); } - if (display.present) { - map['display'] = Variable(display.value); + if (email.present) { + map['email'] = Variable(email.value); } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); + if (displayName.present) { + map['display_name'] = Variable(displayName.value); } return map; } @@ -191,9 +214,9 @@ class UsersCompanion extends UpdateCompanion { @override String toString() { return (StringBuffer('UsersCompanion(') - ..write('username: $username, ') - ..write('display: $display, ') - ..write('rowid: $rowid') + ..write('id: $id, ') + ..write('email: $email, ') + ..write('displayName: $displayName') ..write(')')) .toString(); } @@ -2325,14 +2348,14 @@ abstract class _$AppDatabase extends GeneratedDatabase { } typedef $UsersCreateCompanionBuilder = UsersCompanion Function({ - required String username, - required String display, - Value rowid, + Value id, + required String email, + required String displayName, }); typedef $UsersUpdateCompanionBuilder = UsersCompanion Function({ - Value username, - Value display, - Value rowid, + Value id, + Value email, + Value displayName, }); class $UsersFilterComposer extends Composer<_$AppDatabase, Users> { @@ -2343,11 +2366,14 @@ class $UsersFilterComposer extends Composer<_$AppDatabase, Users> { super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - ColumnFilters get username => $composableBuilder( - column: $table.username, builder: (column) => ColumnFilters(column)); + ColumnFilters get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnFilters(column)); - ColumnFilters get display => $composableBuilder( - column: $table.display, builder: (column) => ColumnFilters(column)); + ColumnFilters get email => $composableBuilder( + column: $table.email, builder: (column) => ColumnFilters(column)); + + ColumnFilters get displayName => $composableBuilder( + column: $table.displayName, builder: (column) => ColumnFilters(column)); } class $UsersOrderingComposer extends Composer<_$AppDatabase, Users> { @@ -2358,11 +2384,14 @@ class $UsersOrderingComposer extends Composer<_$AppDatabase, Users> { super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - ColumnOrderings get username => $composableBuilder( - column: $table.username, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get id => $composableBuilder( + column: $table.id, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get display => $composableBuilder( - column: $table.display, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get email => $composableBuilder( + column: $table.email, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get displayName => $composableBuilder( + column: $table.displayName, builder: (column) => ColumnOrderings(column)); } class $UsersAnnotationComposer extends Composer<_$AppDatabase, Users> { @@ -2373,11 +2402,14 @@ class $UsersAnnotationComposer extends Composer<_$AppDatabase, Users> { super.$addJoinBuilderToRootComposer, super.$removeJoinBuilderFromRootComposer, }); - GeneratedColumn get username => - $composableBuilder(column: $table.username, builder: (column) => column); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); - GeneratedColumn get display => - $composableBuilder(column: $table.display, builder: (column) => column); + GeneratedColumn get email => + $composableBuilder(column: $table.email, builder: (column) => column); + + GeneratedColumn get displayName => $composableBuilder( + column: $table.displayName, builder: (column) => column); } class $UsersTableManager extends RootTableManager< @@ -2403,24 +2435,24 @@ class $UsersTableManager extends RootTableManager< createComputedFieldComposer: () => $UsersAnnotationComposer($db: db, $table: table), updateCompanionCallback: ({ - Value username = const Value.absent(), - Value display = const Value.absent(), - Value rowid = const Value.absent(), + Value id = const Value.absent(), + Value email = const Value.absent(), + Value displayName = const Value.absent(), }) => UsersCompanion( - username: username, - display: display, - rowid: rowid, + id: id, + email: email, + displayName: displayName, ), createCompanionCallback: ({ - required String username, - required String display, - Value rowid = const Value.absent(), + Value id = const Value.absent(), + required String email, + required String displayName, }) => UsersCompanion.insert( - username: username, - display: display, - rowid: rowid, + id: id, + email: email, + displayName: displayName, ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), BaseReferences(db, table, e))) diff --git a/client/lib/libphylum/db/sql/users.drift b/client/lib/libphylum/db/sql/users.drift index 7851c01e..e45f19c6 100644 --- a/client/lib/libphylum/db/sql/users.drift +++ b/client/lib/libphylum/db/sql/users.drift @@ -1,4 +1,5 @@ CREATE TABLE IF NOT EXISTS users( - username TEXT NOT NULL PRIMARY KEY, - display TEXT NOT NULL + id INTEGER NOT NULL PRIMARY KEY, + email TEXT NOT NULL, + display_name TEXT NOT NULL ); \ No newline at end of file diff --git a/client/lib/libphylum/phylum_account.dart b/client/lib/libphylum/phylum_account.dart index d438a469..14356d26 100644 --- a/client/lib/libphylum/phylum_account.dart +++ b/client/lib/libphylum/phylum_account.dart @@ -13,7 +13,7 @@ import 'package:phylum/util/logging.dart'; const _persistKeyAccessToken = 'accessToken'; const _persistKeyUserId = 'userId'; const _persistKeyUserEmail = 'userEmail'; -const _persistKeyUserName = 'userDisplayName'; +const _persistKeyUserDisplayName = 'userDisplayName'; const _persistKeyUserHome = 'userHome'; const _persistKeyUserPermissions = 'userPermissions'; @@ -54,9 +54,9 @@ class PhylumAccount extends Account { persist(_persistKeyUserEmail, value); } - String get userName => getPersisted(_persistKeyUserName); - set userName(String value) { - persist(_persistKeyUserName, value); + String get userDisplayName => getPersisted(_persistKeyUserDisplayName); + set userDisplayName(String value) { + persist(_persistKeyUserDisplayName, value); } String get userHome => getPersisted(_persistKeyUserHome); @@ -121,9 +121,11 @@ class PhylumAccount extends Account { await account.initialized; final userMap = response['user']; - account.userEmail = userMap['username']; - account.userName = userMap['display']; + account.userEmail = userMap['email']; + account.userDisplayName = userMap['display_name']; + account.userId = userMap['id']; account.userHome = userMap['home']; + account.userPermissions = userMap['permissions']; return account; } diff --git a/client/lib/libphylum/repositories/user_repository.dart b/client/lib/libphylum/repositories/user_repository.dart index cee59ea2..91a07443 100644 --- a/client/lib/libphylum/repositories/user_repository.dart +++ b/client/lib/libphylum/repositories/user_repository.dart @@ -7,8 +7,8 @@ import 'package:phylum/libphylum/responses/responses.dart'; class UserRepository { final PhylumAccount account; - Map _users = const {}; - Map get users => _users; + Map _users = const {}; + Map get users => _users; UserRepository({required this.account}); @@ -17,7 +17,7 @@ class UserRepository { await account.db.users .select() .get() - .then((users) => _users = Map.unmodifiable(Map.fromIterable(users, key: (u) => u.username))); + .then((users) => _users = Map.unmodifiable(Map.fromIterable(users, key: (u) => u.id))); } Future refresh() async { @@ -25,12 +25,12 @@ class UserRepository { UsersListRequest(), (request, response) => parseJsonMapResponse(response, UserListResponse.fromResponse), callback: (request, response) async { if (response is UserListResponse) { - _users = Map.unmodifiable(Map.fromIterable(response.users, key: (u) => u.username)); + _users = Map.unmodifiable(Map.fromIterable(response.users, key: (u) => u.id)); } }); } - String getUserDisplayName(String username) { - return _users[username]?.display ?? username; + String getUserDisplayName(int userId) { + return _users[userId]?.displayName ?? 'Unknown User ($userId)'; } } diff --git a/client/lib/libphylum/responses/resource_response.dart b/client/lib/libphylum/responses/resource_response.dart index e0da746e..53922533 100644 --- a/client/lib/libphylum/responses/resource_response.dart +++ b/client/lib/libphylum/responses/resource_response.dart @@ -40,7 +40,7 @@ class ResourceResponse extends PhylumApiSuccessResponse { } void _updateUserPermissions(PhylumAccount account) { - _resource = _resource.copyWith(userPermission: permissions[account.userEmail] ?? 0); + _resource = _resource.copyWith(userPermission: permissions[account.userId.toString()] ?? 0); } @override diff --git a/client/lib/libphylum/responses/user_list_response.dart b/client/lib/libphylum/responses/user_list_response.dart index 7cfa939f..62d8842b 100644 --- a/client/lib/libphylum/responses/user_list_response.dart +++ b/client/lib/libphylum/responses/user_list_response.dart @@ -14,8 +14,9 @@ class UserListResponse extends PhylumApiSuccessResponse { factory UserListResponse.fromResponse(Map data) { final users = (data["users"] as List).cast().map((u) => User( - username: u['username'], - display: u['display'], + id: u['id'], + email: u['email'], + displayName: u['display_name'], )); return UserListResponse(users: users); } diff --git a/client/lib/ui/explorer/resource_permissions_view.dart b/client/lib/ui/explorer/resource_permissions_view.dart index 39c72326..3a18e78c 100644 --- a/client/lib/ui/explorer/resource_permissions_view.dart +++ b/client/lib/ui/explorer/resource_permissions_view.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:drift/drift.dart' show TableOrViewStatements; import 'package:flutter/material.dart'; import 'package:phylum/libphylum/actions/action_resource_share.dart'; import 'package:phylum/libphylum/db/resource_helpers.dart'; @@ -19,8 +20,8 @@ class ResourcePermissionsView extends StatefulWidget { class _ResourcePermissionsViewState extends State { String? resourceName; - Map? permissions; - Map? grants; + Map? permissions; + Map? grants; Permission? userPermission; StreamSubscription? sub; @@ -75,11 +76,11 @@ class _ResourcePermissionsViewState extends State { final users = account.userRepository.users.entries.where((e) => !grants.containsKey(e.key)).map((e) => e.value); final user = await showOptionsDialogBuilder( - context, users.toList(growable: false), (user) => ListTile(title: Text(user.display)), + context, users.toList(growable: false), (user) => ListTile(title: Text(user.displayName)), filterList: (u, q) { final query = q.toLowerCase(); return u - .where((u) => u.username.contains(query) || u.display.contains(query)) + .where((u) => u.email.contains(query) || u.displayName.contains(query)) .toList(growable: false); }); if (user == null || !context.mounted) return; @@ -96,7 +97,7 @@ class _ResourcePermissionsViewState extends State { account.addAction(ResourceShareAction( resourceId: widget.resourceId, resourceName: resourceName!, - username: user.username, + user: user, permission: permission, )); }, @@ -112,15 +113,19 @@ class _ResourcePermissionsViewState extends State { value: e.value, onChanged: (userPermission! & permissionShare) == 0 ? null - : (value) { + : (value) async { if (value == null || value == e.value) return; if (value == permissions[e.key]) { value = 0; } + final user = + await (account.db.users.select()..where((u) => u.id.equals(e.key))).getSingleOrNull(); + if (user == null) return; + account.addAction(ResourceShareAction( resourceId: widget.resourceId, resourceName: resourceName!, - username: e.key, + user: user, permission: value, )); }, diff --git a/client/lib/ui/login/login_page.dart b/client/lib/ui/login/login_page.dart index 8aec5f1e..99d1d271 100644 --- a/client/lib/ui/login/login_page.dart +++ b/client/lib/ui/login/login_page.dart @@ -21,7 +21,7 @@ class LoginPage extends StatefulWidget { class _LoginPageState extends State { final Client _client = Client(); - String _username = ''; + String _email = ''; String _password = ''; Uri? serverUrl = kIsWeb ? Uri() : null; String? urlError; @@ -35,7 +35,7 @@ class _LoginPageState extends State { super.initState(); } - void _performLogin(BuildContext context, String username, String password) async { + void _performLogin(BuildContext context, String email, String password) async { final serverUrl = this.serverUrl; if (!serverUrlValid) return; final builder = serverUrl == null ? UriBuilder() : UriBuilder.fromUri(serverUrl); @@ -49,7 +49,7 @@ class _LoginPageState extends State { ); builder.path = '${builder.path}/api/v1/auth/password'; final request = MultipartRequest('post', builder.build()); - request.fields['username'] = username; + request.fields['email'] = email; request.fields['password'] = password; try { @@ -124,12 +124,12 @@ class _LoginPageState extends State { ), TextField( decoration: const InputDecoration( - label: Text('Username'), + label: Text('Email'), ), keyboardType: TextInputType.emailAddress, onChanged: (value) { setState(() { - _username = value.trim(); + _email = value.trim(); }); }, ), @@ -145,15 +145,15 @@ class _LoginPageState extends State { }); }, onSubmitted: (value) { - _performLogin(context, _username, _password); + _performLogin(context, _email, _password); }, ), Padding( padding: const EdgeInsets.only(top: 16.0), child: ElevatedButton( - onPressed: serverUrlValid && _username.isNotEmpty + onPressed: serverUrlValid && _email.isNotEmpty ? () async { - _performLogin(context, _username, _password); + _performLogin(context, _email, _password); } : null, child: const Text('Login'), diff --git a/client/lib/util/permissions.dart b/client/lib/util/permissions.dart index cded49c2..a2fd206a 100644 --- a/client/lib/util/permissions.dart +++ b/client/lib/util/permissions.dart @@ -13,8 +13,9 @@ const Permission permissionSetReadWrite = permissionRead | permissionWrite; const Permission permissionSetReadWriteShare = permissionRead | permissionWrite | permissionShare; extension PermissionMapper on String? { - Map parsePermissionMap() => - this == null ? {} : (jsonDecode(this!) as Map).cast(); + Map parsePermissionMap() => this == null + ? {} + : (jsonDecode(this!) as Map).cast().map((k, v) => MapEntry(int.parse(k), v)); // Map parseGrantsMap() => this == null // ? {}