mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-25 01:44:12 +00:00
Add listing commands
This commit is contained in:
parent
25901b0d2e
commit
d53944818c
4 changed files with 246 additions and 2 deletions
|
@ -10,6 +10,7 @@ Class BirthdayBot
|
||||||
|
|
||||||
Private ReadOnly _dispatchCommands As Dictionary(Of String, CommandHandler)
|
Private ReadOnly _dispatchCommands As Dictionary(Of String, CommandHandler)
|
||||||
Private ReadOnly _cmdsUser As UserCommands
|
Private ReadOnly _cmdsUser As UserCommands
|
||||||
|
Private ReadOnly _cmdsListing As ListingCommands
|
||||||
Private ReadOnly _cmdsHelp As HelpInfoCommands
|
Private ReadOnly _cmdsHelp As HelpInfoCommands
|
||||||
Private ReadOnly _cmdsMods As ManagerCommands
|
Private ReadOnly _cmdsMods As ManagerCommands
|
||||||
|
|
||||||
|
@ -40,6 +41,10 @@ Class BirthdayBot
|
||||||
For Each item In _cmdsUser.Commands
|
For Each item In _cmdsUser.Commands
|
||||||
_dispatchCommands.Add(item.Item1, item.Item2)
|
_dispatchCommands.Add(item.Item1, item.Item2)
|
||||||
Next
|
Next
|
||||||
|
_cmdsListing = New ListingCommands(Me, conf)
|
||||||
|
For Each item In _cmdsListing.Commands
|
||||||
|
_dispatchCommands.Add(item.Item1, item.Item2)
|
||||||
|
Next
|
||||||
_cmdsHelp = New HelpInfoCommands(Me, conf, DiscordClient)
|
_cmdsHelp = New HelpInfoCommands(Me, conf, DiscordClient)
|
||||||
For Each item In _cmdsHelp.Commands
|
For Each item In _cmdsHelp.Commands
|
||||||
_dispatchCommands.Add(item.Item1, item.Item2)
|
_dispatchCommands.Add(item.Item1, item.Item2)
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>BirthdayBot</RootNamespace>
|
<RootNamespace>BirthdayBot</RootNamespace>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
<Version>0.9.0</Version>
|
<Version>1.0.0</Version>
|
||||||
<AssemblyVersion>0.9.0.0</AssemblyVersion>
|
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||||
<Authors>Noiiko</Authors>
|
<Authors>Noiiko</Authors>
|
||||||
<Company />
|
<Company />
|
||||||
<Description>Discord bot for birthday reminders.</Description>
|
<Description>Discord bot for birthday reminders.</Description>
|
||||||
|
|
|
@ -37,6 +37,8 @@ Friend Class HelpInfoCommands
|
||||||
.Value =
|
.Value =
|
||||||
$"{cpfx}help`, `{CommandPrefix}info`, `{CommandPrefix}help-tzdata`" + vbLf +
|
$"{cpfx}help`, `{CommandPrefix}info`, `{CommandPrefix}help-tzdata`" + vbLf +
|
||||||
$" » Help and informational messages." + vbLf +
|
$" » Help and informational messages." + vbLf +
|
||||||
|
$"{cpfx}recent` and `{CommandPrefix}upcoming`" + vbLf +
|
||||||
|
$" » Lists recent and upcoming birthdays." + vbLf +
|
||||||
$"{cpfx}set (date) [zone]`" + vbLf +
|
$"{cpfx}set (date) [zone]`" + vbLf +
|
||||||
$" » Registers your birth date. Time zone is optional." + vbLf +
|
$" » Registers your birth date. Time zone is optional." + vbLf +
|
||||||
$" »» Examples: `{CommandPrefix}set jan-31`, `{CommandPrefix}set 15-aug America/Los_Angeles`." + vbLf +
|
$" »» Examples: `{CommandPrefix}set jan-31`, `{CommandPrefix}set 15-aug America/Los_Angeles`." + vbLf +
|
||||||
|
@ -50,6 +52,8 @@ Friend Class HelpInfoCommands
|
||||||
.Value =
|
.Value =
|
||||||
$"{cpfx}config`" + vbLf +
|
$"{cpfx}config`" + vbLf +
|
||||||
$" » Edit bot configuration. See `{CommandPrefix}help-config`." + vbLf +
|
$" » Edit bot configuration. See `{CommandPrefix}help-config`." + vbLf +
|
||||||
|
$"{cpfx}list`" + vbLf +
|
||||||
|
$" » Exports all known birthdays to file." + vbLf +
|
||||||
$"{cpfx}override (user ping or ID) (command w/ parameters)`" + vbLf +
|
$"{cpfx}override (user ping or ID) (command w/ parameters)`" + vbLf +
|
||||||
" » Perform certain commands on behalf of another user."
|
" » Perform certain commands on behalf of another user."
|
||||||
}
|
}
|
||||||
|
|
235
BirthdayBot/UserInterface/ListingCommands.vb
Normal file
235
BirthdayBot/UserInterface/ListingCommands.vb
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
Imports System.IO
|
||||||
|
Imports System.Text
|
||||||
|
Imports Discord.WebSocket
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Commands for listing upcoming and all birthdays.
|
||||||
|
''' </summary>
|
||||||
|
Class ListingCommands
|
||||||
|
Inherits CommandsCommon
|
||||||
|
Public Overrides ReadOnly Property Commands As IEnumerable(Of (String, CommandHandler))
|
||||||
|
Get
|
||||||
|
Return New List(Of (String, CommandHandler)) From {
|
||||||
|
("list", AddressOf CmdList),
|
||||||
|
("upcoming", AddressOf CmdUpcoming),
|
||||||
|
("recent", AddressOf CmdUpcoming)
|
||||||
|
}
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
|
Sub New(inst As BirthdayBot, db As Configuration)
|
||||||
|
MyBase.New(inst, db)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
' Creates a file with all birthdays.
|
||||||
|
Private Async Function CmdList(param As String(), reqChannel As SocketTextChannel, reqUser As SocketGuildUser) As Task
|
||||||
|
' For now, we're restricting this command to moderators only. This may turn into an option later.
|
||||||
|
Dim reqMod As Boolean
|
||||||
|
SyncLock Instance.KnownGuilds
|
||||||
|
reqMod = Instance.KnownGuilds(reqChannel.Guild.Id).IsUserModerator(reqUser)
|
||||||
|
End SyncLock
|
||||||
|
|
||||||
|
If Not reqMod Then
|
||||||
|
Await reqChannel.SendMessageAsync(":x: Only bot moderators may use this command.")
|
||||||
|
Return
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim bdlist = Await BuildList(reqChannel.Guild, False)
|
||||||
|
|
||||||
|
Dim filepath = Path.GetTempPath() + "birthdaybot-" + reqChannel.Guild.Id.ToString() + ".txt"
|
||||||
|
Using f = File.CreateText(filepath)
|
||||||
|
f.WriteLine("Birthdays in " + reqChannel.Guild.Name)
|
||||||
|
f.WriteLine()
|
||||||
|
For Each item In bdlist
|
||||||
|
Dim user = reqChannel.Guild.GetUser(item.UserId)
|
||||||
|
If user Is Nothing Then Continue For ' User disappeared in the instant between getting list and processing
|
||||||
|
f.Write($"● {MonthNames(item.BirthMonth)}-{item.BirthDay.ToString("00")}: ")
|
||||||
|
f.Write(item.UserId)
|
||||||
|
f.Write(" " + user.Username + "#" + user.Discriminator)
|
||||||
|
If user.Nickname IsNot Nothing Then
|
||||||
|
f.Write(" - Nickname: " + user.Nickname)
|
||||||
|
End If
|
||||||
|
f.WriteLine()
|
||||||
|
Next
|
||||||
|
Await f.FlushAsync()
|
||||||
|
End Using
|
||||||
|
|
||||||
|
Try
|
||||||
|
Await reqChannel.SendFileAsync(filepath, $"Exported {bdlist.Count} birthdays to file.")
|
||||||
|
Catch ex As Discord.Net.HttpException
|
||||||
|
reqChannel.SendMessageAsync(":x: Unable to send list due to a permissions issue. Check the 'Attach Files' permission.").Wait()
|
||||||
|
Catch ex As Exception
|
||||||
|
Log("Listing", ex.ToString())
|
||||||
|
reqChannel.SendMessageAsync(":x: An internal error occurred. It has been reported to the bot owner.").Wait()
|
||||||
|
Finally
|
||||||
|
File.Delete(filepath)
|
||||||
|
End Try
|
||||||
|
End Function
|
||||||
|
|
||||||
|
' "Recent and upcoming birthdays"
|
||||||
|
' The 'recent' bit removes time zone ambiguity and spares us from extra time zone processing here
|
||||||
|
Private Async Function CmdUpcoming(param As String(), reqChannel As SocketTextChannel, reqUser As SocketGuildUser) As Task
|
||||||
|
Dim now = DateTimeOffset.UtcNow
|
||||||
|
Dim search = DateIndex(now.Month, now.Day) - 4 ' begin search 4 days prior to current date UTC
|
||||||
|
If search <= 0 Then search = 366 - Math.Abs(search)
|
||||||
|
|
||||||
|
Dim query = Await BuildList(reqChannel.Guild, True)
|
||||||
|
If query.Count = 0 Then
|
||||||
|
Await reqChannel.SendMessageAsync("There are currently no recent or upcoming birthdays.")
|
||||||
|
Return
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim output As New StringBuilder()
|
||||||
|
output.AppendLine("Recent and upcoming birthdays:")
|
||||||
|
For count = 1 To 11 ' cover 11 days total (3 prior, current day, 7 upcoming
|
||||||
|
Dim results = From item In query
|
||||||
|
Where item.DateIndex = search
|
||||||
|
Select item
|
||||||
|
|
||||||
|
' push up search by 1 now, in case we back out early
|
||||||
|
search += 1
|
||||||
|
If search > 366 Then search = 1 ' wrap to beginning of year
|
||||||
|
|
||||||
|
If results.Count = 0 Then Continue For ' back out early
|
||||||
|
|
||||||
|
' Build sorted name list
|
||||||
|
Dim names As New List(Of String)
|
||||||
|
For Each item In results
|
||||||
|
names.Add(item.DisplayName)
|
||||||
|
Next
|
||||||
|
names.Sort(StringComparer.InvariantCultureIgnoreCase)
|
||||||
|
|
||||||
|
Dim first = True
|
||||||
|
output.AppendLine()
|
||||||
|
output.Append($"● `{MonthNames(results(0).BirthMonth)}-{results(0).BirthDay.ToString("00")}`: ")
|
||||||
|
For Each item In names
|
||||||
|
If first Then
|
||||||
|
first = False
|
||||||
|
Else
|
||||||
|
output.Append(", ")
|
||||||
|
End If
|
||||||
|
output.Append(item)
|
||||||
|
Next
|
||||||
|
Next
|
||||||
|
|
||||||
|
Await reqChannel.SendMessageAsync(output.ToString())
|
||||||
|
End Function
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Fetches all guild birthdays and places them into an easily usable structure.
|
||||||
|
''' Users currently not in the guild are not included in the result.
|
||||||
|
''' </summary>
|
||||||
|
Private Async Function BuildList(guild As SocketGuild, escapeFormat As Boolean) As Task(Of List(Of ListItem))
|
||||||
|
Dim ping As Boolean
|
||||||
|
SyncLock Instance.KnownGuilds
|
||||||
|
ping = Instance.KnownGuilds(guild.Id).AnnouncePing
|
||||||
|
End SyncLock
|
||||||
|
|
||||||
|
Using db = Await BotConfig.DatabaseSettings.OpenConnectionAsync()
|
||||||
|
Using c = db.CreateCommand()
|
||||||
|
c.CommandText = "select user_id, birth_month, birth_day from " + GuildUserSettings.BackingTable +
|
||||||
|
" where guild_id = @Gid order by birth_month, birth_day"
|
||||||
|
c.Parameters.Add("@Gid", NpgsqlTypes.NpgsqlDbType.Bigint).Value = guild.Id
|
||||||
|
c.Prepare()
|
||||||
|
Using r = Await c.ExecuteReaderAsync()
|
||||||
|
Dim result As New List(Of ListItem)
|
||||||
|
While Await r.ReadAsync()
|
||||||
|
Dim id = CULng(r.GetInt64(0))
|
||||||
|
Dim month = r.GetInt32(1)
|
||||||
|
Dim day = r.GetInt32(2)
|
||||||
|
|
||||||
|
Dim guildUser = guild.GetUser(id)
|
||||||
|
If guildUser Is Nothing Then Continue While ' Skip users not in guild
|
||||||
|
|
||||||
|
result.Add(New ListItem With {
|
||||||
|
.BirthMonth = month,
|
||||||
|
.BirthDay = day,
|
||||||
|
.DateIndex = DateIndex(month, day),
|
||||||
|
.UserId = guildUser.Id,
|
||||||
|
.DisplayName = FormatName(guildUser, False)
|
||||||
|
})
|
||||||
|
End While
|
||||||
|
Return result
|
||||||
|
End Using
|
||||||
|
End Using
|
||||||
|
End Using
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Private Function DateIndex(month As Integer, day As Integer) As Integer
|
||||||
|
DateIndex = 0
|
||||||
|
' Add month offset
|
||||||
|
If month > 1 Then DateIndex += 31 ' Offset January
|
||||||
|
If month > 2 Then DateIndex += 29 ' Offset February (incl. leap day)
|
||||||
|
If month > 3 Then DateIndex += 31 ' etc
|
||||||
|
If month > 4 Then DateIndex += 30
|
||||||
|
If month > 5 Then DateIndex += 31
|
||||||
|
If month > 6 Then DateIndex += 30
|
||||||
|
If month > 7 Then DateIndex += 31
|
||||||
|
If month > 8 Then DateIndex += 31
|
||||||
|
If month > 9 Then DateIndex += 30
|
||||||
|
If month > 10 Then DateIndex += 31
|
||||||
|
If month > 11 Then DateIndex += 30
|
||||||
|
DateIndex += day
|
||||||
|
End Function
|
||||||
|
|
||||||
|
''' <summary>
|
||||||
|
''' Translate from date index value to readable date.
|
||||||
|
''' </summary>
|
||||||
|
Private Function FromDateIndex(ByVal index As Integer) As String
|
||||||
|
' oh no...
|
||||||
|
FromDateIndex = "Jan"
|
||||||
|
If index > 31 Then
|
||||||
|
index -= 31
|
||||||
|
FromDateIndex = "Feb"
|
||||||
|
End If
|
||||||
|
If index > 29 Then
|
||||||
|
index -= 29
|
||||||
|
FromDateIndex = "Mar"
|
||||||
|
End If
|
||||||
|
If index > 31 Then
|
||||||
|
index -= 31
|
||||||
|
FromDateIndex = "Apr"
|
||||||
|
End If
|
||||||
|
If index > 30 Then
|
||||||
|
index -= 30
|
||||||
|
FromDateIndex = "May"
|
||||||
|
End If
|
||||||
|
If index > 31 Then
|
||||||
|
index -= 31
|
||||||
|
FromDateIndex = "Jun"
|
||||||
|
End If
|
||||||
|
If index > 30 Then
|
||||||
|
index -= 30
|
||||||
|
FromDateIndex = "Jul"
|
||||||
|
End If
|
||||||
|
If index > 31 Then
|
||||||
|
index -= 31
|
||||||
|
FromDateIndex = "Aug"
|
||||||
|
End If
|
||||||
|
If index > 31 Then
|
||||||
|
index -= 31
|
||||||
|
FromDateIndex = "Sep"
|
||||||
|
End If
|
||||||
|
If index > 30 Then
|
||||||
|
index -= 30
|
||||||
|
FromDateIndex = "Oct"
|
||||||
|
End If
|
||||||
|
If index > 31 Then
|
||||||
|
index -= 31
|
||||||
|
FromDateIndex = "Nov"
|
||||||
|
End If
|
||||||
|
If index > 30 Then
|
||||||
|
index -= 30
|
||||||
|
FromDateIndex = "Dec"
|
||||||
|
End If
|
||||||
|
FromDateIndex += " " + index.ToString("00")
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Private Structure ListItem
|
||||||
|
Public Property DateIndex As Integer
|
||||||
|
Public Property BirthMonth As Integer
|
||||||
|
Public Property BirthDay As Integer
|
||||||
|
Public Property UserId As ULong
|
||||||
|
Public Property DisplayName As String
|
||||||
|
End Structure
|
||||||
|
End Class
|
Loading…
Reference in a new issue