✨ Better audit logs
This commit is contained in:
parent
77288713e1
commit
48e3b510cf
@ -485,5 +485,6 @@
|
|||||||
"auditLog": "Audit log",
|
"auditLog": "Audit log",
|
||||||
"shareImage": "Share as image",
|
"shareImage": "Share as image",
|
||||||
"shareImageFooter": "Only on the Solar Network",
|
"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": "活动日志",
|
"auditLog": "活动日志",
|
||||||
"shareImage": "分享图片",
|
"shareImage": "分享图片",
|
||||||
"shareImageFooter": "上 Solar Network 看更多有趣帖子",
|
"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:gap/gap.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:marquee/marquee.dart';
|
||||||
import 'package:solian/exceptions/request.dart';
|
import 'package:solian/exceptions/request.dart';
|
||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/models/audit_log.dart';
|
import 'package:solian/models/audit_log.dart';
|
||||||
@ -29,7 +30,7 @@ class _AuditLogScreenState extends State<AuditLogScreen> {
|
|||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
final client = await auth.configureClient('id');
|
final client = await auth.configureClient('id');
|
||||||
final resp =
|
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) {
|
if (resp.statusCode != 200) {
|
||||||
context.showErrorDialog(RequestException(resp));
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -53,42 +70,85 @@ class _AuditLogScreenState extends State<AuditLogScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InfiniteList(
|
return Column(
|
||||||
itemCount: _events.length,
|
children: [
|
||||||
isLoading: _isBusy,
|
CheckboxListTile(
|
||||||
onFetchData: () {
|
value: _showIp,
|
||||||
_getEvents();
|
title: Text('showIp'.tr),
|
||||||
},
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
itemBuilder: (context, idx) {
|
secondary: const Icon(Icons.alternate_email),
|
||||||
final element = _events[idx];
|
tileColor:
|
||||||
return TimelineTile(
|
Theme.of(context).colorScheme.surfaceContainer.withOpacity(0.5),
|
||||||
isFirst: idx == 0,
|
onChanged: (val) {
|
||||||
isLast: _events.length - 1 == idx,
|
setState(() => _showIp = val ?? false);
|
||||||
alignment: TimelineAlign.start,
|
},
|
||||||
endChild: Container(
|
),
|
||||||
child: Card(
|
Expanded(
|
||||||
child: Column(
|
child: RefreshIndicator(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
onRefresh: () {
|
||||||
children: [
|
_events.clear();
|
||||||
Text(
|
return _getEvents();
|
||||||
element.type,
|
},
|
||||||
style: GoogleFonts.robotoMono(fontSize: 15),
|
child: InfiniteList(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
itemCount: _events.length,
|
||||||
|
isLoading: _isBusy,
|
||||||
|
onFetchData: () {
|
||||||
|
_getEvents();
|
||||||
|
},
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
final element = _events[idx];
|
||||||
|
return TimelineTile(
|
||||||
|
isFirst: idx == 0,
|
||||||
|
isLast: _events.length - 1 == idx,
|
||||||
|
alignment: TimelineAlign.start,
|
||||||
|
indicatorStyle: IndicatorStyle(width: 15),
|
||||||
|
endChild: Container(
|
||||||
|
child: Card(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
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),
|
||||||
|
const Gap(6),
|
||||||
|
Text('·'),
|
||||||
|
const Gap(6),
|
||||||
|
RelativeDate(element.createdAt, isFull: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetric(horizontal: 12, vertical: 8),
|
||||||
|
).paddingOnly(left: 16),
|
||||||
),
|
),
|
||||||
Row(
|
).paddingSymmetric(horizontal: 18);
|
||||||
children: [
|
},
|
||||||
RelativeDate(element.createdAt),
|
),
|
||||||
const Gap(6),
|
|
||||||
Text('·'),
|
|
||||||
const Gap(6),
|
|
||||||
RelativeDate(element.createdAt, isFull: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
).paddingSymmetric(horizontal: 12, vertical: 8),
|
|
||||||
).paddingOnly(left: 16),
|
|
||||||
),
|
),
|
||||||
).paddingSymmetric(horizontal: 18);
|
),
|
||||||
},
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,10 +62,9 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
|
|||||||
|
|
||||||
return CustomScrollView(
|
return CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
if (_isBusy)
|
SliverToBoxAdapter(
|
||||||
SliverToBoxAdapter(
|
child: LoadingIndicator(isActive: _isBusy),
|
||||||
child: LoadingIndicator(),
|
),
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: PostItem(
|
child: PostItem(
|
||||||
item: _item!,
|
item: _item!,
|
||||||
|
@ -38,11 +38,13 @@ class _ChannelListWidgetState extends State<ChannelListWidget> {
|
|||||||
|
|
||||||
Future<void> _loadLastMessages() async {
|
Future<void> _loadLastMessages() async {
|
||||||
final messages = await _eventController.src.getLastInAllChannels();
|
final messages = await _eventController.src.getLastInAllChannels();
|
||||||
setState(() {
|
if (mounted) {
|
||||||
_lastMessages = messages
|
setState(() {
|
||||||
.map((k, v) => MapEntry(k, v.firstOrNull))
|
_lastMessages = messages
|
||||||
.cast<int, LocalMessageEventTableData>();
|
.map((k, v) => MapEntry(k, v.firstOrNull))
|
||||||
});
|
.cast<int, LocalMessageEventTableData>();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
16
pubspec.lock
16
pubspec.lock
@ -414,6 +414,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
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:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1277,6 +1285,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.0"
|
||||||
|
marquee:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: marquee
|
||||||
|
sha256: a87e7e80c5d21434f90ad92add9f820cf68be374b226404fe881d2bba7be0862
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -89,6 +89,7 @@ dependencies:
|
|||||||
qr_flutter: ^4.1.0
|
qr_flutter: ^4.1.0
|
||||||
flutter_resizable_container: ^3.0.0
|
flutter_resizable_container: ^3.0.0
|
||||||
file_saver: ^0.2.14
|
file_saver: ^0.2.14
|
||||||
|
marquee: ^2.3.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user