use crate::helpers::helpers::*;
use crate::writers::{add_new_controller_to_main_rs, write_to_file, write_to_module};
use color_eyre;
use color_eyre::eyre::Result;
use color_eyre::owo_colors::OwoColorize;
use eyre::*;
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::{Path, PathBuf};
pub fn write_to_controller_name_html(controller_name: &str) -> Result<(), Error> {
let contents = r#"{% extends 'base.html.tera' %}
{% block title %}Index{% endblock title %}
{% block head %}
{{ super() }}
{% endblock head %}
{% block content %}
<div class='relative px-6 lg:px-8'>
<div class='mx-auto max-w-2xl py-32 sm:py-48 lg:py-56' >
<h1 class='text-4xl sm:text-5xl lg:text-6xl font-extrabold leading-none mb-4'>Your controller's Name: {{controller_name}}</h1>
<p class='text-xl sm:text-2xl lg:text-3xl font-medium mb-8'>This is a rustyroad project</p>
</div>
</div>
{% endblock content %}"#.to_string();
write_to_file(
&format!("src/views/pages/{}.html.tera", controller_name).to_string(),
contents.as_bytes(),
)
.unwrap_or_else(|why| {
println!(
"Couldn't write to {}: {}",
&format!("./views/pages/{}.html.tera", controller_name).to_string(),
why
);
});
Ok(())
}
pub fn write_to_controller_name_html_with_authorized_view(
controller_name: &str,
folder_name: &str,
) -> Result<(), Error> {
let contents = format!(
r"{{% extends 'layouts/authenticated_page/{}.html.tera' %}}
{{% block title %}}Index{{% endblock title %}}
{{% block head %}}
{{{{ super() }}}}
{{% endblock head %}}
{{% block content %}}
<div class='relative px-6 lg:px-8'>
<div class='mx-auto max-w-2xl py-32 sm:py-48 lg:py-56' >
<h1 class='text-4xl sm:text-5xl lg:text-6xl font-extrabold leading-none mb-4'>Your controller's Name: {{{{controller_name}}}}</h1>
<p class='text-xl sm:text-2xl lg:text-3xl font-medium mb-8'>This is a rustyroad project</p>
</div>
</div>
{{% endblock content %}}",
folder_name
);
write_to_file(
&format!(
"src/views/layouts/authenticated_page/{}/{}.html.tera",
folder_name, controller_name
)
.to_string(),
contents.as_bytes(),
)
.unwrap_or_else(|why| {
println!(
"Couldn't write to {}: {}",
&format!(
"./views/layouts/authenticated_page/{}/{}.html.tera",
folder_name, controller_name
)
.to_string(),
why
);
});
Ok(())
}
pub fn write_to_new_get_all_controller(model_name: String) -> Result<(), Error> {
let model_path = format!("./src/models/{}.rs", model_name);
let model_file_path = PathBuf::from(&model_path);
if !model_file_path.exists() {
println!(
"The model {} does not exist. Would you like to create it? (y/n)",
model_name
);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().eq_ignore_ascii_case("y") {
} else {
return Err(eyre!(
"The model {} does not exist. Please create it and try again.",
model_name
));
}
}
let capitalize_model_name = capitalize_first(&model_name);
let controller_contents = format!(
r#"#[get("/{}/all")]
pub async fn get_all_{}s() -> HttpResponse {{
let result = {}::get_all_{}s().await;
match result {{
Ok({}) => HttpResponse::Ok().json({}),
Err(e) => HttpResponse::BadRequest().json(e.to_string()),
}}
}}
"#,
model_name,
model_name,
capitalize_model_name,
model_name,
capitalize_model_name,
capitalize_model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models", &capitalize_model_name);
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Data");
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Json");
file_contents.push_str("\n\n");
file_contents.push_str(&controller_contents);
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&path)
.unwrap();
writeln!(file, "{}", file_contents)?;
file.flush()?;
add_new_controller_to_main_rs(
None,
Some(&model_name),
&format!("get_all_{}s", &model_name),
)?;
println!("Successfully written to {}.rs", model_name);
Ok(())
}
pub fn write_to_new_get_controller(model_name: String) -> Result<(), Error> {
let model_path = format!("./src/models/{}.rs", model_name);
let model_file_path = PathBuf::from(&model_path);
if !model_file_path.exists() {
println!(
"The model {} does not exist. Would you like to create it? (y/n)",
model_name
);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().eq_ignore_ascii_case("y") {
} else {
return Err(eyre!(
"The model {} does not exist. Please create it and try again.",
model_name
));
}
}
let new_controller_content = format!(
r#" /// Alert: This is a generated controller.
/// The controller is generated by the rustyroad CLI.
/// It is a best guess at what the controller should look like.
/// Please review the controller and make any necessary changes.
#[get("/{}")]
pub async fn get_{}(tmpl: web::Data<Tera>) -> HttpResponse {{
let mut context = Context::new();
context.insert("title", "{}");
context.insert("controller_name", "{}");
let rendered = tmpl.render("pages/{}.html.tera", &context).unwrap();
HttpResponse::Ok().body(rendered)
}}"#,
&model_name, &model_name, &model_name, &model_name, &model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents.push_str("\n\n");
file_contents.push_str(&new_controller_content);
file_contents.push_str("\n\n");
fs::write(PathBuf::from(&path), file_contents.as_bytes())?;
add_new_controller_to_main_rs(None, Some(&model_name), &format!("get_{}", &model_name))?;
println!("Successfully written to {}", &path);
Ok(())
}
pub fn write_to_initial_get_controller_authorized_view(model_name: String) -> Result<(), Error> {
let capitalized_model_name = capitalize_first(&model_name);
let model_path = format!("./src/models/{}.rs", model_name);
let model_file_path = PathBuf::from(&model_path);
if !model_file_path.exists() {
println!(
"The model {} does not exist. Would you like to create it? (y/n)",
model_name
);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().eq_ignore_ascii_case("y") {
} else {
return Err(eyre!(
"The model {} does not exist. Please create it and try again.",
model_name
));
}
}
let new_controller_content = format!(
r#"
#[get("/{}")]
pub async fn {}_controller_with_authorized_view(
tmpl: web::Data<Tera>,
user: Option<Identity>
) -> HttpResponse {{
if let Some(_user) = user {{
let mut context = Context::new();
context.insert("username", &user.id().unwrap());
context.insert("title", "{}");
context.insert("controller_name", "{}");
let rendered = tmpl.render("layouts/authenticated_page/{}/{}.html.tera", &context).unwrap();
HttpResponse::Ok().body(rendered)
}} else {{
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to view this page.");
HttpResponse::Found()
.append_header((actix_web::http::header::LOCATION, "/login"))
.finish()
}}
}}"#,
&model_name, &model_name, &model_name, &model_name, &model_name, &model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpRequest");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "models::user", "UserLogin");
file_contents = add_or_update_import(
&file_contents,
format!("models::{}", &model_name).as_str(),
&capitalized_model_name,
);
file_contents.push_str("\n\n");
file_contents.push_str(&new_controller_content);
file_contents.push_str("\n\n");
fs::write(PathBuf::from(&path), file_contents.as_bytes())?;
add_new_controller_to_main_rs(
None,
Some(&model_name),
&format!("{}_controller_with_authorized_view", &model_name),
)?;
println!("Successfully written to {}.rs", model_name);
Ok(())
}
pub fn write_to_new_post_controller(model_name: String) -> Result<(), Error> {
let capitalized_model_name = capitalize_first(&model_name);
let controller_signature = format!("#[post(\"/{}/{{}}\")]", model_name);
let controller_contents = format!(
r#"
/// Alert: This is a generated controller.
/// The controller is generated by the rustyroad CLI.
/// It is a best guess at what the controller should look like.
/// Please review the controller and make any necessary changes.
#[post("/{}")]
pub async fn create_{}({}: Json<{}>,user: Option<Identity>) -> HttpResponse {{
if let Some(_user) = user {{
let result = {}::create_{}({}.into_inner()).await;
match result {{
Ok(page) => HttpResponse::Ok().json(page),
Err(e) => {{
eprintln!("Error creating page: {{:?}}", e); // Log the error
HttpResponse::BadRequest().json(e.to_string())
}}
}}
}} else {{
// redirect to login page
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to create a new {}.");
HttpResponse::Found()
.append_header((actix_web::http::header::LOCATION, "/login"))
.finish()
}}
// before we allow the user to create a new {} we need to check if they are logged in
// if they are not logged in, we need to redirect them to the login page
}}
"#,
&model_name,
&model_name,
&model_name,
&capitalized_model_name,
&capitalized_model_name,
&model_name,
&model_name,
&model_name,
&model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
if !file_contents.contains(&controller_signature) {
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "post");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models", &capitalized_model_name);
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Json");
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Data");
file_contents.push_str("\n\n");
file_contents.push_str(&controller_contents);
println!("File contents: {}", &file_contents.red());
println!("Controller contents: {}", &controller_contents.green());
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&path)
.unwrap();
writeln!(file, "{}", file_contents)?;
file.flush()?;
add_new_controller_to_main_rs(None, Some(&model_name), &format!("create_{}", &model_name))?;
println!("Successfully written to {}.rs", model_name);
Ok(())
} else {
println!("The controller already exists.");
Ok(())
}
}
pub fn write_to_new_delete_controller(model_name: String) -> Result<(), Error> {
let capitalized_model_name = crate::helpers::helpers::capitalize_first(&model_name);
let model_path = format!("./src/models/{}.rs", model_name);
let model_file_path = PathBuf::from(&model_path);
if !model_file_path.exists() {
println!(
"The model {} does not exist. Would you like to create it? (y/n)",
model_name
);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().eq_ignore_ascii_case("y") {
} else {
return Err(eyre!(
"The model {} does not exist. Please create it and try again.",
model_name
));
}
}
let contents = format!(
r#"#[delete("/{}/{{id}}")]
pub async fn delete_{}(id: Path<i32>, user: Option<Identity>) -> HttpResponse {{
if let Some(_user) = user {{
let result = {}::delete_{}(id.into_inner()).await;
match result {{
Ok(_) => HttpResponse::Ok().json("Successfully deleted."),
Err(e) => HttpResponse::BadRequest().json(e.to_string()),
}}
}} else {{
HttpResponse::Unauthorized().json("You must be logged in to delete.")
}}
}}"#,
&model_name, &model_name, &capitalized_model_name, &model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
file_contents = add_or_update_import(&file_contents, "actix_web", "delete");
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models::user", "UserLogin");
file_contents = add_or_update_import(
&file_contents,
format!("models::{}", &model_name).as_str(),
&capitalized_model_name,
);
file_contents.push_str("\n\n");
file_contents.push_str(&contents);
fs::write(PathBuf::from(&path), file_contents.as_bytes())?;
add_new_controller_to_main_rs(None, Some(&model_name), &format!("delete_{}", &model_name))?;
println!("Successfully written to {}.rs", model_name);
Ok(())
}
pub fn write_to_new_update_controller(model_name: String) -> Result<(), Error> {
let capitalized_model_name = capitalize_first(&model_name);
let model_path = format!("./src/models/{}.rs", model_name);
let model_file_path = PathBuf::from(&model_path);
if !model_file_path.exists() {
println!(
"The model {} does not exist. Would you like to create it? (y/n)",
model_name
);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().eq_ignore_ascii_case("y") {
} else {
return Err(eyre!(
"The model {} does not exist. Please create it and try again.",
model_name
));
}
}
let new_controller_content = format!(
r#"#[patch("/{}/{{id}}")]
pub async fn update_{}(id: Path<i32>, {}: Json<{}>, user: Option<Identity>) -> HttpResponse {{
if let Some(_user) = user {{
let result = {}::update_{}(id.into_inner(), {}.into_inner()).await;
match result {{
Ok(page) => HttpResponse::Ok().json(page),
Err(e) => HttpResponse::BadRequest().json(e.to_string()),
}}
}} else {{
HttpResponse::Unauthorized().json("You must be logged in to update.")
}}
}}"#,
&model_name,
&model_name,
&model_name,
&capitalized_model_name,
&capitalized_model_name,
&model_name,
&model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
file_contents = add_or_update_import(&file_contents, "actix_web", "patch");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models", &capitalized_model_name);
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Json");
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Path");
file_contents.push_str("\n\n");
file_contents.push_str(&new_controller_content);
file_contents.push_str("\n\n");
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&path)
.unwrap();
writeln!(file, "{}", file_contents)?;
file.flush()?;
add_new_controller_to_main_rs(None, Some(&model_name), &format!("update_{}", &model_name))?;
println!("Successfully written to {}.rs", model_name);
Ok(())
}
pub fn write_to_new_get_controller_with_authorized_view(model_name: String) -> Result<(), Error> {
let controller_signature = format!("#[put(\"/{}/{{id}}\")]", &model_name);
let _capitalized_model_name = crate::helpers::helpers::capitalize_first(&model_name);
let model_path = format!("./src/models/{}.rs", model_name);
let model_file_path = PathBuf::from(&model_path);
if !model_file_path.exists() {
println!(
"The model {} does not exist. Would you like to create it? (y/n)",
model_name
);
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.trim().eq_ignore_ascii_case("y") {
} else {
return Err(eyre!(
"The model {} does not exist. Please create it and try again.",
model_name
));
}
}
let new_controller_content = format!(
r#"#[get("/{}")]
async fn authenticated_view_for_{}(
tmpl: web::Data<Tera>,
user: Option<Identity>
) -> impl Responder {{
if let Some(_user) = user
{{
let mut context = Context::new();
context.insert("username", &user.id().unwrap());
context.insert("title", "{}");
context.insert("controller_name", "{}");
let rendered = tmpl.render("layouts/authenticated_page/{}/{}.html.tera", &context).unwrap();
HttpResponse::Ok().body(rendered)
}} else {{
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to view this page.");
HttpResponse::Found()
.append_header((actix_web::http::header::LOCATION, "/login"))
.finish()
}}
}}"#,
&model_name, &model_name, &model_name, &model_name, &model_name, &model_name
);
let path = determine_controller_path(&model_name);
let file_exists = PathBuf::from(&path).exists();
if !file_exists {
prompt_to_create_controller(&path).expect("Error prompting to create controller");
}
let mut file_contents = fs::read_to_string(&path)?;
if !file_contents.contains(&controller_signature) {
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models::user", "UserLogin");
file_contents.push_str("\n\n");
file_contents.push_str(&new_controller_content);
file_contents.push_str("\n\n");
fs::write(PathBuf::from(&path), file_contents.as_bytes())?;
add_new_controller_to_main_rs(
None,
Some(&model_name),
&format!("authenticated_view_for_{}", &model_name),
)?;
println!("Successfully written to {}.rs", model_name);
Ok(())
} else {
println!("The controller already exists.");
Ok(())
}
}
pub fn write_to_previous_get_controller(
previous_controller_name: String,
new_controller_name: String,
) -> Result<(), Error> {
let controller_signature = format!(
"#[get(\"/{}/{}\")]",
&previous_controller_name, &new_controller_name
);
let contents = format!(
r#"
#[get("/{}/{}")]
async fn {}(tmpl: web::Data<Tera>) -> impl Responder {{
let mut context = Context::new();
context.insert("controller_name", "{}");
let rendered = tmpl.render("pages/{}.html.tera", &context).unwrap();
HttpResponse::Ok().body(rendered)
}}"#,
previous_controller_name,
new_controller_name,
new_controller_name,
new_controller_name,
new_controller_name
);
let path = format!(
"./src/controllers/{}/{}.rs",
previous_controller_name, previous_controller_name
);
let mut file_contents = fs::read_to_string(&path).unwrap();
if !file_contents.contains(&controller_signature) {
file_contents.push_str(&contents);
write_to_file(&path, file_contents.as_bytes()).unwrap_or_else(|why| {
println!("Failed to write to {}: {:?}", &path, why.kind());
});
Ok(())
} else {
println!("The controller already exists.");
Ok(())
}
}
pub fn write_to_previous_create_controller(
previous_controller_name: String,
new_controller_name: String,
) -> Result<(), Error> {
let controller_signature = format!(
"#[post(\"/{}/{}\")]",
previous_controller_name, new_controller_name
);
let contents = format!(
r#"
use actix_identity::Identity;
use actix_web::{{post, web, HttpResponse}};
use crate::models::{};
/// Alert: This is a generated controller.
/// The controller is generated by the rustyroad CLI.
/// It is a best guess at what the controller should look like.
/// Please review the controller and make any necessary changes.
#[post("/{}/{}")]
pub async fn create_{}({}: web::Json<{}>,user: Option<Identity>) -> HttpResponse {{
if let Some(_user) = user {{
let result = {}::create_{}({}.into_inner()).await;
match result {{
Ok(page) => HttpResponse::Ok().json(page),
Err(e) => HttpResponse::BadRequest().json(e.to_string()),
}}
}} else {{
// redirect to login page
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to create a new {}.");
HttpResponse::Found()
.append_header((actix_web::http::header::LOCATION, "/login"))
.finish()
}}
// before we allow the user to create a new {} we need to check if they are logged in
// if they are not logged in, we need to redirect them to the login page
}}"#,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name,
&new_controller_name
);
let mut path = format!(
"./src/controllers/{}/{}.rs",
previous_controller_name, previous_controller_name
);
path = if std::path::Path::exists(path.as_ref()) {
path.to_string()
} else {
format!("./src/controllers/{}.rs", previous_controller_name)
};
let mut file_contents = fs::read_to_string(&path).unwrap();
if !file_contents.contains(&controller_signature) {
file_contents.push_str(&contents);
write_to_file(&path, file_contents.as_bytes()).unwrap_or_else(|why| {
println!("Failed to write to {}: {:?}", &path, why.kind());
});
Ok(())
} else {
println!("The controller already exists.");
Ok(())
}
}
pub fn write_to_initial_get_controller(controller_name: String) -> Result<(), Error> {
let new_controller_name = controller_name
.trim_start_matches("./src/controllers/")
.trim_end_matches(".rs");
let controller_file_name = std::path::Path::new(&controller_name)
.file_name()
.and_then(std::ffi::OsStr::to_str)
.unwrap_or("");
let contents = format!(
r#"use actix_web::{{get, web, HttpResponse, HttpRequest, Error}};
use tera::{{Context, Tera}};
use crate::models;
use rustyroad::database::Database;
use models::user::UserLogin;
#[get("/{}")]
async fn {}_controller(tmpl: web::Data<Tera>) -> HttpResponse {{
let mut context = Context::new();
context.insert("controller_name", "{}");
let rendered = tmpl.render("pages/{}.html.tera", &context).unwrap();
HttpResponse::Ok().body(rendered)
}}"#,
controller_file_name.trim_end_matches(".rs"),
controller_file_name.trim_end_matches(".rs"),
controller_file_name.trim_end_matches(".rs"),
controller_file_name.trim_end_matches(".rs")
);
write_to_file(&controller_name.to_string(), contents.as_bytes()).unwrap_or_else(|why| {
println!(
"Failed to write to {}: {:?}",
new_controller_name,
why.kind()
);
});
Ok(())
}
pub fn write_to_initial_post_controller_authentication(
controller_name: String,
) -> Result<(), Error> {
let new_controller_name = controller_name
.trim_start_matches("./src/controllers/")
.trim_end_matches(".rs");
let contents = r#"
use actix_web::post;
#[post("/login")]
async fn login_function(
form: web::Form<UserLogin>,
tmpl: web::Data<Tera>, // Updated line
db: web::Data<Database>,
req: HttpRequest
) -> Result<HttpResponse, actix_web::Error> {
form.user_login(req, tmpl, db.get_ref().clone()).await
}
#[get("/logout")]
async fn user_logout(
tmpl: web::Data<Tera>,
user: Option<actix_identity::Identity>,
) -> Result<HttpResponse, Error> {
if let Some(user) = user {
UserLogin::user_logout(tmpl, user).await
} else {
let mut context = Context::new();
context.insert("controller_name", "login");
context.insert("error", "You must be logged in to logout.");
let rendered = tmpl.render("pages/login.html.tera", &context).unwrap();
Ok(HttpResponse::Ok().body(rendered))
}
}
"#
.to_string();
write_to_file(&controller_name.to_string(), contents.as_bytes()).unwrap_or_else(|why| {
println!(
"Failed to write to {}: {:?}",
new_controller_name,
why.kind()
);
});
Ok(())
}
pub fn write_to_controller_file_no_folder(
model_name: String,
import_contents: String,
method_contents: String,
) {
let path = format!("./src/controllers/{}.rs", model_name);
let file_contents = match fs::read_to_string(&path) {
std::result::Result::Ok(contents) => contents,
Err(_) => String::new(), };
let updated_imports = import_contents
.split('\n')
.fold(file_contents, |acc, import| {
if !import.trim().is_empty() {
let parts: Vec<&str> = import.split("::").collect();
if parts.len() > 1 {
let module = parts[0].trim();
let import_item = parts[1].trim_matches('{').trim_matches('}').trim();
add_or_update_import(&acc, module, import_item)
} else {
acc }
} else {
acc
}
});
let combined_contents = format!("{}\n\n{}", updated_imports, method_contents);
match fs::write(PathBuf::from(&path), combined_contents.as_bytes()) {
std::result::Result::Ok(()) => {
add_new_controller_to_main_rs(
None,
Some(&model_name),
&format!("create_{}", &model_name),
)
.unwrap_or_else(|why| {
println!(
"Couldn't add the create_{} controller to the main.rs file: {}",
&model_name, why
);
});
let mut components = Vec::new();
components.push((&model_name).to_string());
let module_path = format!("src/controllers/{}.rs", &model_name);
write_to_module(&module_path, components)
.expect("Error writing the module to the controllers module");
println!("Successfully written to {}.rs", model_name)
}
Err(e) => println!("Failed to write to {}.rs: {:?}", model_name, e),
}
}
pub fn write_to_page_dashboard_get_controller() -> Result<(), Error> {
let controller_signature = "#[get(\"/page_dashboard\")]";
let new_controller_content = r#"
#[get("/page_dashboard")]
async fn page_dashboard(tmpl: Data<Tera>, user: Option<Identity>) -> HttpResponse {
if let Some(user) = user {
let pages_result = Page::get_all_pages().await; // Await the future
let mut context = Context::new();
match pages_result {
Ok(pages) => {
let pages_data = pages.get("data").unwrap().as_array().unwrap();
context.insert("pages", pages_data);
context.insert("error", ""); // Insert an empty string for the error variable
}
Err(e) => {
println!("Error: {}", e);
let message = json!({"error": e.to_string()});
context.insert("error", &message);
context.insert("pages", &Vec::<Page>::new()); // Insert an empty vector for the pages variable
}
};
context.insert("username", &user.id().unwrap());
context.insert("title", "Dashboard");
context.insert("controller_name", "page_dashboard");
let rendered = tmpl
.render(
"layouts/authenticated_page/page/page_dashboard.html.tera",
&context,
)
.expect("Failed to render template");
HttpResponse::Ok().body(rendered)
} else {
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to view this page.");
HttpResponse::Found()
.append_header((LOCATION, "/login"))
.finish()
}
}
"#;
let path = "./src/controllers/dashboard.rs".to_string();
let mut file_contents = fs::read_to_string(path.clone())?;
if !file_contents.contains(controller_signature) {
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models", "Page");
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "actix_web", "http::header::LOCATION");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents = add_or_update_import(&file_contents, "serde_json", "json");
file_contents.push_str("\n\n");
file_contents.push_str(new_controller_content);
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&path)
.unwrap();
writeln!(file, "{}", file_contents)?;
file.flush()?;
println!("Successfully written to dashboard.rs");
add_new_controller_to_main_rs(None, None, "page_dashboard")?;
Ok(())
} else {
println!("The controller already exists.");
Ok(())
}
}
pub fn write_to_create_page_dashboard_get_controller() -> Result<(), Error> {
let controller_signature = "#[get(\"/create_page\")]";
let new_controller_content = r#"
#[get("/create_page")]
async fn create_page_dashboard(tmpl: Data<Tera>, user: Option<Identity>) -> HttpResponse {
if let Some(user) = user {
let mut context = Context::new();
context.insert("title", "Create Page");
context.insert("route_name", "create_page");
let mut page = Page::new();
page.id = Some(0);
let html_content = "<h1 class=\"text-center\">Welcome To The Page Builder</h1><p class=\"text-center\">Drag a block from the right side to this area to get started.</p>";
page.html_content = html_content.to_string();
context.insert("page", &page);
context.insert("username", &user.id().unwrap());
context.insert("html_content", &page.html_content);
let s = tmpl
.render(
"layouts/authenticated_page/page/page_details.html.tera",
&context,
)
.unwrap();
HttpResponse::Ok().body(s)
} else {
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to view this page.");
HttpResponse::Found()
.append_header((LOCATION, "/login"))
.finish()
}
}
"#;
let path = "./src/controllers/dashboard.rs".to_string();
let mut file_contents = fs::read_to_string(path.clone())?;
if !file_contents.contains(controller_signature) {
file_contents.push_str("\n\n");
file_contents.push_str(new_controller_content);
fs::write(PathBuf::from(path), file_contents.as_bytes())?;
println!("Successfully written to dashboard.rs");
add_new_controller_to_main_rs(None, None, "create_page_dashboard")?;
Ok(())
} else {
println!("The controller already exists.");
Ok(())
}
}
pub fn write_to_edit_page_get_controller() -> Result<(), Error> {
let controller_signature = "#[get(\"/page/{id}/edit\")]";
let new_controller_content = r#"
#[get("/page/{id}/edit")]
pub async fn edit_page(tmpl: Data<Tera>, id: Path<i32>, user: Option<Identity>) -> HttpResponse {
if let Some(_user) = user {
let result = Page::get_page_by_id(id.into_inner()).await;
match result {
Ok(page) => {
let mut context = Context::new();
context.insert("title", "Edit Page");
context.insert("route_name", "edit_page");
context.insert("html_content", &page.html_content);
context.insert("page", &page);
context.insert("page_id", &page.id);
context.insert("username", &_user.id().unwrap());
let s = tmpl.render("layouts/authenticated_page/page/edit_page.html.tera", &context).unwrap();
HttpResponse::Ok().body(s)
}
Err(e) => {
let mut context = Context::new();
context.insert("error", &e.to_string());
let s = tmpl.render("layouts/authenticated_page/page/edit_page.html.tera", &context).unwrap();
HttpResponse::Ok().body(s)
}
}
} else {
HttpResponse::Unauthorized().json("You must be logged in to edit.")
}
}
"#;
let path = "./src/controllers/page.rs".to_string();
let mut file_contents = fs::read_to_string(path.clone())?;
if !file_contents.contains(controller_signature) {
file_contents = add_or_update_import(&file_contents, "crate", "models");
file_contents = add_or_update_import(&file_contents, "models", "Page");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Path");
file_contents = add_or_update_import(&file_contents, "actix_web", "web::Data");
file_contents = add_or_update_import(&file_contents, "actix_identity", "Identity");
file_contents.push_str("\n\n");
file_contents.push_str(new_controller_content);
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&path)
.unwrap();
writeln!(file, "{}", file_contents)?;
file.flush()?;
println!("Successfully written to dashboard.rs");
add_new_controller_to_main_rs(None, Some("page"), "edit_page")?;
Ok(())
} else {
println!("The edit_page controller already exists.");
Ok(())
}
}
pub fn write_to_new_dashboard_get_controller_to_test(file_path: &Path) -> Result<(), Error> {
let new_controller_content = r#"
#[get("/page_dashboard")]
async fn page_dashboard(tmpl: web::Data<Tera>, user: Option<Identity>) -> impl Responder {
if let Some(_user) = user {
let mut context = Context::new();
let (pages, error) = match pages_result {
Ok(pages) if pages.is_empty() => (Vec::new(), "No pages found".to_string()),
Ok(pages) => (pages, "".to_string()),
Err(e) => (Vec::new(), e.to_string()),
};
context.insert("pages", &pages);
context.insert("error", &error);
context.insert("username", &user.id().unwrap());
context.insert("title", "Dashboard");
context.insert("controller_name", "page_dashboard");
let rendered = tmpl.render("layouts/authenticated_page/page/page_dashboard.html.tera", &context).unwrap();
HttpResponse::Ok().body(rendered)
} else {
let mut context = Context::new();
context.insert("title", "Login");
context.insert("route_name", "login");
context.insert("error", "You must be logged in to view this page.");
HttpResponse::Found()
.append_header((actix_web::http::header::LOCATION, "/login"))
.finish()
}
}"#;
let mut file_contents = fs::read_to_string(file_path)?;
file_contents = add_or_update_import(&file_contents, "actix_web", "get");
file_contents = add_or_update_import(&file_contents, "actix_web", "web");
file_contents = add_or_update_import(&file_contents, "actix_web", "HttpResponse");
file_contents = add_or_update_import(&file_contents, "actix_web", "Responder");
file_contents = add_or_update_import(&file_contents, "tera", "Tera");
file_contents = add_or_update_import(&file_contents, "tera", "Context");
file_contents.push_str("\n\n");
file_contents.push_str(new_controller_content);
fs::write(PathBuf::from(file_path), file_contents.as_bytes())?;
println!("Successfully written to dashboard.rs");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::NamedTempFile;
#[test]
fn test_write_to_new_dashboard_get_controller() {
let temp_file = NamedTempFile::new().unwrap();
let file_path = temp_file.path().to_path_buf();
let initial_content = "use actix_web::{HttpResponse, Responder};\n";
fs::write(&file_path, initial_content).unwrap();
write_to_new_dashboard_get_controller_to_test(&file_path).unwrap();
let updated_content = fs::read_to_string(file_path).unwrap();
assert!(updated_content.contains("#[get(\"/page_dashboard\")]"));
assert!(updated_content.contains("async fn page_dashboard"));
}
}