d8ca1d70b7
GET routes are not protected against CSRF. This commit changes the needed URLs to POST and replace simple links with forms. Thanks @fdb-hiroshima for noticing it!
118 lines
4.1 KiB
Rust
118 lines
4.1 KiB
Rust
use guid_create::GUID;
|
|
use multipart::server::{Multipart, save::{SavedData, SaveResult}};
|
|
use rocket::{Data, http::ContentType, response::{NamedFile, Redirect}};
|
|
use rocket_contrib::Template;
|
|
use serde_json;
|
|
use std::{fs, path::{Path, PathBuf}};
|
|
use plume_models::{db_conn::DbConn, medias::*, users::User};
|
|
|
|
#[get("/medias")]
|
|
fn list(user: User, conn: DbConn) -> Template {
|
|
let medias = Media::for_user(&*conn, user.id);
|
|
Template::render("medias/index", json!({
|
|
"account": user.to_json(&*conn),
|
|
"medias": medias.into_iter().map(|m| m.to_json(&*conn)).collect::<Vec<serde_json::Value>>()
|
|
}))
|
|
}
|
|
|
|
#[get("/medias/new")]
|
|
fn new(user: User, conn: DbConn) -> Template {
|
|
Template::render("medias/new", json!({
|
|
"account": user.to_json(&*conn),
|
|
"form": {},
|
|
"errors": {}
|
|
}))
|
|
}
|
|
|
|
#[post("/medias/new", data = "<data>")]
|
|
fn upload(user: User, data: Data, ct: &ContentType, conn: DbConn) -> Redirect {
|
|
if ct.is_form_data() {
|
|
let (_, boundary) = ct.params().find(|&(k, _)| k == "boundary").expect("No boundary");
|
|
|
|
match Multipart::with_body(data.open(), boundary).save().temp() {
|
|
SaveResult::Full(entries) => {
|
|
let fields = entries.fields;
|
|
|
|
let filename = fields.get(&"file".to_string()).unwrap().into_iter().next().unwrap().headers
|
|
.filename.clone()
|
|
.unwrap_or("x.png".to_string()); // PNG by default
|
|
let ext = filename.rsplitn(2, ".")
|
|
.next()
|
|
.unwrap();
|
|
let dest = format!("media/{}.{}", GUID::rand().to_string(), ext);
|
|
|
|
if let SavedData::Bytes(ref bytes) = fields[&"file".to_string()][0].data {
|
|
fs::write(&dest, bytes).expect("Couldn't save upload");
|
|
} else {
|
|
if let SavedData::File(ref path, _) = fields[&"file".to_string()][0].data {
|
|
fs::copy(path, &dest).expect("Couldn't copy temp upload");
|
|
} else {
|
|
println!("not file");
|
|
return Redirect::to(uri!(new));
|
|
}
|
|
}
|
|
|
|
let has_cw = read(&fields[&"cw".to_string()][0].data).len() > 0;
|
|
let media = Media::insert(&*conn, NewMedia {
|
|
file_path: dest,
|
|
alt_text: read(&fields[&"alt".to_string()][0].data),
|
|
is_remote: false,
|
|
remote_url: None,
|
|
sensitive: has_cw,
|
|
content_warning: if has_cw {
|
|
Some(read(&fields[&"cw".to_string()][0].data))
|
|
} else {
|
|
None
|
|
},
|
|
owner_id: user.id
|
|
});
|
|
println!("ok");
|
|
Redirect::to(uri!(details: id = media.id))
|
|
},
|
|
SaveResult::Partial(_, _) | SaveResult::Error(_) => {
|
|
println!("partial err");
|
|
Redirect::to(uri!(new))
|
|
}
|
|
}
|
|
} else {
|
|
println!("not form data");
|
|
Redirect::to(uri!(new))
|
|
}
|
|
}
|
|
|
|
fn read(data: &SavedData) -> String {
|
|
if let SavedData::Text(s) = data {
|
|
s.clone()
|
|
} else {
|
|
panic!("Field is not a string")
|
|
}
|
|
}
|
|
|
|
#[get("/medias/<id>")]
|
|
fn details(id: i32, user: User, conn: DbConn) -> Template {
|
|
let media = Media::get(&*conn, id);
|
|
Template::render("medias/details", json!({
|
|
"account": user.to_json(&*conn),
|
|
"media": media.map(|m| m.to_json(&*conn))
|
|
}))
|
|
}
|
|
|
|
#[post("/medias/<id>/delete")]
|
|
fn delete(id: i32, _user: User, conn: DbConn) -> Redirect {
|
|
let media = Media::get(&*conn, id).expect("Media to delete not found");
|
|
media.delete(&*conn);
|
|
Redirect::to(uri!(list))
|
|
}
|
|
|
|
#[post("/medias/<id>/avatar")]
|
|
fn set_avatar(id: i32, user: User, conn: DbConn) -> Redirect {
|
|
let media = Media::get(&*conn, id).expect("Media to delete not found");
|
|
user.set_avatar(&*conn, media.id);
|
|
Redirect::to(uri!(details: id = id))
|
|
}
|
|
|
|
#[get("/static/media/<file..>", rank = 1)]
|
|
fn static_files(file: PathBuf) -> Option<NamedFile> {
|
|
NamedFile::open(Path::new("media/").join(file)).ok()
|
|
}
|