Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Improve join logs handling #42

Merged
merged 1 commit into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ doc/api/
*.exe
*.db

lib_old/
sessions/
85 changes: 68 additions & 17 deletions lib/src/modules/join_logs.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import 'package:injector/injector.dart';
import 'package:nyxx/nyxx.dart';
import 'package:collection/collection.dart';
import 'package:nyxx_extensions/nyxx_extensions.dart';
import 'package:running_on_dart/src/models/feature_settings.dart';
import 'package:running_on_dart/src/repository/feature_settings.dart';
import 'package:running_on_dart/src/modules/feature_settings.dart';
import 'package:running_on_dart/src/settings.dart';
import 'package:running_on_dart/src/util/util.dart';

const idFieldName = 'ID';

class JoinLogsModule implements RequiresInitialization {
final NyxxGateway _client = Injector.appInstance.get();
final FeatureSettingsRepository _featureSettingsRepository = Injector.appInstance.get();
Expand All @@ -16,34 +19,28 @@ class JoinLogsModule implements RequiresInitialization {

@override
Future<void> init() async {
_client.onGuildMemberAdd.listen(_handle);
_client.onGuildMemberAdd.listen(_handleMemberAdd);
_client.onGuildMemberRemove.listen(_handleMemberRemove);
}

void _handle(GuildMemberAddEvent event) async {
final isEnabled = await _isEnabledForGuild(event.guildId);
if (!isEnabled) {
Future<void> _handleMemberAdd(GuildMemberAddEvent event) async {
final channel = await _getChannelIfFeatureEnabled(event.guildId);
if (channel == null) {
return;
}

final setting = await _featureSettingsRepository.fetchSetting(Setting.joinLogs, event.guildId);
if (setting == null) {
return;
}
_logger.fine('Sending join message for member ${event.member.id} in channel ${channel.id}');

final channelId = setting.data!;
final channel = await _client.channels.get(Snowflake.parse(channelId));
if (channel is! TextChannel) {
_logger.warning('Channel $channelId is not a text channel.');
return;
final descriptionBuffer = StringBuffer('**Member joined**');
if (event.member.id.timestamp.difference(DateTime.now()).inDays < 30) {
descriptionBuffer.write(" (New user)");
}

_logger.fine('Sending join message for member ${event.member.id} in channel $channelId');

final embed = EmbedBuilder(
description: '**Member joined**',
description: descriptionBuffer.toString(),
author: EmbedAuthorBuilder(name: event.member.user!.username, iconUrl: event.member.user!.avatar.url),
fields: [
EmbedFieldBuilder(name: 'ID', value: userMention(event.member.id), isInline: true),
EmbedFieldBuilder(name: idFieldName, value: userMention(event.member.id), isInline: true),
EmbedFieldBuilder(name: 'Joined At', value: _formatDateTimeString(event.member.joinedAt), isInline: true),
EmbedFieldBuilder(
name: 'Account created at', value: _formatDateTimeString(event.member.id.timestamp), isInline: true)
Expand All @@ -52,6 +49,60 @@ class JoinLogsModule implements RequiresInitialization {
channel.sendMessage(MessageBuilder(embeds: [embed]));
}

Future<void> _handleMemberRemove(GuildMemberRemoveEvent event) async {
final channel = await _getChannelIfFeatureEnabled(event.guildId);
if (channel == null) {
return;
}

if (event.removedMember != null && event.removedMember!.joinedAt.difference(DateTime.now()).inDays > 7) {
return;
}

_logger.fine('Trying to update join log message for user ${event.user.id} in channel ${channel.id}');

final messages = channel.messages
.stream(pageSize: 20, order: StreamOrder.mostRecentFirst)
.where((message) => message.embeds.isNotEmpty)
.where((message) =>
message.embeds.first.fields
?.firstWhereOrNull((f) => f.name == idFieldName)
?.value
.contains(event.user.id.toString()) !=
null);

final message = (await messages.toList()).firstOrNull;
if (message == null) {
return;
}

final embed = message.embeds.first.toEmbedBuilder();
embed.description = "${embed.description} (Left)";

message.update(MessageUpdateBuilder(embeds: [embed]));
}

Future<TextChannel?> _getChannelIfFeatureEnabled(Snowflake guildId) async {
final isEnabled = await _isEnabledForGuild(guildId);
if (!isEnabled) {
return null;
}

final setting = await _featureSettingsRepository.fetchSetting(Setting.joinLogs, guildId);
if (setting == null) {
return null;
}

final channelId = setting.data!;
final channel = await _client.channels.get(Snowflake.parse(channelId));
if (channel is! TextChannel) {
_logger.warning('Channel $channelId is not a text channel.');
return null;
}

return channel;
}

String _formatDateTimeString(DateTime dateTime) =>
'${dateTime.format(TimestampStyle.shortDate)} (${dateTime.format(TimestampStyle.relativeTime)})';

Expand Down