refactor: clean up some code
parent
a74cf76b2b
commit
2999ca2301
|
@ -7,4 +7,5 @@ pipeline:
|
||||||
build:
|
build:
|
||||||
image: 'rust:1.69'
|
image: 'rust:1.69'
|
||||||
commands:
|
commands:
|
||||||
- cargo build
|
- cargo build --verbose
|
||||||
|
- cargo test --verbose
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::hh_mm_time_format;
|
use super::hh_mm_time_format;
|
||||||
use chrono::NaiveTime;
|
use chrono::{Duration, NaiveTime};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, Copy)]
|
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||||
|
@ -41,3 +41,39 @@ pub struct Resource {
|
||||||
pub slots_state: u32,
|
pub slots_state: u32,
|
||||||
pub hours: Vec<HourBlock>,
|
pub hours: Vec<HourBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Resource {
|
||||||
|
pub fn condensed_hours(&self) -> Vec<(&HourBlock, Duration)> {
|
||||||
|
let mut start_hour_opt: Option<&HourBlock> = None;
|
||||||
|
let mut duration = Duration::seconds(0);
|
||||||
|
let mut out: Vec<(&HourBlock, Duration)> = Default::default();
|
||||||
|
|
||||||
|
for hour in &self.hours {
|
||||||
|
if let Some(start_hour) = start_hour_opt {
|
||||||
|
if hour.state == start_hour.state {
|
||||||
|
duration = duration + Duration::minutes(hour.granularity.into());
|
||||||
|
} else {
|
||||||
|
out.push((start_hour, duration));
|
||||||
|
start_hour_opt = Some(hour);
|
||||||
|
duration = Duration::minutes(hour.granularity.into());
|
||||||
|
}
|
||||||
|
} else if hour.state == 1 {
|
||||||
|
start_hour_opt = Some(hour);
|
||||||
|
duration = Duration::minutes(hour.granularity.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(start_hour) = start_hour_opt {
|
||||||
|
out.push((start_hour, duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn condensed_available_hours(&self) -> Vec<(&HourBlock, Duration)> {
|
||||||
|
self.condensed_hours()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(hour, _)| hour.state == 1)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
113
src/commands.rs
113
src/commands.rs
|
@ -1,6 +1,5 @@
|
||||||
use crate::{Context, Error};
|
use crate::{Context, Error};
|
||||||
use affluences_api::HourBlock;
|
use chrono::NaiveDate;
|
||||||
use chrono::{Duration, NaiveDate};
|
|
||||||
use uuid::{uuid, Uuid};
|
use uuid::{uuid, Uuid};
|
||||||
|
|
||||||
const STERRE_BIB_ID: Uuid = uuid!("4737e57a-ee05-4f7b-901a-7bb541eeb297");
|
const STERRE_BIB_ID: Uuid = uuid!("4737e57a-ee05-4f7b-901a-7bb541eeb297");
|
||||||
|
@ -26,62 +25,6 @@ pub async fn help(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Vote for something
|
|
||||||
///
|
|
||||||
/// Enter `~vote pumpkin` to vote for pumpkins
|
|
||||||
#[poise::command(prefix_command, slash_command)]
|
|
||||||
pub async fn vote(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "What to vote for"] choice: String,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
// Lock the Mutex in a block {} so the Mutex isn't locked across an await point
|
|
||||||
let num_votes = {
|
|
||||||
let mut hash_map = ctx.data().votes.lock().unwrap();
|
|
||||||
let num_votes = hash_map.entry(choice.clone()).or_default();
|
|
||||||
*num_votes += 1;
|
|
||||||
*num_votes
|
|
||||||
};
|
|
||||||
|
|
||||||
let response = format!("Successfully voted for {choice}. {choice} now has {num_votes} votes!");
|
|
||||||
ctx.say(response).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve number of votes
|
|
||||||
///
|
|
||||||
/// Retrieve the number of votes either in general, or for a specific choice:
|
|
||||||
/// ```
|
|
||||||
/// ~getvotes
|
|
||||||
/// ~getvotes pumpkin
|
|
||||||
/// ```
|
|
||||||
#[poise::command(prefix_command, track_edits, aliases("votes"), slash_command)]
|
|
||||||
pub async fn getvotes(
|
|
||||||
ctx: Context<'_>,
|
|
||||||
#[description = "Choice to retrieve votes for"] choice: Option<String>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if let Some(choice) = choice {
|
|
||||||
let num_votes = *ctx.data().votes.lock().unwrap().get(&choice).unwrap_or(&0);
|
|
||||||
let response = match num_votes {
|
|
||||||
0 => format!("Nobody has voted for {} yet", choice),
|
|
||||||
_ => format!("{} people have voted for {}", num_votes, choice),
|
|
||||||
};
|
|
||||||
ctx.say(response).await?;
|
|
||||||
} else {
|
|
||||||
let mut response = String::new();
|
|
||||||
for (choice, num_votes) in ctx.data().votes.lock().unwrap().iter() {
|
|
||||||
response += &format!("{}: {} votes", choice, num_votes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if response.is_empty() {
|
|
||||||
response += "Nobody has voted for anything yet :(";
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.say(response).await?;
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List available timeslots for day
|
/// List available timeslots for day
|
||||||
#[poise::command(prefix_command, slash_command)]
|
#[poise::command(prefix_command, slash_command)]
|
||||||
pub async fn available(ctx: Context<'_>, date: NaiveDate) -> Result<(), Error> {
|
pub async fn available(ctx: Context<'_>, date: NaiveDate) -> Result<(), Error> {
|
||||||
|
@ -90,7 +33,9 @@ pub async fn available(ctx: Context<'_>, date: NaiveDate) -> Result<(), Error> {
|
||||||
let mut fields: Vec<(String, String, bool)> = Default::default();
|
let mut fields: Vec<(String, String, bool)> = Default::default();
|
||||||
|
|
||||||
for resource in &resources {
|
for resource in &resources {
|
||||||
if resource.hours.is_empty() {
|
let available_hours = resource.condensed_available_hours();
|
||||||
|
|
||||||
|
if available_hours.is_empty() {
|
||||||
fields.push((
|
fields.push((
|
||||||
resource.resource_name.clone(),
|
resource.resource_name.clone(),
|
||||||
"Nothing available.".to_string(),
|
"Nothing available.".to_string(),
|
||||||
|
@ -100,45 +45,23 @@ pub async fn available(ctx: Context<'_>, date: NaiveDate) -> Result<(), Error> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lines: Vec<String> = Default::default();
|
fields.push((
|
||||||
|
resource.resource_name.clone(),
|
||||||
let mut start_hour_opt: Option<&HourBlock> = None;
|
available_hours
|
||||||
let mut duration = Duration::seconds(0);
|
.into_iter()
|
||||||
|
.map(|(start_block, duration)| {
|
||||||
for hour in &resource.hours {
|
format!(
|
||||||
if let Some(start_hour) = start_hour_opt {
|
|
||||||
if hour.state == 1 {
|
|
||||||
duration = duration + Duration::minutes(hour.granularity.into());
|
|
||||||
} else {
|
|
||||||
let end_hour = start_hour.hour + duration;
|
|
||||||
lines.push(format!(
|
|
||||||
"{} - {} ({:02}:{:02})",
|
"{} - {} ({:02}:{:02})",
|
||||||
start_hour.hour.format(TIME_FORMAT),
|
start_block.hour.format(TIME_FORMAT),
|
||||||
end_hour.format(TIME_FORMAT),
|
(start_block.hour + duration).format(TIME_FORMAT),
|
||||||
duration.num_hours(),
|
duration.num_hours(),
|
||||||
duration.num_minutes() % 60
|
duration.num_minutes() % 60
|
||||||
));
|
)
|
||||||
start_hour_opt = None;
|
})
|
||||||
}
|
.collect::<Vec<String>>()
|
||||||
} else if hour.state == 1 {
|
.join("\n"),
|
||||||
start_hour_opt = Some(hour);
|
false,
|
||||||
duration = Duration::minutes(hour.granularity.into());
|
));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print final entry if present
|
|
||||||
if let Some(start_hour) = start_hour_opt {
|
|
||||||
let end_hour = start_hour.hour + duration;
|
|
||||||
lines.push(format!(
|
|
||||||
"{} - {} ({:02}:{:02})",
|
|
||||||
start_hour.hour.format(TIME_FORMAT),
|
|
||||||
end_hour.format(TIME_FORMAT),
|
|
||||||
duration.num_hours(),
|
|
||||||
duration.num_minutes() % 60
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fields.push((resource.resource_name.clone(), lines.join("\n"), false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.send(|f| {
|
ctx.send(|f| {
|
||||||
|
|
|
@ -36,12 +36,7 @@ async fn main() {
|
||||||
// FrameworkOptions contains all of poise's configuration option in one struct
|
// FrameworkOptions contains all of poise's configuration option in one struct
|
||||||
// Every option can be omitted to use its default value
|
// Every option can be omitted to use its default value
|
||||||
let options = poise::FrameworkOptions {
|
let options = poise::FrameworkOptions {
|
||||||
commands: vec![
|
commands: vec![commands::help(), commands::available()],
|
||||||
commands::help(),
|
|
||||||
commands::vote(),
|
|
||||||
commands::getvotes(),
|
|
||||||
commands::available(),
|
|
||||||
],
|
|
||||||
prefix_options: poise::PrefixFrameworkOptions {
|
prefix_options: poise::PrefixFrameworkOptions {
|
||||||
prefix: Some("~".into()),
|
prefix: Some("~".into()),
|
||||||
edit_tracker: Some(poise::EditTracker::for_timespan(Duration::from_secs(3600))),
|
edit_tracker: Some(poise::EditTracker::for_timespan(Duration::from_secs(3600))),
|
||||||
|
|
Loading…
Reference in New Issue