diff --git a/src/bin/cli.rs b/src/bin/cli.rs index fef2fc1..f46d387 100644 --- a/src/bin/cli.rs +++ b/src/bin/cli.rs @@ -1,7 +1,20 @@ use std::path::PathBuf; use clap::{Parser,Subcommand,Args,ValueEnum}; +use serde::Deserialize; use squad_quest::{config::Config,quest::{Quest,QuestDifficulty as LibQuestDifficulty}}; +use toml::value::Date; + +#[derive(Deserialize)] +struct DateWrapper { + date: Date +} + +fn parse_date(arg: &str) -> Result { + let toml_str = format!("date = {arg}"); + let wrapper: DateWrapper = toml::from_str(&toml_str)?; + Ok(wrapper.date) +} #[derive(Parser)] #[command(version, about, long_about = None)] @@ -76,7 +89,16 @@ struct QuestCreateArgs { /// Visible description of the quest description: String, /// Answer for the quest for admins - answer: String + answer: String, + /// Create quest and make it public immediately + #[arg(short,long)] + public: bool, + /// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24) + #[arg(short,long,value_parser = parse_date)] + available: Option, + /// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24) + #[arg(short,long,value_parser = parse_date)] + deadline: Option, } #[derive(Args)] @@ -97,7 +119,16 @@ struct QuestUpdateArgs { description: Option, /// Answer for the quest for admins #[arg(long)] - answer: Option + answer: Option, + /// Create quest and make it public immediately + #[arg(long)] + public: Option, + /// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24) + #[arg(long,value_parser = parse_date)] + available: Option, + /// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24) + #[arg(long,value_parser = parse_date)] + deadline: Option, } #[derive(Args)] @@ -141,7 +172,7 @@ fn main() { let next_id = match quests.last() { Some(quest) if quest.id == u16::MAX => { panic!("Error: quest list contains quest with u16::MAX id."); - } + }, Some(quest) => quest.id + 1u16, None => 0u16 }; @@ -167,6 +198,9 @@ fn main() { name: args.name.clone(), description: args.description.clone(), answer: args.answer.clone(), + public: args.public, + available_on: args.available.clone(), + deadline: args.deadline.clone() }; if let Err(error) = quest.save(path) { eprintln!("Error while saving quest: {error}."); @@ -188,7 +222,10 @@ fn main() { reward: args.reward.unwrap_or(quest.reward), name: args.name.clone().unwrap_or(quest.name.clone()), description: args.description.clone().unwrap_or(quest.description.clone()), - answer: args.answer.clone().unwrap_or(quest.answer.clone()) + answer: args.answer.clone().unwrap_or(quest.answer.clone()), + public: args.public.unwrap_or(quest.public), + available_on: args.available.clone().or(quest.available_on.clone()), + deadline: args.deadline.clone().or(quest.deadline.clone()) }; let path = config.full_quests_path(); match quest.save(path) { diff --git a/src/quest/mod.rs b/src/quest/mod.rs index 6c95f69..ccbdbbb 100644 --- a/src/quest/mod.rs +++ b/src/quest/mod.rs @@ -6,6 +6,7 @@ use std::{fs, io::Write, path::PathBuf}; use serde::{ Serialize, Deserialize }; use error::QuestError; +use toml::value::Date; /// Difficulty of the quest #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)] @@ -59,6 +60,15 @@ pub struct Quest { /// Quest answer, available for admins pub answer: String, + + /// Is quest available for regular users + pub public: bool, + + /// When quest becomes public + pub available_on: Option, + + /// When quest expires + pub deadline: Option } impl Default for Quest { @@ -69,7 +79,10 @@ impl Default for Quest { reward: u32::default(), name: default_name(), description: default_description(), - answer: default_answer() + answer: default_answer(), + public: false, + available_on: None, + deadline: None } } } diff --git a/tests/main.rs b/tests/main.rs index 321674a..1210380 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -35,7 +35,10 @@ fn quest_one() { reward: 100, name: "Example easy quest".to_owned(), description: "Answer this quest without any attachments or comments".to_owned(), - answer: "Accept the answer if it has no attachments and an empty comment".to_owned() + answer: "Accept the answer if it has no attachments and an empty comment".to_owned(), + public: false, + available_on: None, + deadline: None }; assert_eq!(*quest, expected); diff --git a/tests/main/quests/1.toml b/tests/main/quests/1.toml index 5b67270..855b576 100644 --- a/tests/main/quests/1.toml +++ b/tests/main/quests/1.toml @@ -6,3 +6,4 @@ reward = 100 name = "Example easy quest" description = "Answer this quest without any attachments or comments" answer = "Accept the answer if it has no attachments and an empty comment" +public = false