diff --git a/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb b/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb
index 3afcd45..fac7736 100644
--- a/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb
+++ b/BirthdayBot/BackgroundServices/BirthdayRoleUpdate.vb
@@ -69,10 +69,11 @@ Class BirthdayRoleUpdate
If gs.AnnounceChannelId.HasValue Then channel = guild.GetTextChannel(gs.AnnounceChannelId.Value)
If gs.RoleId.HasValue Then role = guild.GetRole(gs.RoleId.Value)
If role Is Nothing Then
- gs.RoleWarning = True
+ gs.RoleWarningNonexist = True
Return 0
+ Else
+ gs.RoleWarningNonexist = False
End If
- gs.RoleWarning = False
End SyncLock
' Determine who's currently having a birthday
@@ -81,28 +82,29 @@ Class BirthdayRoleUpdate
' Set birthday roles, get list of users that had the role added
' But first check if we are able to do so. Letting all requests fail instead will lead to rate limiting.
- Dim announceNames As IEnumerable(Of SocketGuildUser)
- If HasCorrectRolePermissions(guild, role) Then
+ Dim correctRolePermissions = HasCorrectRolePermissions(guild, role)
+ Dim gotForbidden = False
+
+ Dim announceNames As IEnumerable(Of SocketGuildUser) = Nothing
+ If correctRolePermissions Then
Try
announceNames = Await UpdateGuildBirthdayRoles(guild, role, birthdays)
Catch ex As Discord.Net.HttpException
If ex.HttpCode = HttpStatusCode.Forbidden Then
- announceNames = Nothing
+ gotForbidden = True
Else
Throw
End If
End Try
- Else
- announceNames = Nothing
End If
- If announceNames Is Nothing Then
- SyncLock BotInstance.KnownGuilds
- ' Nothing on announceNAmes signals failure to apply roles. Set the warning message.
- BotInstance.KnownGuilds(guild.Id).RoleWarning = True
- End SyncLock
- Return 0
- End If
+ ' Update warning flag
+ Dim updateError = Not correctRolePermissions Or gotForbidden
+ SyncLock BotInstance.KnownGuilds
+ BotInstance.KnownGuilds(guild.Id).RoleWarningPermission = updateError
+ End SyncLock
+ ' Quit now if the warning flag was set. Announcement data is not available.
+ If updateError Then Return 0
If announceNames.Count <> 0 Then
' Send out announcement message
diff --git a/BirthdayBot/BirthdayBot.vb b/BirthdayBot/BirthdayBot.vb
index a6a45aa..47685bd 100644
--- a/BirthdayBot/BirthdayBot.vb
+++ b/BirthdayBot/BirthdayBot.vb
@@ -26,12 +26,12 @@ Class BirthdayBot
End Property
''' SyncLock when using. The lock object is itself.
- Friend ReadOnly Property KnownGuilds As Dictionary(Of ULong, GuildSettings)
+ Friend ReadOnly Property KnownGuilds As Dictionary(Of ULong, GuildStateInformation)
Public Sub New(conf As Configuration, dc As DiscordSocketClient)
Config = conf
_client = dc
- KnownGuilds = New Dictionary(Of ULong, GuildSettings)
+ KnownGuilds = New Dictionary(Of ULong, GuildStateInformation)
_worker = New BackgroundServiceRunner(Me)
@@ -75,7 +75,7 @@ Class BirthdayBot
Private Function LoadGuild(g As SocketGuild) As Task Handles _client.JoinedGuild, _client.GuildAvailable
SyncLock KnownGuilds
If Not KnownGuilds.ContainsKey(g.Id) Then
- Dim gi = GuildSettings.LoadSettingsAsync(Config.DatabaseSettings, g.Id).GetAwaiter().GetResult()
+ Dim gi = GuildStateInformation.LoadSettingsAsync(Config.DatabaseSettings, g.Id).GetAwaiter().GetResult()
KnownGuilds.Add(g.Id, gi)
End If
End SyncLock
@@ -114,7 +114,7 @@ Class BirthdayBot
End If
' Ban and role warning check
- Dim roleWarning As Boolean
+ Dim roleWarningText As String
SyncLock KnownGuilds
Dim gi = KnownGuilds(channel.Guild.Id)
@@ -125,13 +125,13 @@ Class BirthdayBot
End If
End If
- roleWarning = gi.RoleWarning
+ roleWarningText = gi.IssueRoleWarning
End SyncLock
Try
- If roleWarning Then
+ If roleWarningText IsNot Nothing Then
Try
- Await channel.SendMessageAsync(RoleWarningMsg)
+ Await channel.SendMessageAsync(roleWarningText)
Catch ex As HttpException
' Don't let this prevent the bot from continuing command execution.
End Try
diff --git a/BirthdayBot/Data/Database.vb b/BirthdayBot/Data/Database.vb
index 1300e47..17c4a90 100644
--- a/BirthdayBot/Data/Database.vb
+++ b/BirthdayBot/Data/Database.vb
@@ -26,7 +26,7 @@ Class Database
Private Sub SetupTables()
Using db = OpenConnectionAsync().GetAwaiter().GetResult()
- GuildSettings.SetUpDatabaseTable(db) ' Note: Call this first. (Foreign reference constraints.)
+ GuildStateInformation.SetUpDatabaseTable(db) ' Note: Call this first. (Foreign reference constraints.)
GuildUserSettings.SetUpDatabaseTable(db)
End Using
End Sub
diff --git a/BirthdayBot/Data/GuildSettings.vb b/BirthdayBot/Data/GuildStateInformation.vb
similarity index 86%
rename from BirthdayBot/Data/GuildSettings.vb
rename to BirthdayBot/Data/GuildStateInformation.vb
index 7dccbef..0eeeb6a 100644
--- a/BirthdayBot/Data/GuildSettings.vb
+++ b/BirthdayBot/Data/GuildStateInformation.vb
@@ -4,11 +4,10 @@ Imports Npgsql
Imports NpgsqlTypes
'''
-''' Collection of GuildUserSettings instances. Holds cached information on guild users and overall
-''' guild options, and provides some database abstractions regarding them all.
-''' Object instances are loaded when entering a guild and discarded when the bot leaves the guild.
+''' Holds various pieces of state information for a guild the bot is operating in.
+''' Includes, among other things, a copy of the guild's settings and a list of all known users with birthdays.
'''
-Friend Class GuildSettings
+Friend Class GuildStateInformation
Public ReadOnly Property GuildId As ULong
Private ReadOnly _db As Database
Private _bdayRole As ULong?
@@ -19,33 +18,55 @@ Friend Class GuildSettings
Private _announceMsg As String
Private _announceMsgPl As String
Private _announcePing As Boolean
- Private _userCache As Dictionary(Of ULong, GuildUserSettings)
+ Private ReadOnly _userCache As Dictionary(Of ULong, GuildUserSettings)
- Private _roleWarning As Boolean
Private _roleLastWarning As New DateTimeOffset(DateTime.MinValue, TimeSpan.Zero)
Private Shared ReadOnly RoleWarningInterval As New TimeSpan(1, 0, 0)
'''
- ''' Flag for notifying servers that the bot is unable to manipulate its role.
- ''' Can be set at any time. Reading this will only return True if it's been set as such,
- ''' and it is only returned after a set time has passed in order to not constantly show the message.
+ ''' Message for notifying servers that the bot is unable to manipulate its designated role for various reasons.
+ ''' The returned value is dependent on certain warning flags accessible in this class. To avoid bombarding users
+ ''' with the same message, this property only returns a non-Nothing value at most once per hour.
+ ''' Otherwise, it shall always return Nothing if there is no warning to be issued.
'''
- Public Property RoleWarning As Boolean
+ Public ReadOnly Property IssueRoleWarning As String
Get
- If _roleWarning = True Then
- ' Only report a warning every so often.
- If DateTimeOffset.UtcNow - _roleLastWarning > RoleWarningInterval Then
- _roleLastWarning = DateTimeOffset.UtcNow
- Return True
- Else
- Return False
- End If
+ If DateTimeOffset.UtcNow - _roleLastWarning > RoleWarningInterval Then
+ _roleLastWarning = DateTimeOffset.UtcNow
+ Else
+ Return Nothing
End If
- Return False
+
+ If RoleWarningUnset Or RoleWarningNonexist Then
+ Return "Warning: A birthday role must be configured before this bot can function properly. " +
+ "Update the designated role with `bb.config role (role name/ID)`."
+ End If
+ If RoleWarningPermission Then
+ Return "Warning: This bot is unable to set the birthday role onto users. " +
+ "Make sure that this bot has the Manage Roles permission and is not placed below the birthday role."
+ End If
+
+ Return Nothing
+ End Get
+ End Property
+
+ '''
+ ''' Role warning message: The birthday role cannot be accessed.
+ '''
+ Friend Property RoleWarningPermission As Boolean = False
+
+ '''
+ ''' Role warning message: The birthday role no longer exists.
+ '''
+ Friend Property RoleWarningNonexist As Boolean = False
+
+ '''
+ ''' Role warning message: The birthday role is not set.
+ '''
+ Friend ReadOnly Property RoleWarningUnset As Boolean
+ Get
+ Return _bdayRole Is Nothing
End Get
- Set(value As Boolean)
- _roleWarning = value
- End Set
End Property
'''
@@ -132,9 +153,6 @@ Friend Class GuildSettings
' Weird: if using a ternary operator with a ULong?, Nothing resolves to 0 despite Option Strict On.
If Not reader.IsDBNull(1) Then
_bdayRole = CULng(reader.GetInt64(1))
- RoleWarning = False
- Else
- RoleWarning = True
End If
If Not reader.IsDBNull(2) Then _announceCh = CULng(reader.GetInt64(2))
_tz = If(reader.IsDBNull(3), Nothing, reader.GetString(3))
@@ -253,7 +271,6 @@ Friend Class GuildSettings
Public Async Function UpdateRoleAsync(roleId As ULong) As Task
_bdayRole = roleId
- _roleWarning = False
_roleLastWarning = New DateTimeOffset
Await UpdateDatabaseAsync()
End Function
@@ -326,7 +343,7 @@ Friend Class GuildSettings
''' Retrieves an object instance representative of guild settings for the specified guild.
''' If settings for the given guild do not yet exist, a new value is created.
'''
- Friend Shared Async Function LoadSettingsAsync(dbsettings As Database, guild As ULong) As Task(Of GuildSettings)
+ Friend Shared Async Function LoadSettingsAsync(dbsettings As Database, guild As ULong) As Task(Of GuildStateInformation)
Using db = Await dbsettings.OpenConnectionAsync()
Using c = db.CreateCommand()
' Take note of ordinals for use in the constructor
@@ -336,7 +353,7 @@ Friend Class GuildSettings
c.Prepare()
Using r = Await c.ExecuteReaderAsync()
If Await r.ReadAsync() Then
- Return New GuildSettings(r, dbsettings)
+ Return New GuildStateInformation(r, dbsettings)
End If
End Using
End Using
diff --git a/BirthdayBot/Data/GuildUserSettings.vb b/BirthdayBot/Data/GuildUserSettings.vb
index 257f1d0..d86d573 100644
--- a/BirthdayBot/Data/GuildUserSettings.vb
+++ b/BirthdayBot/Data/GuildUserSettings.vb
@@ -4,7 +4,7 @@ Imports NpgsqlTypes
'''
''' Representation of a user's birthday settings within a guild.
-''' Instances are held and managed by .
+''' Instances are held and managed by .
'''
Class GuildUserSettings
Private _month As Integer
@@ -125,7 +125,7 @@ Class GuildUserSettings
Friend Shared Sub SetUpDatabaseTable(db As NpgsqlConnection)
Using c = db.CreateCommand()
c.CommandText = $"create table if not exists {BackingTable} (" +
- $"guild_id bigint not null references {GuildSettings.BackingTable}, " +
+ $"guild_id bigint not null references {GuildStateInformation.BackingTable}, " +
"user_id bigint not null, " +
"birth_month integer not null, " +
"birth_day integer not null, " +