feat!: Added several fields to Quest struct
- Added field public - Added optional field available_on - Added optional field deadline - Updated tests and CLI to use these fields
This commit is contained in:
parent
96235086d7
commit
78da6dde05
4 changed files with 60 additions and 6 deletions
|
|
@ -1,7 +1,20 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::{Parser,Subcommand,Args,ValueEnum};
|
use clap::{Parser,Subcommand,Args,ValueEnum};
|
||||||
|
use serde::Deserialize;
|
||||||
use squad_quest::{config::Config,quest::{Quest,QuestDifficulty as LibQuestDifficulty}};
|
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<Date,toml::de::Error> {
|
||||||
|
let toml_str = format!("date = {arg}");
|
||||||
|
let wrapper: DateWrapper = toml::from_str(&toml_str)?;
|
||||||
|
Ok(wrapper.date)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
|
|
@ -76,7 +89,16 @@ struct QuestCreateArgs {
|
||||||
/// Visible description of the quest
|
/// Visible description of the quest
|
||||||
description: String,
|
description: String,
|
||||||
/// Answer for the quest for admins
|
/// 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<Date>,
|
||||||
|
/// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||||
|
#[arg(short,long,value_parser = parse_date)]
|
||||||
|
deadline: Option<Date>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
|
@ -97,7 +119,16 @@ struct QuestUpdateArgs {
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
/// Answer for the quest for admins
|
/// Answer for the quest for admins
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
answer: Option<String>
|
answer: Option<String>,
|
||||||
|
/// Create quest and make it public immediately
|
||||||
|
#[arg(long)]
|
||||||
|
public: Option<bool>,
|
||||||
|
/// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||||
|
#[arg(long,value_parser = parse_date)]
|
||||||
|
available: Option<Date>,
|
||||||
|
/// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||||
|
#[arg(long,value_parser = parse_date)]
|
||||||
|
deadline: Option<Date>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
|
@ -141,7 +172,7 @@ fn main() {
|
||||||
let next_id = match quests.last() {
|
let next_id = match quests.last() {
|
||||||
Some(quest) if quest.id == u16::MAX => {
|
Some(quest) if quest.id == u16::MAX => {
|
||||||
panic!("Error: quest list contains quest with u16::MAX id.");
|
panic!("Error: quest list contains quest with u16::MAX id.");
|
||||||
}
|
},
|
||||||
Some(quest) => quest.id + 1u16,
|
Some(quest) => quest.id + 1u16,
|
||||||
None => 0u16
|
None => 0u16
|
||||||
};
|
};
|
||||||
|
|
@ -167,6 +198,9 @@ fn main() {
|
||||||
name: args.name.clone(),
|
name: args.name.clone(),
|
||||||
description: args.description.clone(),
|
description: args.description.clone(),
|
||||||
answer: args.answer.clone(),
|
answer: args.answer.clone(),
|
||||||
|
public: args.public,
|
||||||
|
available_on: args.available.clone(),
|
||||||
|
deadline: args.deadline.clone()
|
||||||
};
|
};
|
||||||
if let Err(error) = quest.save(path) {
|
if let Err(error) = quest.save(path) {
|
||||||
eprintln!("Error while saving quest: {error}.");
|
eprintln!("Error while saving quest: {error}.");
|
||||||
|
|
@ -188,7 +222,10 @@ fn main() {
|
||||||
reward: args.reward.unwrap_or(quest.reward),
|
reward: args.reward.unwrap_or(quest.reward),
|
||||||
name: args.name.clone().unwrap_or(quest.name.clone()),
|
name: args.name.clone().unwrap_or(quest.name.clone()),
|
||||||
description: args.description.clone().unwrap_or(quest.description.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();
|
let path = config.full_quests_path();
|
||||||
match quest.save(path) {
|
match quest.save(path) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use std::{fs, io::Write, path::PathBuf};
|
||||||
|
|
||||||
use serde::{ Serialize, Deserialize };
|
use serde::{ Serialize, Deserialize };
|
||||||
use error::QuestError;
|
use error::QuestError;
|
||||||
|
use toml::value::Date;
|
||||||
|
|
||||||
/// Difficulty of the quest
|
/// Difficulty of the quest
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
|
||||||
|
|
@ -59,6 +60,15 @@ pub struct Quest {
|
||||||
|
|
||||||
/// Quest answer, available for admins
|
/// Quest answer, available for admins
|
||||||
pub answer: String,
|
pub answer: String,
|
||||||
|
|
||||||
|
/// Is quest available for regular users
|
||||||
|
pub public: bool,
|
||||||
|
|
||||||
|
/// When quest becomes public
|
||||||
|
pub available_on: Option<Date>,
|
||||||
|
|
||||||
|
/// When quest expires
|
||||||
|
pub deadline: Option<Date>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Quest {
|
impl Default for Quest {
|
||||||
|
|
@ -69,7 +79,10 @@ impl Default for Quest {
|
||||||
reward: u32::default(),
|
reward: u32::default(),
|
||||||
name: default_name(),
|
name: default_name(),
|
||||||
description: default_description(),
|
description: default_description(),
|
||||||
answer: default_answer()
|
answer: default_answer(),
|
||||||
|
public: false,
|
||||||
|
available_on: None,
|
||||||
|
deadline: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,10 @@ fn quest_one() {
|
||||||
reward: 100,
|
reward: 100,
|
||||||
name: "Example easy quest".to_owned(),
|
name: "Example easy quest".to_owned(),
|
||||||
description: "Answer this quest without any attachments or comments".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);
|
assert_eq!(*quest, expected);
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,4 @@ reward = 100
|
||||||
name = "Example easy quest"
|
name = "Example easy quest"
|
||||||
description = "Answer this quest without any attachments or comments"
|
description = "Answer this quest without any attachments or comments"
|
||||||
answer = "Accept the answer if it has no attachments and an empty comment"
|
answer = "Accept the answer if it has no attachments and an empty comment"
|
||||||
|
public = false
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue