about summary refs log tree commit diff
path: root/src/command/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/command/mod.rs')
-rw-r--r--src/command/mod.rs138
1 files changed, 136 insertions, 2 deletions
diff --git a/src/command/mod.rs b/src/command/mod.rs
index 73b292a..c3dc7a9 100644
--- a/src/command/mod.rs
+++ b/src/command/mod.rs
@@ -5,6 +5,7 @@ mod revise;
 pub use add_points::add_points;
 pub use leaderboard::leaderboard;
 pub use revise::revise;
+use time::{Date, PrimitiveDateTime, Time, format_description};
 
 use std::sync::Arc;
 
@@ -14,8 +15,12 @@ use twilight_model::{
 		interaction::application_command::{CommandData, CommandOptionValue},
 	},
 	gateway::payload::incoming::InteractionCreate,
+	guild::PartialMember,
 	http::interaction::InteractionResponseData,
-	id::{Id, marker::GuildMarker},
+	id::{
+		Id,
+		marker::{GuildMarker, UserMarker},
+	},
 };
 use twilight_util::builder::{
 	InteractionResponseDataBuilder,
@@ -23,7 +28,7 @@ use twilight_util::builder::{
 	embed::{EmbedBuilder, EmbedFieldBuilder},
 };
 
-use crate::{bail, brain::Brain, database::PermissionSetting, fail, import, success};
+use crate::{bail, brain::Brain, database::PermissionSetting, fail, import, success, util};
 
 pub enum Commands {
 	About,
@@ -231,3 +236,132 @@ pub async fn import(
 		import::emboard_direct::import(brain, guild, create).await;
 	}
 }
+
+/// Checks the settings of the leaderboard associated with the provided guild.
+///
+/// Returns `None` if:
+/// - The guild does not have permissions set
+/// - The guild member has the appropriate permissions
+///
+/// Returns `Some` with InteractionResponseData if:
+/// - The guild member does not have proper permissions
+/// - The guild is set to role required, but no role is set, which should be
+///   impossible to happen, but.
+pub fn check_command_permissions(
+	brain: &Brain,
+	guild: Id<GuildMarker>,
+	member: PartialMember,
+) -> Option<InteractionResponseData> {
+	let settings = brain.db.get_leaderboard_settings(guild.get()).unwrap();
+	if let PermissionSetting::RoleRequired = settings.permission {
+		if let Some(role) = settings.role {
+			let member = member;
+			let found_role = member.roles.iter().find(|vrole| vrole.get() == role);
+
+			if found_role.is_none() {
+				Some(fail!(
+					"You do not have the right permissions to change the score"
+				))
+			} else {
+				None
+			}
+		} else {
+			// Seeing as the role is a required input on the subcommand, this
+			// would only happen with direct database fiddling or like, some
+			// really weird arcane bullshit?
+			Some(fail!(
+				"Permissions set to Role Required, but no role is set. \
+				This shouldn't be able to happen. \
+				Maybe try to set the permissions again?"
+			))
+		}
+	} else {
+		None
+	}
+}
+
+pub struct PointsCommandData {
+	points: i64,
+	points_verb: &'static str,
+	users: Vec<Id<UserMarker>>,
+	date: Result<PrimitiveDateTime, InteractionResponseData>,
+}
+
+impl PointsCommandData {
+	pub fn user_string(&self) -> String {
+		self.users
+			.iter()
+			.map(|u| format!("<@{u}>"))
+			.collect::<Vec<String>>()
+			.join(", ")
+	}
+}
+
+pub fn parse_points_command_data(
+	data: &CommandData,
+) -> Result<PointsCommandData, InteractionResponseData> {
+	let mut points = None;
+	let mut users: Vec<Id<UserMarker>> = vec![];
+	let mut date_string = None;
+
+	for opt in &data.options {
+		match opt.name.as_str() {
+			"points" => match opt.value {
+				CommandOptionValue::Integer(num) => points = Some(num),
+				_ => unreachable!(),
+			},
+			"users" => match &opt.value {
+				CommandOptionValue::String(raw) => {
+					let mentions = util::extract_user_mentions(&raw);
+					users = mentions;
+				}
+				_ => unreachable!(),
+			},
+			"date" => match &opt.value {
+				CommandOptionValue::String(raw) => {
+					date_string = Some(raw);
+				}
+				_ => unreachable!(),
+			},
+			_ => unreachable!(),
+		}
+	}
+
+	if users.len() == 0 {
+		return Err(fail!("No users mentioned! Who do we add points to?"));
+	}
+
+	let (points, _points_display, points_verb) = match points {
+		Some(p) if p >= 0 => (p, p, "added to"),
+		Some(p) if p < 0 => (p, -p, "removed from"),
+		Some(_) | None => unreachable!(),
+	};
+
+	let date_fmt = format_description::parse("[year]-[month]-[day]").unwrap();
+	let datetime_fmt =
+		format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]").unwrap();
+
+	let date = match date_string {
+		None => Err(fail!("What date were these points earned?")),
+		Some(str) if str.is_empty() => Err(fail!("You must specify a date!")),
+		Some(date) => match Date::parse(date.trim(), &date_fmt) {
+			Err(_e) => match PrimitiveDateTime::parse(date.trim(), &datetime_fmt) {
+				Err(_e) => Err(fail!(
+					"Cannot parse the given date/time. Did you write it like \"2025-04-13\" or, with time, \"2025-04-13 02:33\"?"
+				)),
+				Ok(datetime) => Ok(datetime),
+			},
+			Ok(date) => Ok(PrimitiveDateTime::new(
+				date,
+				Time::from_hms(12, 0, 0).unwrap(),
+			)),
+		},
+	};
+
+	Ok(PointsCommandData {
+		points,
+		points_verb,
+		users,
+		date,
+	})
+}