use crate::database::Database;
use crate::models::projects;
use crate::models::users::User;
use lazy_static::lazy_static;
use regex::Regex;
use rocket::{
form::{self, Error, Form},
response::{Flash, Redirect},
Route, State,
};
use rocket_dyn_templates::Template;
#[get("/projects/new")]
fn new(user: User) -> Template {
Template::render(
"projects/new",
crate::context! {
current_user: user,
},
)
}
fn validate_project_name<'v>(name: &String) -> form::Result<'v, ()> {
lazy_static! {
static ref RE: Regex = Regex::new(r"\A[\w\d]{2,20}\z").unwrap();
}
if !RE.is_match(&name) {
Err(Error::validation(
"only up to 20 letters or digets are to be used as project name",
))?;
}
Ok(())
}
#[derive(FromForm)]
struct NewProject {
#[field(validate = validate_project_name())]
name: String,
}
#[post("/projects", data = "<project>")]
async fn create(
db: &State<Database>,
project: Form<NewProject>,
user: User,
) -> Result<Flash<Redirect>, Flash<Redirect>> {
match projects::create(&**db, user.id, project.name.clone()).await {
Ok(_) => Ok(Flash::success(Redirect::to("/"), "Project is created")),
Err(_e) => Err(Flash::error(
Redirect::to("/projects/new"),
"Something went wrong",
)),
}
}
#[get("/<org_path>/<proj_path>", rank = 3)]
async fn show_anonymous(
db: &State<Database>,
org_path: String,
proj_path: String,
) -> Result<Template, rocket::http::Status> {
let p = if let Some(p) = projects::find(&**db, org_path, proj_path).await {
p
} else {
return Err(rocket::http::Status::InternalServerError);
};
Ok(Template::render(
"projects/show",
crate::context! {
project: p.clone(),
organisation: p.organisation(&**db).await.ok(),
},
))
}
#[get("/<org_path>/<proj_path>", rank = 4)]
async fn show(
db: &State<Database>,
user: User,
org_path: String,
proj_path: String,
) -> Result<Template, rocket::http::Status> {
let p = if let Some(p) = projects::find(&**db, org_path, proj_path).await {
p
} else {
return Err(rocket::http::Status::InternalServerError);
};
Ok(Template::render(
"projects/show",
crate::context! {
current_user: user,
project: p.clone(),
organisation: p.organisation(&**db).await.ok(),
},
))
}
use std::vec::Vec;
#[get("/projects/explore")]
async fn explore(
db: &State<Database>,
current_user: Option<User>,
) -> Result<Template, rocket::http::Status> {
let projects = if let Ok(projects) = projects::list(&**db).await {
projects
} else {
return Err(rocket::http::Status::InternalServerError);
};
let mut disp = Vec::new();
for proj in projects.iter() {
disp.push(projects::DispProject::new(&**db, proj.clone()).await)
}
Ok(Template::render(
"projects/explore",
crate::context! {
current_user: current_user,
projects: disp,
},
))
}
pub fn routes() -> Vec<Route> {
routes![new, create, show, show_anonymous, explore]
}