use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use rocket::response::status::NotFound;
use rocket::serde::json::Json;
use rocket::serde::{Deserialize, Serialize};
use rocket::State;
use rocket::{get, post};
use quake_core::entry::entry_file::EntryFile;
use quake_core::entry::entry_paths::EntryPaths;
use quake_core::entry::EntryDefines;
use quake_core::helper::file_filter;
use quake_core::usecases::entry_usecases;
use quake_core::QuakeConfig;
use crate::server::ApiError;
#[get("/defines")]
pub(crate) async fn get_entry_defines(conf: &State<QuakeConfig>) -> String {
let path = PathBuf::from(&conf.workspace);
let defines = EntryDefines::from_path(&path.join(EntryPaths::entries_define()));
serde_json::to_string(&defines).unwrap()
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
struct EntryResponse {
content: String,
}
#[post("/<entry_type>?<text>")]
pub(crate) async fn create_entry(
entry_type: String,
text: String,
config: &State<QuakeConfig>,
) -> Result<Json<EntryFile>, NotFound<Json<ApiError>>> {
let workspace = config.workspace.to_string();
return match entry_usecases::create_entry(&workspace, &entry_type, &text) {
Ok((_path, file)) => Ok(Json(file)),
Err(err) => Err(NotFound(Json(ApiError {
msg: err.to_string(),
}))),
};
}
#[get("/<entry_type>/<id>")]
pub(crate) async fn get_entry(
entry_type: &str,
id: usize,
config: &State<QuakeConfig>,
) -> Result<Json<EntryFile>, NotFound<Json<ApiError>>> {
let file_path = entry_by_id(entry_type, id, config)?;
let str = fs::read_to_string(file_path).expect("cannot read entry type");
let file = EntryFile::from(str.as_str(), id).unwrap();
Ok(Json(file))
}
pub fn entry_by_id(
entry_type: &str,
id: usize,
config: &State<QuakeConfig>,
) -> Result<PathBuf, NotFound<Json<ApiError>>> {
let base_path = PathBuf::from(&config.workspace).join(entry_type);
let entries = file_filter::filter_by_prefix(base_path, EntryFile::file_prefix(id));
if entries.is_empty() {
return Err(NotFound(Json(ApiError {
msg: "file not found".to_string(),
})));
}
Ok(entries[0].clone())
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(crate = "rocket::serde")]
pub struct EntryUpdate {
properties: HashMap<String, String>,
}
#[post("/<entry_type>/<id>", data = "<entry>")]
pub(crate) async fn update_entry(
entry_type: &str,
id: usize,
entry: Json<EntryUpdate>,
config: &State<QuakeConfig>,
) -> Result<Json<EntryFile>, NotFound<Json<ApiError>>> {
let path = PathBuf::from(&config.workspace).join(entry_type);
return match entry_usecases::update_entry_properties(path, entry_type, id, &entry.properties) {
Ok(file) => Ok(Json(file)),
Err(err) => Err(NotFound(Json(ApiError {
msg: err.to_string(),
}))),
};
}
#[cfg(test)]
mod test {
use std::collections::HashMap;
use std::fs;
use std::io::Read;
use rocket::form::validate::Contains;
use rocket::http::Status;
use rocket::local::blocking::Client;
use quake_core::entry::entry_paths::EntryPaths;
use crate::quake_rocket;
use crate::server::entry_api::EntryUpdate;
#[test]
fn crud_for_entry() {
let client = Client::tracked(quake_rocket()).expect("valid rocket instance");
let response = client.post("/entry/test_quake?text=demo").dispatch();
assert_eq!(response.status(), Status::Ok);
let created_time = "2021-12-13 20:45:51";
let req = create_update_req(created_time);
let string = serde_json::to_string(&req).unwrap();
let response = client.post("/entry/test_quake/1").body(string).dispatch();
assert_eq!(response.status(), Status::Ok);
let mut response = client.get("/entry/test_quake/1").dispatch();
let mut res = "".to_string();
let _ = response.read_to_string(&mut res);
assert_eq!(response.status(), Status::Ok);
assert!(res.contains(created_time));
assert!(res.contains("\"id\":1"));
assert!(res.contains("\"title\":\"demo\""));
let paths = EntryPaths::init(&"examples".to_string(), &"test_quake".to_string());
fs::remove_dir_all(paths.entry_path).unwrap();
}
fn create_update_req(time: &str) -> EntryUpdate {
let mut fields: HashMap<String, String> = HashMap::new();
fields.insert("created_date".to_string(), time.to_string());
fields.insert("updated_date".to_string(), time.to_string());
EntryUpdate { properties: fields }
}
}