diff --git a/bin/beer_bot.dart b/bin/beer_bot.dart index 422b94c..ddd4857 100644 --- a/bin/beer_bot.dart +++ b/bin/beer_bot.dart @@ -1,32 +1,28 @@ import 'dart:io'; import 'package:nyxx/nyxx.dart'; -import 'package:nyxx_interactions/nyxx_interactions.dart'; +import 'package:nyxx_commands/nyxx_commands.dart'; import 'commands.dart'; import 'modules/untappd/untapped_module.dart'; String BOT_TOKEN = Platform.environment['DISCORD_TOKEN'] ?? ''; -late final INyxxWebsocket bot; - -void main(List arguments) { - bot = - NyxxFactory.createNyxxWebsocket(BOT_TOKEN, GatewayIntents.allUnprivileged) - ..registerPlugin(Logging()) - ..registerPlugin(CliIntegration()) - ..registerPlugin(IgnoreExceptions()) - ..connect(); - - final interactions = IInteractions.create(WebsocketInteractionBackend(bot)); +// late final INyxxWebsocket bot; +void main(List arguments) async { + final commands = CommandsPlugin(prefix: mentionOr((_) => '!')); Commands.getCommands().forEach((command) { - interactions.registerSlashCommand(command); + commands.addCommand(command); }); - interactions.syncOnReady(); + final bot = + await Nyxx.connectGateway('', GatewayIntents.allUnprivileged, + options: GatewayClientOptions( + plugins: [commands], + )); - bot.eventsWs.onReady.listen((e) { + bot.onReady.listen((ReadyEvent e) { print('Agent Hops is ready!'); }); diff --git a/bin/commands.dart b/bin/commands.dart index d6a5284..9149395 100644 --- a/bin/commands.dart +++ b/bin/commands.dart @@ -1,38 +1,33 @@ import 'package:nyxx/nyxx.dart'; -import 'package:nyxx_interactions/nyxx_interactions.dart'; +import 'package:nyxx_commands/nyxx_commands.dart'; import 'modules/untappd/untapped_module.dart'; class Commands { - static List getCommands() => [ - SlashCommandBuilder( + /// Get all commands available for the bot + static List getCommands() => [ + ChatCommand( 'help', 'List commands available', - [], - )..registerHandler((event) async { - await event.acknowledge(); - await _helpCommand(event); - }), + (ChatContext ctx) async { + await _helpCommand(ctx); + }, + ), + // Add all commands from the modules here ...UntappdModule().commands, ]; - static Future _helpCommand(ISlashCommandInteractionEvent ctx) async { - var helpMessage = MessageBuilder() - ..append(ctx.interaction.userAuthor!.mention) - ..appendNewLine() - ..append(_mainHelpMessage) - ..appendNewLine() - ..appendNewLine() - ..append(UntappdModule().helpMessage); + static Future _helpCommand(ChatContext ctx) async { + var helpMessage = MessageBuilder( + content: '$_mainHelpMessage\n\n' + '${UntappdModule().helpMessage}'); await ctx.respond(helpMessage); } - static MessageBuilder get _mainHelpMessage => MessageBuilder() - ..append('Did anyone say beer? This is what I can do for you:') - ..appendNewLine() - ..appendNewLine() - ..appendBold('/help') - ..appendNewLine() - ..append('Shows you this help message.'); + static MessageBuilder get _mainHelpMessage => MessageBuilder( + content: 'Did anyone say beer? This is what I can do for you: \n\n' + '/help\n' + 'Shows you this help message.', + ); } diff --git a/bin/modules/beer_agent/beer_agent_module.dart b/bin/modules/beer_agent/beer_agent_module.dart index bf0c5da..b1fd94c 100644 --- a/bin/modules/beer_agent/beer_agent_module.dart +++ b/bin/modules/beer_agent/beer_agent_module.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; import 'package:nyxx/nyxx.dart'; -import 'package:nyxx_interactions/nyxx_interactions.dart'; +import 'package:nyxx_commands/nyxx_commands.dart'; import '../bot_module.dart'; import 'models/beer.dart'; @@ -19,7 +19,7 @@ class BeerAgentModule extends BotModule { bool _isInitialized = false; - late INyxxWebsocket _bot; + late NyxxGateway _bot; static final BeerAgentModule _singleton = BeerAgentModule._internal(); @@ -56,34 +56,32 @@ class BeerAgentModule extends BotModule { } if (shouldInform) { - for (var dmchannel in await _getSubChannels(_bot)) { + for (var userDmChannel in await _getSubbedUsers(_bot)) { var beersStr = ''; beers.forEach((element) { beersStr += '- ' + element.name + '\n'; }); - var updateMessage = MessageBuilder() - ..append(':beers: Hey!') - ..appendNewLine() - ..append('There is a fresh beer release tomorrow, ') - ..appendBold(DateFormat('yyyy-MM-dd').format(saleDate)) - ..append('. Bolaget opens 10:00') - ..appendNewLine() - ..append('There are ') - ..appendBold(beers.length.toString()) - ..append(' new beers tomorrow.') - ..appendNewLine() - ..append('For more info, visit https://systembevakningsagenten.se/') - ..appendNewLine() - ..appendNewLine() - ..append(beersStr); + var updateMessage = MessageBuilder( + content: ':beers: Hey!' + '\n' + 'There is a fresh beer release tomorrow, ' + '${DateFormat('yyyy-MM-dd').format(saleDate)}. Bolaget opens 10:00' + '\n' + 'There are ${beers.length} new beers tomorrow.' + '\n' + 'For more info, visit https://systembevakningsagenten.se/' + '\n\n' + '$beersStr', + ); //To avoid hitting maximum characters for a message, limit output to 2000. - if (updateMessage.toString().length > 2000) { - updateMessage.content = - updateMessage.content.substring(0, 1992) + '...\n\n'; + final content = updateMessage.content; + if (content != null && content.toString().length > 2000) { + updateMessage.content = content.substring(0, 1992) + '...\n\n'; } - await dmchannel.sendMessage(updateMessage); + + await userDmChannel.sendMessage(updateMessage); } } else { print('No sale, boring...'); @@ -103,24 +101,21 @@ class BeerAgentModule extends BotModule { } } - /// Returns a list of all channels (users) that are subscribed to beer updates. - Future> _getSubChannels(INyxxWebsocket bot) async { + /// Returns a list of all users that are subscribed to beer updates. + Future> _getSubbedUsers(NyxxGateway bot) async { var myFile = File('sub.dat'); - var channelList = []; + var userList = []; var fileExists = await myFile.exists(); if (!fileExists) await myFile.create(); await myFile.readAsLines().then((value) async { for (var line in value) { - var chan = await bot - .fetchChannel(Snowflake(line)) - .then((value) => (value as IDMChannel)); - - channelList.add(chan); + var chan = await bot.channels.fetch(Snowflake(int.parse(line))); + userList.add(chan as DmChannel); } }); - return channelList; + return userList; } /// Updates the list of beer sales. @@ -159,9 +154,9 @@ class BeerAgentModule extends BotModule { throw Exception('Beer agent service not initialized!'); } - var subs = await _getSubChannels(_bot); + var subs = await _getSubbedUsers(_bot); - if (subs.asSnowflakes().contains(userSnowflake)) { + if (subs.map((elemet) => elemet.id).contains(userSnowflake)) { return true; } else { return false; @@ -175,7 +170,7 @@ class BeerAgentModule extends BotModule { throw Exception('Beer agent service not initialized!'); } - var currentSubs = await _getSubChannels(_bot); + var currentSubs = await _getSubbedUsers(_bot); currentSubs.removeWhere((element) => element.id == userSnowflake); var tempFile = File('temp.dat'); @@ -204,7 +199,7 @@ class BeerAgentModule extends BotModule { } @override - void init(INyxxWebsocket bot) { + void init(NyxxGateway bot) { _bot = bot; _elapsedSinceUpdate = Stopwatch(); _elapsedSinceUpdate.start(); @@ -215,67 +210,63 @@ class BeerAgentModule extends BotModule { } @override - List get commands => !_isInitialized + List get commands => !_isInitialized ? throw Exception('Beer agent module not initialized!') : [ - SlashCommandBuilder( + ChatCommand( 'oel', 'Show the latest beer releases.', - [], - )..registerHandler((event) async { - await event.acknowledge(); - await _oelCommand(event); - }), - SlashCommandBuilder( + (ChatContext ctx) async { + await _oelCommand(ctx); + }, + ), + ChatCommand( 'subscribe', 'Subscribe to beer release reminders.', - [], - )..registerHandler((event) async { - await event.acknowledge(); - await _regCommand(event); - }), - SlashCommandBuilder( + (ChatContext ctx) async { + await _regCommand(ctx, _bot); + }, + ), + ChatCommand( 'stop', 'Unsubscribe to beer release reminders.', - [], - )..registerHandler((event) async { - await event.acknowledge(); - await _stopCommand(event); - }), - SlashCommandBuilder( + (ChatContext ctx) async { + await _stopCommand(ctx); + }, + ), + ChatCommand( 'release', 'Detailed info about a specific beer release e.g. /release 2022-07-15', - [ - CommandOptionBuilder( - CommandOptionType.string, 'datum', 'YYYY-MM-dd', - required: true), - ], - )..registerHandler((event) async { - await event.acknowledge(); - await _releaseCommand(event); - }), + (ChatContext ctx, + [@Name('date') + @Description('The date of the release in the format YYYY-MM-dd') + String? date]) async { + if (date == null) { + await ctx.respond(MessageBuilder( + content: 'Please provide a date in the format YYYY-MM-dd')); + return; + } + await _releaseCommand(ctx); + }, + ) ]; @override MessageBuilder get helpMessage => !_isInitialized ? throw Exception('Beer agent not initialized!') - : MessageBuilder() - ..appendBold('/oel') - ..appendNewLine() - ..append('Lists all known beer releases.') - ..appendNewLine() - ..appendNewLine() - ..appendBold('/subscribe') - ..appendNewLine() - ..append( - 'Subscribe to automatic beer release reminders. Reminders will be posted 3 times during the day before release.') - ..appendNewLine() - ..appendNewLine() - ..appendBold('/release YYYY-MM-dd') - ..appendNewLine() - ..append( - 'Posts the beer release for given date in the format YYYY-MM-dd. e.g ') - ..appendItalics('/release 1970-01-30'); + : MessageBuilder( + content: + 'Beer agent module is active! Here are the available commands:' + '\n\n' + '/oel\n' + 'Lists all known beer releases.' + '\n\n' + '/subscribe\n' + 'Subscribe to automatic beer release reminders. Reminders will be posted 3 times during the day before release.' + '\n\n' + '/release YYYY-MM-dd\n' + 'Posts the beer release for given date in the format YYYY-MM-dd. e.g */release 1970-01-30*', + ); /// Returns a list of all current beer sales. List get beerSales => _beerSales; diff --git a/bin/modules/beer_agent/commands.dart b/bin/modules/beer_agent/commands.dart index 55783c9..b1c7795 100644 --- a/bin/modules/beer_agent/commands.dart +++ b/bin/modules/beer_agent/commands.dart @@ -1,50 +1,48 @@ part of 'beer_agent_module.dart'; -Future _regCommand(ISlashCommandInteractionEvent ctx) async { - var dmChan = await ctx.interaction.userAuthor!.dmChannel; - - if (await BeerAgentModule()._isUserSubbed(dmChan.id)) { - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' You are already subscribed! :beers:')); +Future _regCommand(ChatContext ctx, NyxxGateway bot) async { + var user = ctx.user.id; + + if (await BeerAgentModule()._isUserSubbed(user)) { + await ctx.respond( + MessageBuilder(content: 'You are already subscribed! :beers:'), + level: ResponseLevel.private, + ); } else { - await BeerAgentModule()._subUser(dmChan.id); - - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' You are now subscribed to beer release reminders! :beers:')); + final dmChannel = await bot.user.manager.createDm(user); + await BeerAgentModule()._subUser(dmChannel.id); + + await ctx.respond( + MessageBuilder( + content: 'You are now subscribed to beer release reminders! :beers:'), + level: ResponseLevel.private, + ); } } -Future _stopCommand(ISlashCommandInteractionEvent ctx) async { - var dmChan = await ctx.interaction.userAuthor!.dmChannel; +Future _stopCommand(ChatContext ctx) async { + var user = ctx.user.id; - if (await BeerAgentModule()._isUserSubbed(dmChan.id)) { - await BeerAgentModule()._unsubUser(dmChan.id); + if (await BeerAgentModule()._isUserSubbed(user)) { + await BeerAgentModule()._unsubUser(user); - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' Sad, no more beer for you! :beers:')); + await ctx.respond( + MessageBuilder(content: 'Sad, no more beer for you! :beers:'), + level: ResponseLevel.private); } else { - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' You are not subscribed! :beers:')); + await ctx.respond( + MessageBuilder(content: 'You are not subscribed! :beers:'), + level: ResponseLevel.private); } } -Future _oelCommand(ISlashCommandInteractionEvent ctx) async { +Future _oelCommand(ChatContext ctx) async { //Updates current beer list if needed await BeerAgentModule()._updateBeerSales(); //Build message - var oelMessage = MessageBuilder() - ..append(ctx.interaction.userAuthor!.mention) - ..appendNewLine() - ..append('There are ') - ..appendBold(BeerAgentModule().beerSales.length.toString()) - ..append(' current releases!') - ..appendNewLine() - ..appendNewLine(); + var message = 'There are ' + '${BeerAgentModule().beerSales.length} current releases!\n\n'; for (var beerSale in BeerAgentModule().beerSales) { var saleDate = beerSale.saleDate; @@ -52,77 +50,37 @@ Future _oelCommand(ISlashCommandInteractionEvent ctx) async { beerSale.beerList.shuffle(); if (saleSize >= 3) { - oelMessage - ..append(':beer: ') - ..appendBold(saleDate) - ..appendNewLine() - ..append('This release has ') - ..appendBold(saleSize) - ..append(' new beers!') - ..appendNewLine() - ..appendNewLine() - ..append('Some of them are:') - ..appendNewLine() - ..append('- ') - ..appendBold(beerSale.beerList[0].name) - ..appendNewLine() - ..append('- ') - ..appendBold(beerSale.beerList[1].name) - ..appendNewLine() - ..append('- ') - ..appendBold(beerSale.beerList[2].name) - ..appendNewLine() - ..appendNewLine(); + message = ':beer: $saleDate\n' + 'This release has $saleSize new beers!\n\n' + 'Some of them are:\n' + '- ${beerSale.beerList[0].name}\n' + '- ${beerSale.beerList[1].name}\n' + '- ${beerSale.beerList[2].name}\n\n'; } else if (saleSize == 2) { - oelMessage - ..append(':beer: ') - ..appendBold(saleDate) - ..appendNewLine() - ..append('This release has ') - ..appendBold(saleSize) - ..append(' new beers!') - ..appendNewLine() - ..appendNewLine() - ..append('Some of them are:') - ..appendNewLine() - ..append('- ') - ..appendBold(beerSale.beerList[0].name) - ..appendNewLine() - ..append('- ') - ..appendBold(beerSale.beerList[1].name) - ..appendNewLine() - ..appendNewLine(); + message = ':beer: $saleDate\n' + 'This release has $saleSize new beers!\n\n' + 'Some of them are:\n' + '- ${beerSale.beerList[0].name}\n' + '- ${beerSale.beerList[1].name}\n\n'; } else if (saleSize == 1) { - oelMessage - ..append(':beer: ') - ..appendBold(saleDate) - ..appendNewLine() - ..append('This release has ') - ..appendBold(saleSize) - ..append(' new beer!') - ..appendNewLine() - ..appendNewLine() - ..append('- ') - ..appendBold(beerSale.beerList[0].name) - ..appendNewLine() - ..appendNewLine(); + message = ':beer: $saleDate\n' + 'This release has $saleSize new beer!\n\n' + '- ${beerSale.beerList[0].name}\n\n'; } - } - oelMessage - ..append('---') - ..appendNewLine() - ..append('For more information: https://systembevakningsagenten.se/') - ..appendNewLine() - ..appendNewLine() - ..append('Cheers! :beers:'); + var oelMessage = MessageBuilder( + content: '$message\n' + '---\n' + 'For more information: https://systembevakningsagenten.se/\n' + 'Cheers! :beers:'); - //Send message - await ctx.respond(oelMessage); + //Send message + await ctx.respond(oelMessage); + } } -Future _releaseCommand(ISlashCommandInteractionEvent ctx) async { - var input = ctx.args; +Future _releaseCommand(ChatContext ctx) async { + var input = ctx.arguments; if (input.length == 1) { var parsedDate = DateTime.tryParse(input[0].value); @@ -139,38 +97,31 @@ Future _releaseCommand(ISlashCommandInteractionEvent ctx) async { }); //Bulild reply - var slappMessage = MessageBuilder() - ..append(ctx.interaction.userAuthor!.mention) - ..appendNewLine() - ..append(' :beers: ') - ..appendBold(input[0].value) - ..appendNewLine() - ..append('Innehåller ') - ..appendBold(sale.beerList.length) - ..append(' nya öl:') - ..appendNewLine() - ..appendNewLine() - ..append(beerStr); - - if (slappMessage.content.length > 2000) { - slappMessage.content = slappMessage.content.substring( - 0, - slappMessage.content.substring(0, 1999).lastIndexOf('- ') - - 1) + + var slappMessage = MessageBuilder( + content: + ':beers: Ölsläpp för ${DateFormat('yyyy-MM-dd').format(parsedDate)}' + ' nya öl:' + '\n\n' + '$beerStr'); + + final content = slappMessage.content; + + if (content!.length > 2000) { + slappMessage.content = content.substring( + 0, content.substring(0, 1999).lastIndexOf('- ') - 1) + '\n...'; } await ctx.respond(slappMessage); return; } } - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' Fanns inget ölsläpp för ' + + await ctx.respond(MessageBuilder( + content: 'Fanns inget ölsläpp för ' + DateFormat('yyyy-MM-dd').format(parsedDate))); return; } } - await ctx.respond(MessageBuilder.content(ctx.interaction.userAuthor!.mention + - ' Are you drunk buddy? I only accept ***/release YYYY-MM-dd***')); + await ctx.respond(MessageBuilder( + content: 'Are you drunk buddy? I only accept ***/release YYYY-MM-dd***')); } diff --git a/bin/modules/beer_agent/models/beer.dart b/bin/modules/beer_agent/models/beer.dart index 84416e0..b839d2b 100644 --- a/bin/modules/beer_agent/models/beer.dart +++ b/bin/modules/beer_agent/models/beer.dart @@ -1,7 +1,5 @@ import 'dart:math'; -import 'package:nyxx/nyxx.dart'; - class Beer { final int id; final int sysid; @@ -41,8 +39,7 @@ class Beer { score = Random().nextInt(100); String buildBeerMessage() { - var title = MessageDecoration.underline.format( - MessageDecoration.bold.format(name + ' ' + alcohol_vol + '%\n')); + var title = (name + ' ' + alcohol_vol + '%\n'); return title; } } diff --git a/bin/modules/bot_module.dart b/bin/modules/bot_module.dart index 651b216..280dd8e 100644 --- a/bin/modules/bot_module.dart +++ b/bin/modules/bot_module.dart @@ -1,12 +1,12 @@ import 'package:nyxx/nyxx.dart'; -import 'package:nyxx_interactions/nyxx_interactions.dart'; +import 'package:nyxx_commands/nyxx_commands.dart'; abstract class BotModule { /// Initializes the module - void init(INyxxWebsocket bot); + void init(NyxxGateway bot); /// Returns the list of commands for the module - List get commands; + List get commands; /// Returns the help message for the module MessageBuilder get helpMessage; diff --git a/bin/modules/untappd/commands.dart b/bin/modules/untappd/commands.dart index 1ea5c0e..76e74f7 100644 --- a/bin/modules/untappd/commands.dart +++ b/bin/modules/untappd/commands.dart @@ -1,40 +1,37 @@ part of 'untapped_module.dart'; -Future _untappdCommand(ISlashCommandInteractionEvent ctx) async { +Future _untappdCommand(ChatContext ctx) async { var box = Hive.box(HiveConstants.untappdBox); if (box.get(HiveConstants.untappdUpdateChannelId) == null) { - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' Whops, ask your admin to run setup first! :beers:')); + await ctx.respond(MessageBuilder( + content: 'Whops, ask your admin to run setup first! :beers:')); return; } - if (ctx.args.length != 1) { - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' Are you drunk buddy? Your username is missing.')); + if (ctx.arguments.length != 1) { + await ctx.respond(MessageBuilder( + content: 'Are you drunk buddy? Your username is missing.')); } - var discordUser = ctx.interaction.userAuthor!.id; - var untappdUsername = ctx.args.first.value; + var discordUser = ctx.user.id; + var untappdUsername = ctx.arguments.first.value; if (!await UntappdModule()._regUntappdUser(discordUser, untappdUsername)) { - await ctx.respond(MessageBuilder.content( - ctx.interaction.userAuthor!.mention + - ' Whops, something went sideways! :beers:')); + await ctx.respond( + MessageBuilder(content: 'Whops, something went sideways! :beers:')); } - await ctx.respond(MessageBuilder.content(ctx.interaction.userAuthor!.mention + - ' From now on I will post your updates from untappd! :beers:')); + await ctx.respond(MessageBuilder( + content: 'From now on I will post your updates from untappd! :beers:')); } -Future _setupUntappdServiceCommand( - ISlashCommandInteractionEvent ctx) async { - if (ctx.interaction.memberAuthorPermissions?.administrator ?? false) { - var beerUpdateChannel = await ctx.interaction.channel.getOrDownload(); +Future _setupUntappdServiceCommand(ChatContext ctx) async { + if (ctx.member?.permissions?.isAdministrator ?? false) { + var beerUpdateChannel = ctx.channel; var box = Hive.box(HiveConstants.untappdBox); await box.put( HiveConstants.untappdUpdateChannelId, beerUpdateChannel.id.toString()); - await beerUpdateChannel.sendMessage(MessageBuilder.content( - ' I will post untappd updates to this channel! Ask your users to register their username with /untappd followed by their untappd username.')); + await beerUpdateChannel.sendMessage(MessageBuilder( + content: + ' I will post untappd updates to this channel! Ask your users to register their username with /untappd followed by their untappd username.')); } } diff --git a/bin/modules/untappd/untapped_module.dart b/bin/modules/untappd/untapped_module.dart index 9449f78..28a5bf4 100644 --- a/bin/modules/untappd/untapped_module.dart +++ b/bin/modules/untappd/untapped_module.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:hive/hive.dart'; import 'package:nyxx/nyxx.dart'; -import 'package:nyxx_interactions/nyxx_interactions.dart'; +import 'package:nyxx_commands/nyxx_commands.dart'; import 'package:web_scraper/web_scraper.dart'; import '../bot_module.dart'; @@ -16,7 +16,7 @@ class UntappdModule extends BotModule { bool _isInitialized = false; - late INyxxWebsocket _bot; + late NyxxGateway _bot; factory UntappdModule() { return _singleton; @@ -31,7 +31,7 @@ class UntappdModule extends BotModule { } var box = Hive.box(HiveConstants.untappdBox); - Map listOfUsers = + Map listOfUsers = await box.get(HiveConstants.untappdUserList, defaultValue: {}); var latestCheckins = await box .get(HiveConstants.untappdLatestUserCheckins, defaultValue: {}); @@ -59,35 +59,41 @@ class UntappdModule extends BotModule { HiveConstants.untappdLatestUserCheckins, latestCheckins); // Build update message with info from untappd checkin - var user = await _bot.fetchUser(Snowflake(userSnowflake)); + var user = await _bot.users.fetch(Snowflake(userSnowflake)); var embedBuilder = EmbedBuilder(); embedBuilder.title = '${user.username} is drinking beer!'; - embedBuilder.url = - _getCheckinUrl(latestCheckinUntappd.id, untappdUsername); + embedBuilder.url = Uri.dataFromString( + _getCheckinUrl(latestCheckinUntappd.id, untappdUsername)); embedBuilder.description = latestCheckinUntappd.title; if (latestCheckinUntappd.comment.isNotEmpty) { - embedBuilder.addField( - field: - EmbedFieldBuilder('Comment', latestCheckinUntappd.comment)); + embedBuilder.fields?.add(EmbedFieldBuilder( + name: 'Comment', + value: latestCheckinUntappd.comment, + isInline: false)); } if (latestCheckinUntappd.rating.isNotEmpty) { - embedBuilder.addField( - field: EmbedFieldBuilder( - 'Rating', - _buildRatingEmoji( - double.parse(latestCheckinUntappd.rating)))); + embedBuilder.fields?.add( + EmbedFieldBuilder( + name: 'Rating', + value: _buildRatingEmoji( + double.parse(latestCheckinUntappd.rating), + ), + isInline: false, + ), + ); } if (latestCheckinUntappd.photoAddress != null) { - embedBuilder.imageUrl = latestCheckinUntappd.photoAddress; + embedBuilder.image?.url = + Uri.dataFromString(latestCheckinUntappd.photoAddress!); } // Get channel used for untappd updates, previously set by discord admin. - var updateChannel = await _bot - .fetchChannel(Snowflake(updateChannelId)) - .then((value) => (value as ITextChannel)); + var updateChannel = await _bot.channels + .fetch(Snowflake(updateChannelId)) as PartialTextChannel; // Send update message - await updateChannel.sendMessage(MessageBuilder.embed(embedBuilder)); + await updateChannel + .sendMessage(MessageBuilder(embeds: [embedBuilder])); } // Sleep 5 seconds per user to avoid suspicious requests to untappd server await Future.delayed(Duration(seconds: 5)); @@ -149,6 +155,7 @@ class UntappdModule extends BotModule { /// Get latest checkin for given untapped username Future _getLatestCheckin(String untappdUsername) async { final webScraper = WebScraper('https://untappd.com'); + if (await webScraper.loadWebPage('/user/$untappdUsername')) { final checkins = webScraper.getElementAttribute( 'div#main-stream > *', 'data-checkin-id'); @@ -199,7 +206,7 @@ class UntappdModule extends BotModule { 'https://untappd.com/user/$username/checkin/$checkinId'; @override - void init(INyxxWebsocket bot, + void init(NyxxGateway bot, {Duration updateInterval = const Duration(minutes: 12)}) { // Set up Hive for local data storage Hive.init('/data'); @@ -215,44 +222,62 @@ class UntappdModule extends BotModule { } @override - List get commands => !_isInitialized + List get commands => !_isInitialized ? throw Exception('Untappd module not initialized!') : [ - SlashCommandBuilder( + ChatCommand('untappd', + 'Let me know your untappd username so I can post automatic updates from your untappd account.', + (ChatContext context) async { + await _untappdCommand(context); + }), + ChatCommand( 'untappd', 'Let me know your untappd username so I can post automatic updates from your untappd account.', - [ - CommandOptionBuilder(CommandOptionType.string, 'username', - 'e.g. cornholio (kontot måste minst ha 1 incheckning)', - required: true), - ], - )..registerHandler((event) async { - await event.acknowledge(); - await _untappdCommand(event); - }), - SlashCommandBuilder( + ( + ChatContext context, [ + @Description( + 'e.g. cornholio (kontot måste minst ha 1 incheckning)') + String? username, + ]) async { + if (username == null) { + await context.respond(MessageBuilder( + content: 'Are you drunk buddy? Your username is missing.')); + return; + } + await _untappdCommand(context); + }, + options: CommandOptions( + autoAcknowledgeInteractions: true, + type: CommandType.slashOnly, + ), + ), + ChatCommand( 'setup', 'Setup the bot to post untappd updates to the current channel.', - [], - requiredPermissions: PermissionsConstants.administrator, - )..registerHandler((event) async { - await event.acknowledge(); - await _setupUntappdServiceCommand(event); - }), + (ChatContext context) async { + context.member?.permissions?.isAdministrator ?? false + ? await _setupUntappdServiceCommand(context) + : await context.respond(MessageBuilder( + content: 'Only admins can issue this command!')); + }, + options: CommandOptions( + autoAcknowledgeInteractions: true, + type: CommandType.slashOnly, + ), + ), ]; @override MessageBuilder get helpMessage => !_isInitialized ? throw Exception('Untappd module not initialized!') - : MessageBuilder() - ..appendBold('/untappd') - ..appendNewLine() - ..append( - 'Registers your untappd username so I can post automatic updates based on your untappd checkins.') - ..appendNewLine() - ..appendNewLine() - ..appendBold('/setup') - ..appendNewLine() - ..append( - 'Setup the bot to post untappd updates to the current channel. (Only admins can issue this command.)'); + : MessageBuilder( + content: '**Untappd Module**\n\n' + 'This module allows you to post automatic updates from your untappd account.' + '\n\n' + '**Commands**\n' + '/untappd\n' + 'Registers your untappd username so I can post automatic updates based on your untappd checkins.\n\n' + '/setup\n' + 'Setup the bot to post untappd updates to the current channel. (Only admins can issue this command.)', + ); } diff --git a/pubspec.yaml b/pubspec.yaml index c4f717c..db77835 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,19 +2,20 @@ name: Agent_S description: The Dart Discord bot for beer lovers in Sweden. version: 1.0.0 homepage: https://github.com/oelburk/agentsbot +publish_to: none environment: sdk: ">=3.0.0 <4.0.0" dependencies: hive: ^2.2.3 - intl: ^0.18.1 - nyxx: ^5.1.0 - nyxx_commands: ^5.0.2 - nyxx_interactions: ^4.6.0 - web_scraper: ^0.1.4 + intl: ^0.20.2 + nyxx: ^6.5.2 + nyxx_commands: ^6.0.3 + web_scraper: + git: https://github.com/oelburk/web_scraper.git dev_dependencies: - lints: ^2.1.1 + lints: ^5.1.1 test: ^1.24.4 pedantic: ^1.11.1