You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
6.9 KiB

pub mod forms;
pub mod db;
use bcrypt::{
hash,
verify,
DEFAULT_COST
};
use rocket::{
form::Form,
response::Redirect,
State
};
use forms::{
UserLoginForm,
NewUserForm,
NewListForm,
PermsForm,
NewNoteForm,
};
use db::{
List,
Notes,
Note,
Result,
add_permission,
get_user_from_email,
get_user_lists,
get_user_lists_from_perms,
get_notes_from_list,
add_note_to_list,
User,
};
#[macro_use] extern crate rocket;
use rocket_dyn_templates::{Template, context};
use rocket_db_pools::{
Database,
Connection,
sqlx::{
self,
Row,
},
};
use rocket::{
serde::{
Serialize
},
http::{
Cookie,
CookieJar,
RawStr,
},
};
#[get("/hello/<name>/<age>")]
async fn hello(name: &str, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name)
}
#[get("/")]
async fn home() -> Template {
Template::render("index", context!{})
}
#[get("/create")]
async fn create() -> Template {
Template::render("new", context!{})
}
#[post("/new", data="<user>")]
async fn new_user(user: Form<NewUserForm<'_>>, mut db: Connection<Notes>) -> Result<String> {
let check_exists = sqlx::query!("SELECT id FROM users WHERE username = $1 OR email = $2", user.username, user.email)
.fetch_optional(&mut *db)
.await?;
if check_exists.is_some() {
return Ok(format!("This account already exists!"));
}
let hashed_pass = match hash(user.password, DEFAULT_COST) {
Ok(pass) => pass,
Err(e) => panic!("Could not hash a password! {}", e)
};
sqlx::query!("INSERT INTO users (username,password,email) VALUES ($1, $2, $3)", user.username, hashed_pass, user.email)
.execute(&mut *db)
.await?;
Ok(format!("Thanks, {}, for creating an account on our service.", user.username))
}
#[post("/login", data="<user>")]
async fn login(user: Form<UserLoginForm<'_>>, mut db: Connection<Notes>, cookies: &CookieJar<'_>) -> Result<String> {
match cookies.get_private("user_uuid") {
Some(crumb) => println!("UUID: {:?}", crumb.value()),
_ => {}
};
let result = sqlx::query!("SELECT * FROM users WHERE username=$1", user.username)
.fetch_optional(&mut *db)
.await?;
let success = match result {
Some(ref db_user) => verify(&user.password, &db_user.password).unwrap(),
_ => false,
};
if success {
cookies.add_private(Cookie::new("user_uuid", result.unwrap().uuid));
Ok(format!("Yay! Thanks for logging in to our service!"))
} else {
Ok(format!("Incorrect login!"))
}
}
#[post("/list", data="<new_list>")]
async fn new_list(mut db: Connection<Notes>, user: User, new_list: Form<NewListForm<'_>>) -> Result<String> {
sqlx::query!("INSERT INTO list (owner_id, name) VALUES ($1, $2)", user.id, new_list.name)
.execute(&mut *db)
.await?;
Ok(format!("You added a new list: {}", new_list.name))
}
#[post("/list", data="<new_list>", rank=2)]
async fn new_list_not_logged_in(new_list: Form<NewListForm<'_>>) -> Redirect {
Redirect::to(uri!(home))
}
#[get("/lists")]
async fn show_list(mut db: Connection<Notes>, user: User) -> Result<Template> {
Ok(Template::render("show_lists", context!{
lists: get_user_lists(&mut db, user.id).await?,
perm_lists: get_user_lists_from_perms(&mut db, user.id).await?
}))
}
#[get("/lists", rank=2)]
async fn show_list_not_logged_in() -> Redirect {
Redirect::to(uri!(home))
}
#[get("/new/list")]
async fn new_list_form(_user: User) -> Template {
Template::render("new_list", context!{})
}
#[get("/new/list", rank=2)]
async fn new_list_form_not_logged_in() -> Redirect {
Redirect::to(uri!(home))
}
#[get("/new/note/<list_uuid>")]
async fn new_note_form(mut db: Connection<Notes>, user: User, list_uuid: String) -> Result<Template> {
Ok(Template::render("new_note_form", context!{
list_uuid: list_uuid
}))
}
#[post("/note", data="<note>")]
async fn new_note(mut db: Connection<Notes>, user: User, note: Form<NewNoteForm<'_>>) -> Result<String> {
let list = match List::from_uuid(note.list_uuid.to_string(), &mut *db).await? {
Some(l) => l,
None => return Ok(format!("List not found!")),
};
match add_note_to_list(&mut *db, list.id, note.content.to_string(), user.id).await {
Ok(_) => Ok(format!("Added note!")),
Err(_) => Ok(format!("Error!"))
}
}
#[post("/perms", data="<perms>")]
async fn new_perms(perms: Form<PermsForm<'_>>, user: User, mut db: Connection<Notes>) -> Result<String> {
let perm_user = match get_user_from_email(&mut db, perms.user_email.to_string()).await? {
Some(u) => {
if u.id == user.id { return Ok(format!("You may not grant yourself a permission.")); } else { u }
},
None => return Ok(format!("Permission is added.")),
};
match add_permission(&mut db, perm_user.id, perms.list_id, perms.perm).await {
Err(_) => Ok(format!("There was an error adding this permission.")),
Ok(_) => Ok(format!("Permission is added.")),
}
}
#[post("/perms", data="<perms>", rank=2)]
async fn new_perms_not_logged_in(perms: Form<PermsForm<'_>>) -> Redirect {
Redirect::to(uri!(home))
}
#[get("/new/perms")]
async fn add_perms_form(mut db: Connection<Notes>, user: User) -> Result<Template> {
Ok(Template::render("new_perms", context!{
lists: get_user_lists(&mut db, user.id).await?
}))
}
#[get("/new/perms", rank=2)]
async fn add_perms_form_not_logged_in() -> Redirect {
Redirect::to(uri!(home))
}
#[get("/logout")]
async fn logout(mut db: Connection<Notes>, cookies: &CookieJar<'_>) -> Result<String> {
let uuid = cookies.get_private("user_uuid");
if uuid.is_none() {
return Ok(format!("You aren't logged in, lol!"));
}
cookies.remove_private(Cookie::named("user_uuid"));
let actual_uuid = uuid.unwrap();
let result = sqlx::query!("SELECT * FROM users WHERE uuid = $1", actual_uuid.value())
.fetch_optional(&mut *db)
.await?;
if let Some(user) = result {
Ok(format!("User '{}', logged out.", user.username))
} else {
Ok(format!("We don't know what happened..."))
}
}
#[get("/notes/<list_uuid>")]
async fn show_notes(user: User, mut db: Connection<Notes>, list_uuid: String) -> Result<Template> {
let list = match List::from_uuid(list_uuid, &mut *db).await? {
Some(list) => list,
None => panic!("LOL!"),
};
Ok(Template::render("show_notes", context!{
notes: get_notes_from_list(list.id, &mut *db).await?
}))
}
#[launch]
fn rocket() -> _ {
rocket::build()
.attach(Template::fairing())
.attach(Notes::init())
.mount("/", routes![
hello,
home,
login,
new_user,
create,
logout
])
.mount("/new", routes![
new_list, new_list_not_logged_in,
new_perms, new_perms_not_logged_in,
new_note, //new_note_not_logged_in,
])
.mount("/show", routes![
show_list, show_list_not_logged_in,
show_notes,
])
.mount("/forms", routes![
add_perms_form, add_perms_form_not_logged_in,
new_list_form, new_list_form_not_logged_in,
new_note_form,
])
}