feat: type stats and event log models
This commit is contained in:
116
lib/models/event_log_item.dart
Normal file
116
lib/models/event_log_item.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
class EventLogItem {
|
||||
final String timestamp;
|
||||
final String action;
|
||||
final String targetId;
|
||||
final Object? params;
|
||||
final String actor;
|
||||
|
||||
const EventLogItem({
|
||||
required this.timestamp,
|
||||
required this.action,
|
||||
required this.targetId,
|
||||
this.params,
|
||||
this.actor = '',
|
||||
});
|
||||
|
||||
String get title => '$action - $targetId';
|
||||
|
||||
String get paramsText {
|
||||
final value = params;
|
||||
if (value == null) return '';
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
String get formattedTime {
|
||||
if (timestamp.isEmpty) return '';
|
||||
try {
|
||||
final date = DateTime.parse(timestamp);
|
||||
String pad(int n) => n.toString().padLeft(2, '0');
|
||||
return '${pad(date.day)}.${pad(date.month)} '
|
||||
'${pad(date.hour)}:${pad(date.minute)}:${pad(date.second)}';
|
||||
} catch (_) {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
static EventLogItem fromApi(Object? data, {String? fallbackId}) {
|
||||
if (data is! Map) {
|
||||
final action = data?.toString() ?? fallbackId;
|
||||
if (action == null || action.isEmpty) {
|
||||
throw const FormatException('event log item должен быть объектом');
|
||||
}
|
||||
return EventLogItem(timestamp: '', action: action, targetId: '');
|
||||
}
|
||||
|
||||
final map = Map<String, dynamic>.from(data);
|
||||
return EventLogItem(
|
||||
timestamp:
|
||||
_stringValue(map, const ['timestamp', 'time', 'created_at']) ?? '',
|
||||
action: _stringValue(map, const ['action', 'command', 'type']) ?? '',
|
||||
targetId:
|
||||
_stringValue(map, const ['target_id', 'target', 'group_id']) ?? '',
|
||||
params: map['params'] ?? map['details'],
|
||||
actor: _stringValue(map, const ['actor', 'user', 'key_name']) ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
static List<EventLogItem> listFromApi(Object? data) {
|
||||
final values = _collectionValues(data, const ['data', 'events', 'log']);
|
||||
return values.map((value) {
|
||||
if (value.entryKey == null) return EventLogItem.fromApi(value.value);
|
||||
return EventLogItem.fromApi(value.value, fallbackId: value.entryKey);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
String? _stringValue(Map<String, dynamic> map, List<String> keys) {
|
||||
for (final key in keys) {
|
||||
final value = map[key];
|
||||
if (value != null && value.toString().isNotEmpty) {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<_CollectionValue> _collectionValues(Object? data, List<String> wrappers) {
|
||||
if (data is List) {
|
||||
return data.map((value) => _CollectionValue(value)).toList();
|
||||
}
|
||||
|
||||
if (data is Map) {
|
||||
final map = Map<String, dynamic>.from(data);
|
||||
for (final wrapper in wrappers) {
|
||||
final value = map[wrapper];
|
||||
if (value is List) {
|
||||
return value.map((item) => _CollectionValue(item)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
if (_looksLikeEventItem(map)) {
|
||||
return <_CollectionValue>[_CollectionValue(map)];
|
||||
}
|
||||
|
||||
return map.entries
|
||||
.map((entry) => _CollectionValue(entry.value, entryKey: entry.key))
|
||||
.toList();
|
||||
}
|
||||
|
||||
throw const FormatException('stats log должен быть списком событий');
|
||||
}
|
||||
|
||||
bool _looksLikeEventItem(Map<String, dynamic> map) {
|
||||
return map.containsKey('timestamp') ||
|
||||
map.containsKey('time') ||
|
||||
map.containsKey('created_at') ||
|
||||
map.containsKey('action') ||
|
||||
map.containsKey('command') ||
|
||||
map.containsKey('type');
|
||||
}
|
||||
|
||||
class _CollectionValue {
|
||||
final Object? value;
|
||||
final String? entryKey;
|
||||
|
||||
const _CollectionValue(this.value, {this.entryKey});
|
||||
}
|
||||
Reference in New Issue
Block a user