Stabilize auth flow and profile images
This commit is contained in:
@@ -101,19 +101,24 @@ class PhoneLoginResponse {
|
||||
required this.token,
|
||||
required this.expiresAt,
|
||||
required this.user,
|
||||
this.orgContextCredential,
|
||||
});
|
||||
|
||||
final String status;
|
||||
final String token;
|
||||
final DateTime expiresAt;
|
||||
final LoginUser user;
|
||||
final OrgContextCredential? orgContextCredential;
|
||||
|
||||
factory PhoneLoginResponse.fromJson(Map<String, dynamic> json) {
|
||||
return PhoneLoginResponse(
|
||||
status: json['status'] as String? ?? '',
|
||||
token: json['token'] as String? ?? '',
|
||||
token: json['token'] as String? ?? json['accessToken'] as String? ?? '',
|
||||
expiresAt: DateTime.parse(json['expiresAt'] as String),
|
||||
user: LoginUser.fromJson(json['user'] as Map<String, dynamic>? ?? {}),
|
||||
orgContextCredential: OrgContextCredential.fromJsonOrNull(
|
||||
json['orgContextCredential'] ?? json['org_context'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,10 +128,176 @@ class PhoneLoginResponse {
|
||||
'token': token,
|
||||
'expiresAt': expiresAt.toUtc().toIso8601String(),
|
||||
'user': user.toJson(),
|
||||
if (orgContextCredential != null)
|
||||
'orgContextCredential': orgContextCredential!.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class OrgContextCredential {
|
||||
const OrgContextCredential({
|
||||
required this.baseUrl,
|
||||
required this.tenantSlug,
|
||||
required this.keyId,
|
||||
required this.keySecret,
|
||||
this.expiresAt,
|
||||
});
|
||||
|
||||
final String baseUrl;
|
||||
final String tenantSlug;
|
||||
final String keyId;
|
||||
final String keySecret;
|
||||
final DateTime? expiresAt;
|
||||
|
||||
bool get isUsable {
|
||||
return baseUrl.trim().isNotEmpty &&
|
||||
tenantSlug.trim().isNotEmpty &&
|
||||
keyId.trim().isNotEmpty &&
|
||||
keySecret.trim().isNotEmpty &&
|
||||
(expiresAt == null || expiresAt!.isAfter(DateTime.now().toUtc()));
|
||||
}
|
||||
|
||||
factory OrgContextCredential.fromJson(Map<String, dynamic> json) {
|
||||
return OrgContextCredential(
|
||||
baseUrl: _readString(json, const ['baseUrl', 'base_url']),
|
||||
tenantSlug: _readString(json, const ['tenantSlug', 'tenant_slug']),
|
||||
keyId: _readString(json, const ['keyId', 'key_id']),
|
||||
keySecret: _readString(json, const ['keySecret', 'key_secret']),
|
||||
expiresAt: _readDate(json['expiresAt'] ?? json['expires_at']),
|
||||
);
|
||||
}
|
||||
|
||||
static OrgContextCredential? fromJsonOrNull(Object? value) {
|
||||
if (value is! Map) {
|
||||
return null;
|
||||
}
|
||||
final credential = OrgContextCredential.fromJson(
|
||||
Map<String, dynamic>.from(value),
|
||||
);
|
||||
return credential.isUsable ? credential : null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'baseUrl': baseUrl,
|
||||
'tenantSlug': tenantSlug,
|
||||
'keyId': keyId,
|
||||
'keySecret': keySecret,
|
||||
if (expiresAt != null) 'expiresAt': expiresAt!.toUtc().toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
static String _readString(Map<String, dynamic> json, List<String> keys) {
|
||||
for (final key in keys) {
|
||||
final value = json[key];
|
||||
if (value is String && value.trim().isNotEmpty) {
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
static DateTime? _readDate(Object? value) {
|
||||
if (value is! String || value.trim().isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return DateTime.tryParse(value)?.toUtc();
|
||||
}
|
||||
}
|
||||
|
||||
class PhoneLoginLinkInitRequest {
|
||||
const PhoneLoginLinkInitRequest({
|
||||
required this.phoneNumber,
|
||||
required this.device,
|
||||
});
|
||||
|
||||
final String phoneNumber;
|
||||
final LoginDeviceInfo device;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'phoneNumber': phoneNumber, 'device': device.toJson()};
|
||||
}
|
||||
}
|
||||
|
||||
class PhoneLoginLinkInitResponse {
|
||||
const PhoneLoginLinkInitResponse({
|
||||
required this.status,
|
||||
required this.pendingRef,
|
||||
required this.expiresIn,
|
||||
required this.interval,
|
||||
required this.resendAfter,
|
||||
this.provider,
|
||||
});
|
||||
|
||||
final String status;
|
||||
final String pendingRef;
|
||||
final int expiresIn;
|
||||
final int interval;
|
||||
final int resendAfter;
|
||||
final String? provider;
|
||||
|
||||
factory PhoneLoginLinkInitResponse.fromJson(Map<String, dynamic> json) {
|
||||
return PhoneLoginLinkInitResponse(
|
||||
status: json['status'] as String? ?? '',
|
||||
pendingRef: json['pendingRef'] as String? ?? '',
|
||||
expiresIn: json['expiresIn'] as int? ?? 180,
|
||||
interval: json['interval'] as int? ?? json['pollInterval'] as int? ?? 3,
|
||||
resendAfter: json['resendAfter'] as int? ?? 30,
|
||||
provider: json['provider'] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PhoneLoginLinkPollRequest {
|
||||
const PhoneLoginLinkPollRequest({required this.pendingRef});
|
||||
|
||||
final String pendingRef;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'pendingRef': pendingRef};
|
||||
}
|
||||
}
|
||||
|
||||
class PhoneLoginLinkPollResponse {
|
||||
const PhoneLoginLinkPollResponse({
|
||||
required this.status,
|
||||
this.code,
|
||||
this.interval,
|
||||
this.session,
|
||||
});
|
||||
|
||||
final String status;
|
||||
final String? code;
|
||||
final int? interval;
|
||||
final PhoneLoginResponse? session;
|
||||
|
||||
bool get isPending =>
|
||||
status == 'pending' ||
|
||||
code == 'authorization_pending' ||
|
||||
code == 'slow_down';
|
||||
|
||||
bool get isExpired => code == 'expired_token';
|
||||
|
||||
factory PhoneLoginLinkPollResponse.fromJson(Map<String, dynamic> json) {
|
||||
PhoneLoginResponse? session;
|
||||
if (json['session'] is Map<String, dynamic>) {
|
||||
session = PhoneLoginResponse.fromJson(
|
||||
json['session'] as Map<String, dynamic>,
|
||||
);
|
||||
} else if ((json['token'] != null || json['accessToken'] != null) &&
|
||||
json['expiresAt'] != null) {
|
||||
session = PhoneLoginResponse.fromJson(json);
|
||||
}
|
||||
|
||||
return PhoneLoginLinkPollResponse(
|
||||
status: json['status'] as String? ?? '',
|
||||
code: json['code'] as String?,
|
||||
interval: json['interval'] as int? ?? json['pollInterval'] as int?,
|
||||
session: session,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserPermissions {
|
||||
const UserPermissions({
|
||||
required this.directory,
|
||||
|
||||
Reference in New Issue
Block a user