✨ Better audit logs
This commit is contained in:
		| @@ -485,5 +485,6 @@ | ||||
|   "auditLog": "Audit log", | ||||
|   "shareImage": "Share as image", | ||||
|   "shareImageFooter": "Only on the Solar Network", | ||||
|   "fileSavedAt": "File saved at @path" | ||||
|   "fileSavedAt": "File saved at @path", | ||||
|   "showIp": "Show IP Address" | ||||
| } | ||||
|   | ||||
| @@ -481,5 +481,6 @@ | ||||
|   "auditLog": "活动日志", | ||||
|   "shareImage": "分享图片", | ||||
|   "shareImageFooter": "上 Solar Network 看更多有趣帖子", | ||||
|   "fileSavedAt": "文件保存于 @path" | ||||
|   "fileSavedAt": "文件保存于 @path", | ||||
|   "showIp": "显示 IP 地址" | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| import 'package:google_fonts/google_fonts.dart'; | ||||
| import 'package:marquee/marquee.dart'; | ||||
| import 'package:solian/exceptions/request.dart'; | ||||
| import 'package:solian/exts.dart'; | ||||
| import 'package:solian/models/audit_log.dart'; | ||||
| @@ -29,7 +30,7 @@ class _AuditLogScreenState extends State<AuditLogScreen> { | ||||
|     final AuthProvider auth = Get.find(); | ||||
|     final client = await auth.configureClient('id'); | ||||
|     final resp = | ||||
|         await client.get('/users/me/events?take=10&offset=${_events.length}'); | ||||
|         await client.get('/users/me/events?take=15&offset=${_events.length}'); | ||||
|     if (resp.statusCode != 200) { | ||||
|       context.showErrorDialog(RequestException(resp)); | ||||
|     } | ||||
| @@ -45,6 +46,22 @@ class _AuditLogScreenState extends State<AuditLogScreen> { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   bool _showIp = false; | ||||
|  | ||||
|   String _censorIpAddress(String ip) { | ||||
|     List<String> parts = ip.split('.'); | ||||
|  | ||||
|     if (parts.length == 4) { | ||||
|       String censoredPart1 = '*' * parts[1].length; | ||||
|       String censoredPart2 = '*' * parts[2].length; | ||||
|       String censoredPart3 = '*' * parts[3].length; | ||||
|  | ||||
|       return '${parts[0]}.$censoredPart1.$censoredPart2.$censoredPart3'; | ||||
|     } else { | ||||
|       return '***.***.***.***'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
| @@ -53,7 +70,27 @@ class _AuditLogScreenState extends State<AuditLogScreen> { | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return InfiniteList( | ||||
|     return Column( | ||||
|       children: [ | ||||
|         CheckboxListTile( | ||||
|           value: _showIp, | ||||
|           title: Text('showIp'.tr), | ||||
|           contentPadding: const EdgeInsets.symmetric(horizontal: 24), | ||||
|           secondary: const Icon(Icons.alternate_email), | ||||
|           tileColor: | ||||
|               Theme.of(context).colorScheme.surfaceContainer.withOpacity(0.5), | ||||
|           onChanged: (val) { | ||||
|             setState(() => _showIp = val ?? false); | ||||
|           }, | ||||
|         ), | ||||
|         Expanded( | ||||
|           child: RefreshIndicator( | ||||
|             onRefresh: () { | ||||
|               _events.clear(); | ||||
|               return _getEvents(); | ||||
|             }, | ||||
|             child: InfiniteList( | ||||
|               padding: const EdgeInsets.symmetric(vertical: 12), | ||||
|               itemCount: _events.length, | ||||
|               isLoading: _isBusy, | ||||
|               onFetchData: () { | ||||
| @@ -65,6 +102,7 @@ class _AuditLogScreenState extends State<AuditLogScreen> { | ||||
|                   isFirst: idx == 0, | ||||
|                   isLast: _events.length - 1 == idx, | ||||
|                   alignment: TimelineAlign.start, | ||||
|                   indicatorStyle: IndicatorStyle(width: 15), | ||||
|                   endChild: Container( | ||||
|                     child: Card( | ||||
|                       child: Column( | ||||
| @@ -74,6 +112,24 @@ class _AuditLogScreenState extends State<AuditLogScreen> { | ||||
|                             element.type, | ||||
|                             style: GoogleFonts.robotoMono(fontSize: 15), | ||||
|                           ), | ||||
|                           Text( | ||||
|                             _showIp | ||||
|                                 ? element.ipAddress | ||||
|                                 : _censorIpAddress(element.ipAddress), | ||||
|                             style: GoogleFonts.sourceCodePro( | ||||
|                               fontWeight: FontWeight.bold, | ||||
|                             ), | ||||
|                           ), | ||||
|                           SizedBox( | ||||
|                             height: 20, | ||||
|                             width: double.maxFinite, | ||||
|                             child: Marquee( | ||||
|                               text: element.userAgent, | ||||
|                               velocity: 25, | ||||
|                               startAfter: Duration(milliseconds: 500), | ||||
|                               pauseAfterRound: Duration(milliseconds: 3000), | ||||
|                             ), | ||||
|                           ), | ||||
|                           Row( | ||||
|                             children: [ | ||||
|                               RelativeDate(element.createdAt), | ||||
| @@ -89,6 +145,10 @@ class _AuditLogScreenState extends State<AuditLogScreen> { | ||||
|                   ), | ||||
|                 ).paddingSymmetric(horizontal: 18); | ||||
|               }, | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -62,9 +62,8 @@ class _PostDetailScreenState extends State<PostDetailScreen> { | ||||
|  | ||||
|     return CustomScrollView( | ||||
|       slivers: [ | ||||
|         if (_isBusy) | ||||
|         SliverToBoxAdapter( | ||||
|             child: LoadingIndicator(), | ||||
|           child: LoadingIndicator(isActive: _isBusy), | ||||
|         ), | ||||
|         SliverToBoxAdapter( | ||||
|           child: PostItem( | ||||
|   | ||||
| @@ -38,12 +38,14 @@ class _ChannelListWidgetState extends State<ChannelListWidget> { | ||||
|  | ||||
|   Future<void> _loadLastMessages() async { | ||||
|     final messages = await _eventController.src.getLastInAllChannels(); | ||||
|     if (mounted) { | ||||
|       setState(() { | ||||
|         _lastMessages = messages | ||||
|             .map((k, v) => MapEntry(k, v.firstOrNull)) | ||||
|             .cast<int, LocalMessageEventTableData>(); | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
|   | ||||
							
								
								
									
										16
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -414,6 +414,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.5" | ||||
|   fading_edge_scrollview: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: fading_edge_scrollview | ||||
|       sha256: "1f84fe3ea8e251d00d5735e27502a6a250e4aa3d3b330d3fdcb475af741464ef" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "4.1.1" | ||||
|   fake_async: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1277,6 +1285,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.5.0" | ||||
|   marquee: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: marquee | ||||
|       sha256: a87e7e80c5d21434f90ad92add9f820cf68be374b226404fe881d2bba7be0862 | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.0" | ||||
|   matcher: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
| @@ -89,6 +89,7 @@ dependencies: | ||||
|   qr_flutter: ^4.1.0 | ||||
|   flutter_resizable_container: ^3.0.0 | ||||
|   file_saver: ^0.2.14 | ||||
|   marquee: ^2.3.0 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user