mirror of
https://github.com/NoiTheCat/BirthdayBot.git
synced 2024-11-24 17:34:13 +00:00
Add more supported input formats
This commit is contained in:
parent
a0571ce3d7
commit
69583e2270
1 changed files with 102 additions and 67 deletions
|
@ -19,25 +19,32 @@ namespace BirthdayBot.UserInterface
|
||||||
("remove", CmdRemove)
|
("remove", CmdRemove)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#region Date parsing
|
||||||
|
const string FormatError = ":x: Unrecognized date format. The following formats are accepted, as examples: "
|
||||||
|
+ "`15-jan`, `jan-15`, `15 jan`, `jan 15`, `15 January`, `January 15`.";
|
||||||
|
|
||||||
|
private static readonly Regex DateParse1 = new Regex(@"^(?<day>\d{1,2})[ -](?<month>[A-Za-z]+)$", RegexOptions.Compiled);
|
||||||
|
private static readonly Regex DateParse2 = new Regex(@"^(?<month>[A-Za-z]+)[ -](?<day>\d{1,2})$", RegexOptions.Compiled);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses date parameter. Strictly takes dd-MMM or MMM-dd only. Eliminates ambiguity over dd/mm vs mm/dd.
|
/// Parses a date input.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Tuple: month, day</returns>
|
/// <returns>Tuple: month, day</returns>
|
||||||
/// <exception cref="FormatException">Thrown for any parsing issue. Reason is expected to be sent to Discord as-is.</exception>
|
/// <exception cref="FormatException">
|
||||||
|
/// Thrown for any parsing issue. Reason is expected to be sent to Discord as-is.
|
||||||
|
/// </exception>
|
||||||
private (int, int) ParseDate(string dateInput)
|
private (int, int) ParseDate(string dateInput)
|
||||||
{
|
{
|
||||||
const string FormatError = ":x: Incorrect date format. Use a three-letter abbreviation and a number separated by "
|
var m = DateParse1.Match(dateInput);
|
||||||
+ "hyphen to specify a date. Examples: `jan-15` `23-aug` `may-12` `5-jun`";
|
|
||||||
// Not doing DateTime.Parse. Setting it up is rather complicated, and it's probably case sensitive.
|
|
||||||
// Admittedly, doing it the way it's being done here probably isn't any better.
|
|
||||||
var m = Regex.Match(dateInput, @"^(?<day>\d{1,2})-(?<month>[A-Za-z]{3})$");
|
|
||||||
if (!m.Success)
|
if (!m.Success)
|
||||||
{
|
{
|
||||||
// Flip the fields around, try again
|
// Flip the fields around, try again
|
||||||
m = Regex.Match(dateInput, @"^(?<month>[A-Za-z]{3})-(?<day>\d{1,2})$");
|
m = DateParse2.Match(dateInput);
|
||||||
if (!m.Success) throw new FormatException(FormatError);
|
if (!m.Success) throw new FormatException(FormatError);
|
||||||
}
|
}
|
||||||
int day;
|
|
||||||
|
int day, month;
|
||||||
|
string monthVal;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
day = int.Parse(m.Groups["day"].Value);
|
day = int.Parse(m.Groups["day"].Value);
|
||||||
|
@ -46,60 +53,69 @@ namespace BirthdayBot.UserInterface
|
||||||
{
|
{
|
||||||
throw new Exception(FormatError);
|
throw new Exception(FormatError);
|
||||||
}
|
}
|
||||||
var monthVal = m.Groups["month"].Value;
|
monthVal = m.Groups["month"].Value;
|
||||||
int month;
|
|
||||||
var dayUpper = 31; // upper day of month check
|
int dayUpper; // upper day of month check
|
||||||
switch (monthVal.ToLower())
|
(month, dayUpper) = GetMonth(monthVal);
|
||||||
{
|
|
||||||
case "jan":
|
|
||||||
month = 1;
|
|
||||||
break;
|
|
||||||
case "feb":
|
|
||||||
month = 2;
|
|
||||||
dayUpper = 29;
|
|
||||||
break;
|
|
||||||
case "mar":
|
|
||||||
month = 3;
|
|
||||||
break;
|
|
||||||
case "apr":
|
|
||||||
month = 4;
|
|
||||||
dayUpper = 30;
|
|
||||||
break;
|
|
||||||
case "may":
|
|
||||||
month = 5;
|
|
||||||
break;
|
|
||||||
case "jun":
|
|
||||||
month = 6;
|
|
||||||
dayUpper = 30;
|
|
||||||
break;
|
|
||||||
case "jul":
|
|
||||||
month = 7;
|
|
||||||
break;
|
|
||||||
case "aug":
|
|
||||||
month = 8;
|
|
||||||
break;
|
|
||||||
case "sep":
|
|
||||||
month = 9;
|
|
||||||
dayUpper = 30;
|
|
||||||
break;
|
|
||||||
case "oct":
|
|
||||||
month = 10;
|
|
||||||
break;
|
|
||||||
case "nov":
|
|
||||||
month = 11;
|
|
||||||
dayUpper = 30;
|
|
||||||
break;
|
|
||||||
case "dec":
|
|
||||||
month = 12;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new FormatException(":x: Invalid month name. Use a three-letter month abbreviation.");
|
|
||||||
}
|
|
||||||
if (day == 0 || day > dayUpper) throw new FormatException(":x: The date you specified is not a valid calendar date.");
|
if (day == 0 || day > dayUpper) throw new FormatException(":x: The date you specified is not a valid calendar date.");
|
||||||
|
|
||||||
return (month, day);
|
return (month, day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns information for a given month input.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns>Tuple: Month value, upper limit of days in the month</returns>
|
||||||
|
/// <exception cref="FormatException">
|
||||||
|
/// Thrown on error. Send out to Discord as-is.
|
||||||
|
/// </exception>
|
||||||
|
private (int, int) GetMonth(string input)
|
||||||
|
{
|
||||||
|
switch (input.ToLower())
|
||||||
|
{
|
||||||
|
case "jan":
|
||||||
|
case "january":
|
||||||
|
return (1, 31);
|
||||||
|
case "feb":
|
||||||
|
case "february":
|
||||||
|
return (2, 29);
|
||||||
|
case "mar":
|
||||||
|
case "march":
|
||||||
|
return (3, 31);
|
||||||
|
case "apr":
|
||||||
|
case "april":
|
||||||
|
return (4, 30);
|
||||||
|
case "may":
|
||||||
|
return (5, 31);
|
||||||
|
case "jun":
|
||||||
|
case "june":
|
||||||
|
return (6, 30);
|
||||||
|
case "jul":
|
||||||
|
case "july":
|
||||||
|
return (7, 31);
|
||||||
|
case "aug":
|
||||||
|
case "august":
|
||||||
|
return (8, 31);
|
||||||
|
case "sep":
|
||||||
|
case "september":
|
||||||
|
return (9, 30);
|
||||||
|
case "oct":
|
||||||
|
case "october":
|
||||||
|
return (10, 31);
|
||||||
|
case "nov":
|
||||||
|
case "november":
|
||||||
|
return (11, 30);
|
||||||
|
case "dec":
|
||||||
|
case "december":
|
||||||
|
return (12, 31);
|
||||||
|
default:
|
||||||
|
throw new FormatException($":x: Can't determine month name `{input}`. Check your spelling and try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Documentation
|
#region Documentation
|
||||||
public static readonly CommandDocumentation DocSet =
|
public static readonly CommandDocumentation DocSet =
|
||||||
new CommandDocumentation(new string[] { "set (date) [zone]" }, "Registers your birth date. Time zone is optional.",
|
new CommandDocumentation(new string[] { "set (date) [zone]" }, "Registers your birth date. Time zone is optional.",
|
||||||
|
@ -114,25 +130,44 @@ namespace BirthdayBot.UserInterface
|
||||||
private async Task CmdSet(ShardInstance instance, GuildConfiguration gconf,
|
private async Task CmdSet(ShardInstance instance, GuildConfiguration gconf,
|
||||||
string[] param, SocketTextChannel reqChannel, SocketGuildUser reqUser)
|
string[] param, SocketTextChannel reqChannel, SocketGuildUser reqUser)
|
||||||
{
|
{
|
||||||
// Requires one parameter. Optionally two.
|
// Requires *some* parameter.
|
||||||
if (param.Length < 2 || param.Length > 3)
|
if (param.Length < 2)
|
||||||
{
|
{
|
||||||
await reqChannel.SendMessageAsync(ParameterError, embed: DocSet.UsageEmbed).ConfigureAwait(false);
|
await reqChannel.SendMessageAsync(ParameterError, embed: DocSet.UsageEmbed).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Date format accepts spaces, and then we look for an additional parameter.
|
||||||
|
// This is weird. Gotta compensate.
|
||||||
|
var fullinput = "";
|
||||||
|
for (int i = 1; i < param.Length; i++)
|
||||||
|
{
|
||||||
|
fullinput += " " + param[i];
|
||||||
|
}
|
||||||
|
fullinput = fullinput[1..];
|
||||||
|
// Attempt to get last "parameter"; check if it's a time zone value
|
||||||
|
string timezone = null;
|
||||||
|
var fli = fullinput.LastIndexOf(' ');
|
||||||
|
if (fli != -1)
|
||||||
|
{
|
||||||
|
var tzstring = fullinput[(fli+1)..];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
timezone = ParseTimeZone(tzstring);
|
||||||
|
// If we got here, last parameter was indeed a time zone. Trim it away for what comes next.
|
||||||
|
fullinput = fullinput[0..fli];
|
||||||
|
}
|
||||||
|
catch (FormatException) { } // Was not a time zone name. Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
int bmonth, bday;
|
int bmonth, bday;
|
||||||
string btz = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var res = ParseDate(param[1]);
|
(bmonth, bday) = ParseDate(fullinput);
|
||||||
bmonth = res.Item1;
|
|
||||||
bday = res.Item2;
|
|
||||||
if (param.Length == 3) btz = ParseTimeZone(param[2]);
|
|
||||||
}
|
}
|
||||||
catch (FormatException ex)
|
catch (FormatException ex)
|
||||||
{
|
{
|
||||||
// Our parse methods' FormatException has its message to send out to Discord.
|
// Our parse method's FormatException has its message to send out to Discord.
|
||||||
reqChannel.SendMessageAsync(ex.Message, embed: DocSet.UsageEmbed).Wait();
|
reqChannel.SendMessageAsync(ex.Message, embed: DocSet.UsageEmbed).Wait();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +178,7 @@ namespace BirthdayBot.UserInterface
|
||||||
{
|
{
|
||||||
var user = await GuildUserConfiguration.LoadAsync(gconf.GuildId, reqUser.Id).ConfigureAwait(false);
|
var user = await GuildUserConfiguration.LoadAsync(gconf.GuildId, reqUser.Id).ConfigureAwait(false);
|
||||||
known = user.IsKnown;
|
known = user.IsKnown;
|
||||||
await user.UpdateAsync(bmonth, bday, btz).ConfigureAwait(false);
|
await user.UpdateAsync(bmonth, bday, timezone).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue