Media upload
This commit is contained in:
+10
-2
@@ -1,6 +1,6 @@
|
||||
#![feature(custom_derive, decl_macro, plugin)]
|
||||
#![plugin(rocket_codegen)]
|
||||
|
||||
|
||||
extern crate activitypub;
|
||||
extern crate atom_syndication;
|
||||
extern crate colored;
|
||||
@@ -8,7 +8,9 @@ extern crate diesel;
|
||||
extern crate dotenv;
|
||||
extern crate failure;
|
||||
extern crate gettextrs;
|
||||
extern crate guid_create;
|
||||
extern crate heck;
|
||||
extern crate multipart;
|
||||
extern crate plume_common;
|
||||
extern crate plume_models;
|
||||
extern crate rocket;
|
||||
@@ -61,6 +63,12 @@ fn main() {
|
||||
routes::likes::create,
|
||||
routes::likes::create_auth,
|
||||
|
||||
routes::medias::list,
|
||||
routes::medias::new,
|
||||
routes::medias::upload,
|
||||
routes::medias::details,
|
||||
routes::medias::static_files,
|
||||
|
||||
routes::notifications::paginated_notifications,
|
||||
routes::notifications::notifications,
|
||||
routes::notifications::notifications_auth,
|
||||
@@ -123,7 +131,7 @@ fn main() {
|
||||
.add_exceptions(vec![
|
||||
("/inbox".to_owned(), "/inbox".to_owned(), rocket::http::Method::Post),
|
||||
("/@/<name>/inbox".to_owned(), "/@/<name>/inbox".to_owned(), rocket::http::Method::Post),
|
||||
|
||||
("/medias/new".to_owned(), "/medias/new".to_owned(), rocket::http::Method::Post), // not compatible with multipart/form-data
|
||||
])
|
||||
.finalize().unwrap())
|
||||
.launch();
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
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,
|
||||
"medias": medias.into_iter().map(|m| m.to_json(&*conn)).collect::<Vec<serde_json::Value>>()
|
||||
}))
|
||||
}
|
||||
|
||||
#[get("/medias/new")]
|
||||
fn new(user: User) -> Template {
|
||||
Template::render("medias/new", json!({
|
||||
"account": user,
|
||||
"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,
|
||||
"media": media.map(|m| m.to_json(&*conn))
|
||||
}))
|
||||
}
|
||||
|
||||
#[get("/static/media/<file..>", rank = 1)]
|
||||
fn static_files(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new("media/").join(file)).ok()
|
||||
}
|
||||
|
||||
+2
-1
@@ -103,6 +103,7 @@ pub mod comments;
|
||||
pub mod errors;
|
||||
pub mod instance;
|
||||
pub mod likes;
|
||||
pub mod medias;
|
||||
pub mod notifications;
|
||||
pub mod posts;
|
||||
pub mod reshares;
|
||||
@@ -110,7 +111,7 @@ pub mod session;
|
||||
pub mod user;
|
||||
pub mod well_known;
|
||||
|
||||
#[get("/static/<file..>")]
|
||||
#[get("/static/<file..>", rank = 2)]
|
||||
fn static_files(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new("static/").join(file)).ok()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user