Compare commits
No commits in common. "e4ec80e1183c6643f4c946d5e2533576581ee4c2" and "9c368e82ab31b03591bda7224712477484f4b47d" have entirely different histories.
e4ec80e118
...
9c368e82ab
8 changed files with 20 additions and 186 deletions
|
|
@ -35,6 +35,7 @@ pub enum Log {
|
||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
},
|
},
|
||||||
StdoutOnly,
|
StdoutOnly,
|
||||||
|
NoLog,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Log {
|
impl Log {
|
||||||
|
|
@ -85,12 +86,8 @@ impl Log {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_to_stdout_only() -> Self {
|
pub fn new_to_stdout_only() -> Self {
|
||||||
Self::new_to_stdout_only_with_max_level(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_to_stdout_only_with_max_level(level: Option<tracing::Level>) -> Self {
|
|
||||||
let layer_stdout = tracing_subscriber::fmt::layer()
|
let layer_stdout = tracing_subscriber::fmt::layer()
|
||||||
.with_writer(std::io::stdout.with_max_level(level.unwrap_or(TRACING_LEVEL)))
|
.with_writer(std::io::stdout.with_max_level(TRACING_LEVEL))
|
||||||
.with_thread_ids(TRACING_DISPLAY_THREAD)
|
.with_thread_ids(TRACING_DISPLAY_THREAD)
|
||||||
.with_thread_names(TRACING_DISPLAY_THREAD);
|
.with_thread_names(TRACING_DISPLAY_THREAD);
|
||||||
|
|
||||||
|
|
@ -101,6 +98,10 @@ impl Log {
|
||||||
Log::StdoutOnly
|
Log::StdoutOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_no_log() -> Self {
|
||||||
|
Log::NoLog
|
||||||
|
}
|
||||||
|
|
||||||
pub fn file_names(&self) -> std::io::Result<Vec<String>> {
|
pub fn file_names(&self) -> std::io::Result<Vec<String>> {
|
||||||
match self {
|
match self {
|
||||||
Log::FileAndStdout { _guard, directory } => {
|
Log::FileAndStdout { _guard, directory } => {
|
||||||
|
|
@ -129,7 +130,7 @@ impl Log {
|
||||||
.rev()
|
.rev()
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
Log::StdoutOnly => Ok(vec![]),
|
Log::StdoutOnly | Log::NoLog => Ok(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,7 +145,7 @@ impl Log {
|
||||||
.map(|l| l.unwrap_or_default())
|
.map(|l| l.unwrap_or_default())
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
Log::StdoutOnly => Ok(vec![]),
|
Log::StdoutOnly | Log::NoLog => Ok(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,7 @@ pub async fn rm_tags(
|
||||||
ExtractRon(ron): ExtractRon<ron_api::Tags>,
|
ExtractRon(ron): ExtractRon<ron_api::Tags>,
|
||||||
) -> Result<impl IntoResponse> {
|
) -> Result<impl IntoResponse> {
|
||||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||||
connection
|
connection.rm_recipe_tags(ron.recipe_id, &ron.tags).await?;
|
||||||
.rm_recipe_tags(
|
|
||||||
ron.recipe_id,
|
|
||||||
&ron.tags
|
|
||||||
.into_iter()
|
|
||||||
.map(|tag| tag.to_lowercase())
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(StatusCode::OK)
|
Ok(StatusCode::OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +157,7 @@ pub async fn set_language(
|
||||||
pub async fn set_is_public(
|
pub async fn set_is_public(
|
||||||
State(connection): State<db::Connection>,
|
State(connection): State<db::Connection>,
|
||||||
Extension(context): Extension<Context>,
|
Extension(context): Extension<Context>,
|
||||||
ExtractRon(ron): ExtractRon<ron_api::SetRecipeIsPublic>,
|
ExtractRon(ron): ExtractRon<ron_api::SetIsPublic>,
|
||||||
) -> Result<StatusCode> {
|
) -> Result<StatusCode> {
|
||||||
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
check_user_rights_recipe(&connection, &context.user, ron.recipe_id).await?;
|
||||||
connection
|
connection
|
||||||
|
|
|
||||||
|
|
@ -301,65 +301,7 @@ async fn create_recipe_and_edit_it() -> Result<(), Box<dyn Error>> {
|
||||||
.await;
|
.await;
|
||||||
response.assert_status_ok();
|
response.assert_status_ok();
|
||||||
|
|
||||||
let response = server
|
// TODO: Set other recipe fields.
|
||||||
.patch("/ron-api/recipe/estimated_time")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON)
|
|
||||||
.bytes(
|
|
||||||
ron_api::to_string(ron_api::SetRecipeEstimatedTime {
|
|
||||||
recipe_id,
|
|
||||||
estimated_time: Some(420),
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
|
|
||||||
let response = server
|
|
||||||
.patch("/ron-api/recipe/difficulty")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON)
|
|
||||||
.bytes(
|
|
||||||
ron_api::to_string(ron_api::SetRecipeDifficulty {
|
|
||||||
recipe_id,
|
|
||||||
difficulty: ron_api::Difficulty::Hard,
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
|
|
||||||
let response = server
|
|
||||||
.patch("/ron-api/recipe/language")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON)
|
|
||||||
.bytes(
|
|
||||||
ron_api::to_string(ron_api::SetRecipeLanguage {
|
|
||||||
recipe_id,
|
|
||||||
lang: "fr".into(),
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
|
|
||||||
let response = server
|
|
||||||
.patch("/ron-api/recipe/is_public")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON)
|
|
||||||
.bytes(
|
|
||||||
ron_api::to_string(ron_api::SetRecipeIsPublic {
|
|
||||||
recipe_id,
|
|
||||||
is_public: true,
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
let response = server
|
let response = server
|
||||||
|
|
@ -385,112 +327,7 @@ async fn create_recipe_and_edit_it() -> Result<(), Box<dyn Error>> {
|
||||||
let element_servings = document.select(&servings_selector).next().unwrap();
|
let element_servings = document.select(&servings_selector).next().unwrap();
|
||||||
assert_eq!(element_servings.attr("value").unwrap(), "42");
|
assert_eq!(element_servings.attr("value").unwrap(), "42");
|
||||||
|
|
||||||
let estimated_time_selector = Selector::parse("#input-estimated-time").unwrap();
|
// dbg!(response);
|
||||||
let element_estimated_time = document.select(&estimated_time_selector).next().unwrap();
|
|
||||||
assert_eq!(element_estimated_time.attr("value").unwrap(), "420");
|
|
||||||
|
|
||||||
let selected_difficulty_selector =
|
|
||||||
Selector::parse("#select-difficulty option[selected]").unwrap();
|
|
||||||
let element_selected_difficulty = document
|
|
||||||
.select(&selected_difficulty_selector)
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(element_selected_difficulty.inner_html(), "Hard");
|
|
||||||
|
|
||||||
let selected_language_selector = Selector::parse("#select-language option[selected]").unwrap();
|
|
||||||
let element_selected_language = document.select(&selected_language_selector).next().unwrap();
|
|
||||||
assert_eq!(element_selected_language.inner_html(), "Français");
|
|
||||||
|
|
||||||
let is_public_selector = Selector::parse("#input-is-public").unwrap();
|
|
||||||
let element_is_public = document.select(&is_public_selector).next().unwrap();
|
|
||||||
assert!(element_is_public.attr("checked").is_some());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn recipe_tags() -> Result<(), Box<dyn Error>> {
|
|
||||||
// Arrange.
|
|
||||||
let state = utils::common_state().await?;
|
|
||||||
let user_id = utils::create_user(
|
|
||||||
&state.db_connection,
|
|
||||||
"president@spaceball.planet",
|
|
||||||
"12345678",
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let token = utils::sign_in(
|
|
||||||
&state.db_connection,
|
|
||||||
"president@spaceball.planet",
|
|
||||||
"12345678",
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let recipe_id = utils::create_recipe(&state.db_connection, user_id, "spaghetti").await?;
|
|
||||||
let server = TestServer::new(app::make_service(state))?;
|
|
||||||
let cookie = Cookie::new("auth_token", token);
|
|
||||||
|
|
||||||
// Act.
|
|
||||||
// Tags list must be empty.
|
|
||||||
let response = server
|
|
||||||
.get("/ron-api/recipe/tags")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_query_param("id", recipe_id)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
let tags: ron_api::Tags = ron::de::from_bytes(response.as_bytes()).unwrap();
|
|
||||||
assert!(tags.tags.is_empty());
|
|
||||||
|
|
||||||
// Add some tags.
|
|
||||||
let response = server
|
|
||||||
.post("/ron-api/recipe/tags")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON)
|
|
||||||
.bytes(
|
|
||||||
ron_api::to_string(ron_api::Tags {
|
|
||||||
recipe_id,
|
|
||||||
tags: vec!["ABC".into(), "xyz".into()],
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
|
|
||||||
let response = server
|
|
||||||
.get("/ron-api/recipe/tags")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_query_param("id", recipe_id)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
let tags: ron_api::Tags = ron::de::from_bytes(response.as_bytes()).unwrap();
|
|
||||||
assert_eq!(tags.tags.len(), 2);
|
|
||||||
assert!(tags.tags.contains(&"abc".to_string())); // Tags are in lower case.
|
|
||||||
assert!(tags.tags.contains(&"xyz".to_string()));
|
|
||||||
|
|
||||||
// Remove some tags.
|
|
||||||
let response = server
|
|
||||||
.delete("/ron-api/recipe/tags")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON)
|
|
||||||
.bytes(
|
|
||||||
ron_api::to_string(ron_api::Tags {
|
|
||||||
recipe_id,
|
|
||||||
tags: vec!["XYZ".into(), "qwe".into()],
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
|
|
||||||
let response = server
|
|
||||||
.get("/ron-api/recipe/tags")
|
|
||||||
.add_cookie(cookie.clone())
|
|
||||||
.add_query_param("id", recipe_id)
|
|
||||||
.await;
|
|
||||||
response.assert_status_ok();
|
|
||||||
let tags: ron_api::Tags = ron::de::from_bytes(response.as_bytes()).unwrap();
|
|
||||||
assert_eq!(tags.tags.len(), 1);
|
|
||||||
assert_eq!(tags.tags[0], "abc".to_string());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub async fn common_state_with_email_service(
|
||||||
) -> Result<app::AppState, Box<dyn Error>> {
|
) -> Result<app::AppState, Box<dyn Error>> {
|
||||||
let db_connection = db::Connection::new_in_memory().await?;
|
let db_connection = db::Connection::new_in_memory().await?;
|
||||||
let config = config::Config::default();
|
let config = config::Config::default();
|
||||||
let log = log::Log::new_to_stdout_only_with_max_level(Some(tracing::Level::ERROR));
|
let log = log::Log::new_no_log();
|
||||||
Ok(app::AppState {
|
Ok(app::AppState {
|
||||||
config,
|
config,
|
||||||
db_connection,
|
db_connection,
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ pub struct SetRecipeLanguage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct SetRecipeIsPublic {
|
pub struct SetIsPublic {
|
||||||
pub recipe_id: i64,
|
pub recipe_id: i64,
|
||||||
pub is_public: bool,
|
pub is_public: bool,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
do.nu
1
do.nu
|
|
@ -52,6 +52,7 @@ def "main deploy" [
|
||||||
} else {
|
} else {
|
||||||
cargo build --release
|
cargo build --release
|
||||||
}
|
}
|
||||||
|
cd ..
|
||||||
|
|
||||||
invoke_ssh [sudo systemctl stop recipes]
|
invoke_ssh [sudo systemctl stop recipes]
|
||||||
copy_ssh ./target/($target)/release/recipes $destination
|
copy_ssh ./target/($target)/release/recipes $destination
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ pub fn setup_page(recipe_id: i64) {
|
||||||
{
|
{
|
||||||
let is_public: HtmlInputElement = by_id("input-is-public");
|
let is_public: HtmlInputElement = by_id("input-is-public");
|
||||||
EventListener::new(&is_public.clone(), "input", move |_event| {
|
EventListener::new(&is_public.clone(), "input", move |_event| {
|
||||||
let body = ron_api::SetRecipeIsPublic {
|
let body = ron_api::SetIsPublic {
|
||||||
recipe_id,
|
recipe_id,
|
||||||
is_public: is_public.checked(),
|
is_public: is_public.checked(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,10 @@ where
|
||||||
{
|
{
|
||||||
let mut url = format!("/ron-api/{}?", api_name);
|
let mut url = format!("/ron-api/{}?", api_name);
|
||||||
serde_html_form::ser::push_to_string(&mut url, params).unwrap();
|
serde_html_form::ser::push_to_string(&mut url, params).unwrap();
|
||||||
let request_builder = method_fn(&url);
|
let request_builder = method_fn(&url).header(
|
||||||
|
CONTENT_TYPE,
|
||||||
|
common::consts::MIME_TYPE_RON.to_str().unwrap(),
|
||||||
|
);
|
||||||
send_req(request_builder.build()?).await
|
send_req(request_builder.build()?).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue