mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-05 02:59:57 -06:00
[client] Use user id and email
This commit is contained in:
@@ -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<String, dynamic>? get requestBody => {
|
||||
'path': '$resourceId:',
|
||||
'username': username,
|
||||
'email': userEmail,
|
||||
'permission': permission,
|
||||
};
|
||||
|
||||
@@ -27,7 +28,7 @@ class ResourceShareAction extends ResourceAction with JsonApiAction {
|
||||
List<LocalChange> 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<String, dynamic> 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<String, dynamic> 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);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'package:phylum/libphylum/db/db.dart';
|
||||
class UpdateResourcePermissionsChange extends LocalChange<Resource> {
|
||||
@override
|
||||
final String objectId;
|
||||
final String username;
|
||||
final int userId;
|
||||
final int permission;
|
||||
final DateTime timestamp;
|
||||
|
||||
@@ -16,7 +16,7 @@ class UpdateResourcePermissionsChange extends LocalChange<Resource> {
|
||||
|
||||
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<Resource> {
|
||||
@override
|
||||
Resource? apply(Resource? data) {
|
||||
if (data == null) return null;
|
||||
var p = data.grants == null ? const <String, Map>{} : (jsonDecode(data.grants!) as Map).cast<String, Map>();
|
||||
if ((p[username]?['p'] ?? 0) == permission) {
|
||||
var p = data.grants == null ? const <int, Map>{} : (jsonDecode(data.grants!) as Map).cast<int, Map>();
|
||||
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: <String, int>{
|
||||
userId: <String, int>{
|
||||
'p': permission,
|
||||
't': DateTime.now().millisecondsSinceEpoch,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
p[username] = <String, int>{
|
||||
p[userId] = <String, int>{
|
||||
'p': permission,
|
||||
't': DateTime.now().millisecondsSinceEpoch,
|
||||
};
|
||||
|
||||
@@ -8,22 +8,27 @@ class Users extends Table with TableInfo<Users, User> {
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
static const VerificationMeta _usernameMeta =
|
||||
const VerificationMeta('username');
|
||||
late final GeneratedColumn<String> username = GeneratedColumn<String>(
|
||||
'username', aliasedName, false,
|
||||
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL PRIMARY KEY');
|
||||
static const VerificationMeta _emailMeta = const VerificationMeta('email');
|
||||
late final GeneratedColumn<String> email = GeneratedColumn<String>(
|
||||
'email', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL PRIMARY KEY');
|
||||
static const VerificationMeta _displayMeta =
|
||||
const VerificationMeta('display');
|
||||
late final GeneratedColumn<String> display = GeneratedColumn<String>(
|
||||
'display', aliasedName, false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
static const VerificationMeta _displayNameMeta =
|
||||
const VerificationMeta('displayName');
|
||||
late final GeneratedColumn<String> displayName = GeneratedColumn<String>(
|
||||
'display_name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [username, display];
|
||||
List<GeneratedColumn> get $columns => [id, email, displayName];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
@@ -34,31 +39,38 @@ class Users extends Table with TableInfo<Users, User> {
|
||||
{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<GeneratedColumn> get $primaryKey => {username};
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
User map(Map<String, dynamic> 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<Users, User> {
|
||||
}
|
||||
|
||||
class User extends DataClass implements Insertable<User> {
|
||||
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<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['username'] = Variable<String>(username);
|
||||
map['display'] = Variable<String>(display);
|
||||
map['id'] = Variable<int>(id);
|
||||
map['email'] = Variable<String>(email);
|
||||
map['display_name'] = Variable<String>(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<User> {
|
||||
{ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return User(
|
||||
username: serializer.fromJson<String>(json['username']),
|
||||
display: serializer.fromJson<String>(json['display']),
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
email: serializer.fromJson<String>(json['email']),
|
||||
displayName: serializer.fromJson<String>(json['display_name']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'username': serializer.toJson<String>(username),
|
||||
'display': serializer.toJson<String>(display),
|
||||
'id': serializer.toJson<int>(id),
|
||||
'email': serializer.toJson<String>(email),
|
||||
'display_name': serializer.toJson<String>(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<User> {
|
||||
final Value<String> username;
|
||||
final Value<String> display;
|
||||
final Value<int> rowid;
|
||||
final Value<int> id;
|
||||
final Value<String> email;
|
||||
final Value<String> 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<User> custom({
|
||||
Expression<String>? username,
|
||||
Expression<String>? display,
|
||||
Expression<int>? rowid,
|
||||
Expression<int>? id,
|
||||
Expression<String>? email,
|
||||
Expression<String>? 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<String>? username, Value<String>? display, Value<int>? rowid}) {
|
||||
{Value<int>? id, Value<String>? email, Value<String>? 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<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (username.present) {
|
||||
map['username'] = Variable<String>(username.value);
|
||||
if (id.present) {
|
||||
map['id'] = Variable<int>(id.value);
|
||||
}
|
||||
if (display.present) {
|
||||
map['display'] = Variable<String>(display.value);
|
||||
if (email.present) {
|
||||
map['email'] = Variable<String>(email.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
if (displayName.present) {
|
||||
map['display_name'] = Variable<String>(displayName.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -191,9 +214,9 @@ class UsersCompanion extends UpdateCompanion<User> {
|
||||
@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<int> rowid,
|
||||
Value<int> id,
|
||||
required String email,
|
||||
required String displayName,
|
||||
});
|
||||
typedef $UsersUpdateCompanionBuilder = UsersCompanion Function({
|
||||
Value<String> username,
|
||||
Value<String> display,
|
||||
Value<int> rowid,
|
||||
Value<int> id,
|
||||
Value<String> email,
|
||||
Value<String> displayName,
|
||||
});
|
||||
|
||||
class $UsersFilterComposer extends Composer<_$AppDatabase, Users> {
|
||||
@@ -2343,11 +2366,14 @@ class $UsersFilterComposer extends Composer<_$AppDatabase, Users> {
|
||||
super.$addJoinBuilderToRootComposer,
|
||||
super.$removeJoinBuilderFromRootComposer,
|
||||
});
|
||||
ColumnFilters<String> get username => $composableBuilder(
|
||||
column: $table.username, builder: (column) => ColumnFilters(column));
|
||||
ColumnFilters<int> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get display => $composableBuilder(
|
||||
column: $table.display, builder: (column) => ColumnFilters(column));
|
||||
ColumnFilters<String> get email => $composableBuilder(
|
||||
column: $table.email, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> 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<String> get username => $composableBuilder(
|
||||
column: $table.username, builder: (column) => ColumnOrderings(column));
|
||||
ColumnOrderings<int> get id => $composableBuilder(
|
||||
column: $table.id, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get display => $composableBuilder(
|
||||
column: $table.display, builder: (column) => ColumnOrderings(column));
|
||||
ColumnOrderings<String> get email => $composableBuilder(
|
||||
column: $table.email, builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> 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<String> get username =>
|
||||
$composableBuilder(column: $table.username, builder: (column) => column);
|
||||
GeneratedColumn<int> get id =>
|
||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get display =>
|
||||
$composableBuilder(column: $table.display, builder: (column) => column);
|
||||
GeneratedColumn<String> get email =>
|
||||
$composableBuilder(column: $table.email, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> 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<String> username = const Value.absent(),
|
||||
Value<String> display = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
Value<int> id = const Value.absent(),
|
||||
Value<String> email = const Value.absent(),
|
||||
Value<String> 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<int> rowid = const Value.absent(),
|
||||
Value<int> 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)))
|
||||
|
||||
@@ -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
|
||||
);
|
||||
@@ -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<PhylumAccount> {
|
||||
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<PhylumAccount> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import 'package:phylum/libphylum/responses/responses.dart';
|
||||
|
||||
class UserRepository {
|
||||
final PhylumAccount account;
|
||||
Map<String, User> _users = const {};
|
||||
Map<String, User> get users => _users;
|
||||
Map<int, User> _users = const {};
|
||||
Map<int, User> 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<int, User>.fromIterable(users, key: (u) => u.id)));
|
||||
}
|
||||
|
||||
Future<ApiResult> 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<int, User>.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)';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,8 +14,9 @@ class UserListResponse extends PhylumApiSuccessResponse {
|
||||
|
||||
factory UserListResponse.fromResponse(Map<String, dynamic> data) {
|
||||
final users = (data["users"] as List).cast<Map>().map((u) => User(
|
||||
username: u['username'],
|
||||
display: u['display'],
|
||||
id: u['id'],
|
||||
email: u['email'],
|
||||
displayName: u['display_name'],
|
||||
));
|
||||
return UserListResponse(users: users);
|
||||
}
|
||||
|
||||
@@ -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<ResourcePermissionsView> {
|
||||
String? resourceName;
|
||||
Map<String, Permission>? permissions;
|
||||
Map<String, Permission>? grants;
|
||||
Map<int, Permission>? permissions;
|
||||
Map<int, Permission>? grants;
|
||||
Permission? userPermission;
|
||||
|
||||
StreamSubscription? sub;
|
||||
@@ -75,11 +76,11 @@ class _ResourcePermissionsViewState extends State<ResourcePermissionsView> {
|
||||
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<ResourcePermissionsView> {
|
||||
account.addAction(ResourceShareAction(
|
||||
resourceId: widget.resourceId,
|
||||
resourceName: resourceName!,
|
||||
username: user.username,
|
||||
user: user,
|
||||
permission: permission,
|
||||
));
|
||||
},
|
||||
@@ -112,15 +113,19 @@ class _ResourcePermissionsViewState extends State<ResourcePermissionsView> {
|
||||
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,
|
||||
));
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ class LoginPage extends StatefulWidget {
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
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<LoginPage> {
|
||||
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<LoginPage> {
|
||||
);
|
||||
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<LoginPage> {
|
||||
),
|
||||
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<LoginPage> {
|
||||
});
|
||||
},
|
||||
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'),
|
||||
|
||||
@@ -13,8 +13,9 @@ const Permission permissionSetReadWrite = permissionRead | permissionWrite;
|
||||
const Permission permissionSetReadWriteShare = permissionRead | permissionWrite | permissionShare;
|
||||
|
||||
extension PermissionMapper on String? {
|
||||
Map<String, Permission> parsePermissionMap() =>
|
||||
this == null ? {} : (jsonDecode(this!) as Map).cast<String, Permission>();
|
||||
Map<int, Permission> parsePermissionMap() => this == null
|
||||
? {}
|
||||
: (jsonDecode(this!) as Map).cast<String, Permission>().map((k, v) => MapEntry(int.parse(k), v));
|
||||
|
||||
// Map<String, Permission> parseGrantsMap() => this == null
|
||||
// ? {}
|
||||
|
||||
Reference in New Issue
Block a user