55 lines
1.7 KiB
Dart
55 lines
1.7 KiB
Dart
import '../utils/app_time.dart';
|
|
|
|
/// A cross-device face verification session.
|
|
///
|
|
/// Created on web when no camera is detected. The web client generates a QR
|
|
/// code containing the session ID. The mobile client scans the QR, performs
|
|
/// liveness detection, uploads the photo, and marks the session completed.
|
|
class VerificationSession {
|
|
VerificationSession({
|
|
required this.id,
|
|
required this.userId,
|
|
required this.type,
|
|
this.contextId,
|
|
this.status = 'pending',
|
|
this.imageUrl,
|
|
required this.createdAt,
|
|
required this.expiresAt,
|
|
});
|
|
|
|
final String id;
|
|
final String userId;
|
|
final String type; // 'enrollment' or 'verification'
|
|
final String? contextId; // e.g. attendance_log_id
|
|
final String status; // 'pending', 'completed', 'expired'
|
|
final String? imageUrl;
|
|
final DateTime createdAt;
|
|
final DateTime expiresAt;
|
|
|
|
bool get isPending => status == 'pending';
|
|
bool get isCompleted => status == 'completed';
|
|
bool get isExpired =>
|
|
status == 'expired' || DateTime.now().toUtc().isAfter(expiresAt);
|
|
|
|
factory VerificationSession.fromMap(Map<String, dynamic> map) {
|
|
return VerificationSession(
|
|
id: map['id'] as String,
|
|
userId: map['user_id'] as String,
|
|
type: map['type'] as String,
|
|
contextId: map['context_id'] as String?,
|
|
status: (map['status'] as String?) ?? 'pending',
|
|
imageUrl: map['image_url'] as String?,
|
|
createdAt: AppTime.parse(map['created_at'] as String),
|
|
expiresAt: AppTime.parse(map['expires_at'] as String),
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'user_id': userId,
|
|
'type': type,
|
|
if (contextId != null) 'context_id': contextId,
|
|
};
|
|
}
|
|
}
|