feat: CLI quest CRUD

- Quest creation
- Quest list retrieving
- Quest update
- Quest deletion
This commit is contained in:
Alexey 2025-11-29 14:40:23 +03:00
commit d61011f5ea
2 changed files with 124 additions and 9 deletions

View file

@ -1,6 +1,7 @@
use std::path::PathBuf;
use clap::{Parser,Subcommand,Args,ValueEnum};
use squad_quest::{config::Config,quest::{Quest,QuestDifficulty as LibQuestDifficulty}};
#[derive(Parser)]
#[command(version, about, long_about = None)]
@ -33,6 +34,17 @@ enum QuestDifficulty {
Secret
}
impl From<QuestDifficulty> for LibQuestDifficulty {
fn from(value: QuestDifficulty) -> Self {
match value {
QuestDifficulty::Easy => LibQuestDifficulty::Easy,
QuestDifficulty::Normal => LibQuestDifficulty::Normal,
QuestDifficulty::Hard => LibQuestDifficulty::Hard,
QuestDifficulty::Secret => LibQuestDifficulty::Secret,
}
}
}
#[derive(Subcommand)]
enum QuestCommands {
/// List available quests
@ -72,16 +84,20 @@ struct QuestUpdateArgs {
/// Id of the quest to update
id: u16,
/// Difficulty of the quest
#[arg(value_enum)]
difficulty: QuestDifficulty,
#[arg(value_enum,long)]
difficulty: Option<QuestDifficulty>,
/// Reward for the quest
reward: u32,
#[arg(long)]
reward: Option<u32>,
/// Name of the quest
name: String,
#[arg(long)]
name: Option<String>,
/// Visible description of the quest
description: String,
#[arg(long)]
description: Option<String>,
/// Answer for the quest for admins
answer: String
#[arg(long)]
answer: Option<String>
}
#[derive(Args)]
@ -90,6 +106,105 @@ struct QuestDeleteArgs {
id: u16
}
fn main() {
let _cli = Cli::parse();
fn print_quest_short(quest: &Quest) {
println!("Quest #{}: {}", quest.id, quest.name);
}
fn print_quest_long(quest: &Quest) {
print_quest_short(quest);
println!("Difficulty: {:?}", quest.difficulty);
println!("Description:\n{}", quest.description);
println!("Answer:\n{}", quest.answer);
}
fn main() {
let cli = Cli::parse();
let config = Config::load(cli.config.clone());
match &cli.command {
Objects::Quest(commands) => {
match commands {
QuestCommands::List(args) => {
let quests = config.load_quests();
for quest in quests {
if args.short {
print_quest_short(&quest);
} else {
print_quest_long(&quest);
}
}
},
QuestCommands::Create(args) => {
let mut quests = config.load_quests();
quests.sort_by(|a,b| a.id.cmp(&b.id));
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
};
let path = config.full_quests_path();
let mut quest_path = path.clone();
quest_path.push(format!("{next_id}.toml"));
match std::fs::exists(&quest_path) {
Ok(exists) => {
if exists {
panic!("Error: {:?} is not empty.", quest_path);
}
},
Err(error) => {
panic!("Error while retrieving {:?}: {}.", quest_path, error);
}
}
let quest = Quest {
id: next_id,
difficulty: args.difficulty.into(),
reward: args.reward,
name: args.name.clone(),
description: args.description.clone(),
answer: args.answer.clone(),
};
if let Err(error) = quest.save(path) {
eprintln!("Error while saving quest: {error}.");
} else {
println!("Successfully saved quest #{}.", quest.id);
}
},
QuestCommands::Update(args) => {
let quests = config.load_quests();
let Some(quest) = quests.iter().find(|q| q.id == args.id) else {
panic!("Error: Quest #{} not found.", args.id);
};
let quest = Quest {
id: args.id,
difficulty: match args.difficulty {
Some(diff) => diff.into(),
None => quest.difficulty
},
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())
};
let path = config.full_quests_path();
match quest.save(path) {
Ok(_) => println!("Updated quest #{}", quest.id),
Err(error) => eprintln!("Error while updating quest: {error}")
}
},
QuestCommands::Delete(args) => {
let mut path = config.full_quests_path();
path.push(format!("{}.toml", args.id));
match Quest::delete(path) {
Ok(_) => println!("Successfully deleted quest #{}", args.id),
Err(error) => eprintln!("Error deleting quest #{}: {}", args.id, error),
}
},
}
}
}
}

View file

@ -8,7 +8,7 @@ use serde::{ Serialize, Deserialize };
use error::QuestError;
/// Difficulty of the quest
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
pub enum QuestDifficulty {
/// Easy quest
Easy,