Import and update the file service application and orizentic #72
|
@ -611,6 +611,19 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
||||||
|
dependencies = [
|
||||||
|
"humantime",
|
||||||
|
"is-terminal",
|
||||||
|
"log 0.4.20",
|
||||||
|
"regex",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -695,12 +708,14 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"image 0.23.14",
|
"image 0.23.14",
|
||||||
"iron",
|
"iron",
|
||||||
|
"log 0.4.20",
|
||||||
"logger",
|
"logger",
|
||||||
"mime 0.3.17",
|
"mime 0.3.17",
|
||||||
"mime_guess 2.0.4",
|
"mime_guess 2.0.4",
|
||||||
"mustache",
|
"mustache",
|
||||||
"orizentic",
|
"orizentic",
|
||||||
"params",
|
"params",
|
||||||
|
"pretty_env_logger",
|
||||||
"router",
|
"router",
|
||||||
"serde 1.0.188",
|
"serde 1.0.188",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1515,6 +1530,12 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.10.16"
|
version = "0.10.16"
|
||||||
|
@ -1729,6 +1750,17 @@ dependencies = [
|
||||||
"url 1.7.2",
|
"url 1.7.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.3.2",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.5"
|
version = "0.10.5"
|
||||||
|
@ -2616,6 +2648,16 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_env_logger"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c"
|
||||||
|
dependencies = [
|
||||||
|
"env_logger",
|
||||||
|
"log 0.4.20",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
@ -3417,6 +3459,15 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -4086,6 +4137,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
@ -27,3 +27,5 @@ thiserror = "1.0.20"
|
||||||
tokio = { version = "1", features = [ "full" ] }
|
tokio = { version = "1", features = [ "full" ] }
|
||||||
uuid = { version = "0.4", features = [ "serde", "v4" ] }
|
uuid = { version = "0.4", features = [ "serde", "v4" ] }
|
||||||
warp = { version = "0.3" }
|
warp = { version = "0.3" }
|
||||||
|
pretty_env_logger = { version = "0.5" }
|
||||||
|
log = { version = "0.4" }
|
||||||
|
|
|
@ -2,6 +2,7 @@ use build_html::{self, Html, HtmlContainer};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Form {
|
pub struct Form {
|
||||||
|
path: String,
|
||||||
method: String,
|
method: String,
|
||||||
encoding: Option<String>,
|
encoding: Option<String>,
|
||||||
elements: String,
|
elements: String,
|
||||||
|
@ -10,12 +11,18 @@ pub struct Form {
|
||||||
impl Form {
|
impl Form {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
path: "/".to_owned(),
|
||||||
method: "get".to_owned(),
|
method: "get".to_owned(),
|
||||||
encoding: None,
|
encoding: None,
|
||||||
elements: "".to_owned(),
|
elements: "".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_path(mut self, path: &str) -> Self {
|
||||||
|
self.path = path.to_owned();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_method(mut self, method: &str) -> Self {
|
pub fn with_method(mut self, method: &str) -> Self {
|
||||||
self.method = method.to_owned();
|
self.method = method.to_owned();
|
||||||
self
|
self
|
||||||
|
@ -30,11 +37,12 @@ impl Form {
|
||||||
impl Html for Form {
|
impl Html for Form {
|
||||||
fn to_html_string(&self) -> String {
|
fn to_html_string(&self) -> String {
|
||||||
let encoding = match self.encoding {
|
let encoding = match self.encoding {
|
||||||
Some(ref encoding) => format!("encoding={encoding}", encoding = encoding),
|
Some(ref encoding) => format!("encoding=\"{encoding}\"", encoding = encoding),
|
||||||
None => format!(""),
|
None => format!(""),
|
||||||
};
|
};
|
||||||
format!(
|
format!(
|
||||||
"<form method={method} {encoding}>\n{elements}\n</form>\n",
|
"<form action=\"{path}\" method=\"{method}\" {encoding}>\n{elements}\n</form>\n",
|
||||||
|
path = self.path,
|
||||||
method = self.method,
|
method = self.method,
|
||||||
encoding = encoding,
|
encoding = encoding,
|
||||||
elements = self.elements.to_html_string()
|
elements = self.elements.to_html_string()
|
||||||
|
@ -52,36 +60,58 @@ impl HtmlContainer for Form {
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
ty: String,
|
ty: String,
|
||||||
name: String,
|
name: String,
|
||||||
id: String,
|
id: Option<String>,
|
||||||
value: Option<String>,
|
value: Option<String>,
|
||||||
|
content: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Html for Input {
|
impl Html for Input {
|
||||||
fn to_html_string(&self) -> String {
|
fn to_html_string(&self) -> String {
|
||||||
|
let id = match self.id {
|
||||||
|
Some(ref id) => format!("id=\"{}\"", id),
|
||||||
|
None => "".to_owned(),
|
||||||
|
};
|
||||||
|
let value = match self.value {
|
||||||
|
Some(ref value) => format!("value=\"{}\"", value),
|
||||||
|
None => "".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"<input type=\"{ty}\" name=\"{name}\" id=\"{id}\">{value}</input>\n",
|
"<input type=\"{ty}\" name=\"{name}\" {id} {value}>{content}</input>\n",
|
||||||
ty = self.ty,
|
ty = self.ty,
|
||||||
name = self.name,
|
name = self.name,
|
||||||
id = self.id,
|
id = id,
|
||||||
value = self.value.clone().unwrap_or("".to_owned()),
|
value = value,
|
||||||
|
content = self.content.clone().unwrap_or("".to_owned()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn new(ty: &str, name: &str, id: &str) -> Self {
|
pub fn new(ty: &str, name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ty: ty.to_owned(),
|
ty: ty.to_owned(),
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
id: id.to_owned(),
|
id: None,
|
||||||
value: None,
|
value: None,
|
||||||
|
content: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_id(mut self, val: &str) -> Self {
|
||||||
|
self.id = Some(val.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_value(mut self, val: &str) -> Self {
|
pub fn with_value(mut self, val: &str) -> Self {
|
||||||
self.value = Some(val.to_owned());
|
self.value = Some(val.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_content(mut self, val: &str) -> Self {
|
||||||
|
self.content = Some(val.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -111,25 +141,29 @@ impl Html for Label {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
name: String,
|
name: Option<String>,
|
||||||
text: String,
|
label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Button {
|
impl Button {
|
||||||
pub fn new(name: &str, text: &str) -> Self {
|
pub fn new(label: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_owned(),
|
name: None,
|
||||||
text: text.to_owned(),
|
label: label.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Html for Button {
|
impl Html for Button {
|
||||||
fn to_html_string(&self) -> String {
|
fn to_html_string(&self) -> String {
|
||||||
|
let name = match self.name {
|
||||||
|
Some(ref name) => format!("name={}", name),
|
||||||
|
None => "".to_owned(),
|
||||||
|
};
|
||||||
format!(
|
format!(
|
||||||
"<button name={name}>{text}</button>",
|
"<button {name}>{label}</button>",
|
||||||
name = self.name,
|
name = name,
|
||||||
text = self.text
|
label = self.label
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,15 @@ use iron::prelude::*;
|
||||||
use iron::response::BodyReader;
|
use iron::response::BodyReader;
|
||||||
use iron::status;
|
use iron::status;
|
||||||
*/
|
*/
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
use http::status::StatusCode;
|
use http::status::StatusCode;
|
||||||
// use mustache::{compile_path, Template};
|
// use mustache::{compile_path, Template};
|
||||||
// use orizentic::{Permissions, ResourceName, Secret};
|
// use orizentic::{Permissions, ResourceName, Secret};
|
||||||
use build_html::Html;
|
use build_html::Html;
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
io::Read,
|
io::Read,
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
path::Path,
|
path::Path,
|
||||||
|
@ -254,21 +258,6 @@ pub async fn main() {
|
||||||
|
|
||||||
let mut router = Router::new();
|
let mut router = Router::new();
|
||||||
|
|
||||||
router.get(
|
|
||||||
"/:id",
|
|
||||||
files::GetFileHandler {
|
|
||||||
app: app.clone(),
|
|
||||||
template: compile_path("templates/file.html").expect("the template to compile"),
|
|
||||||
},
|
|
||||||
"get-file-page",
|
|
||||||
);
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
"/:id/raw",
|
|
||||||
files::GetHandler { app: app.clone() },
|
|
||||||
"get-file",
|
|
||||||
);
|
|
||||||
|
|
||||||
router.post("/", files::PostHandler { app: app.clone() }, "upload-file");
|
router.post("/", files::PostHandler { app: app.clone() }, "upload-file");
|
||||||
|
|
||||||
router.delete(
|
router.delete(
|
||||||
|
@ -301,13 +290,18 @@ pub async fn main() {
|
||||||
.await;
|
.await;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let app = Arc::new(RwLock::new(App::new(Path::new(
|
let app = Arc::new(RwLock::new(App::new(Path::new(
|
||||||
&std::env::var("FILE_SHARE_DIR").unwrap(),
|
&std::env::var("FILE_SHARE_DIR").unwrap(),
|
||||||
))));
|
))));
|
||||||
|
|
||||||
let root = warp::path!().map({
|
let log = warp::log("file_service");
|
||||||
|
|
||||||
|
let root = warp::path!().and(warp::get()).map({
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
move || {
|
move || {
|
||||||
|
info!("root handler");
|
||||||
warp::http::Response::builder()
|
warp::http::Response::builder()
|
||||||
.header("content-type", "text/html")
|
.header("content-type", "text/html")
|
||||||
.status(StatusCode::OK)
|
.status(StatusCode::OK)
|
||||||
|
@ -315,7 +309,20 @@ pub async fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let post_handler = warp::path!(String)
|
||||||
|
.and(warp::post())
|
||||||
|
.and(warp::filters::body::form())
|
||||||
|
.map(|id: String, form: HashMap<String, String>| {
|
||||||
|
info!("post_delete {}", id);
|
||||||
|
info!("form: {:?}", form);
|
||||||
|
warp::http::Response::builder()
|
||||||
|
.header("location", "/")
|
||||||
|
.status(StatusCode::SEE_OTHER)
|
||||||
|
.body(vec![])
|
||||||
|
});
|
||||||
|
|
||||||
let thumbnail = warp::path!(String / "tn")
|
let thumbnail = warp::path!(String / "tn")
|
||||||
|
.and(warp::get())
|
||||||
.and(warp::header::optional::<String>("if-none-match"))
|
.and(warp::header::optional::<String>("if-none-match"))
|
||||||
.map({
|
.map({
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
|
@ -332,6 +339,7 @@ pub async fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let file = warp::path!(String)
|
let file = warp::path!(String)
|
||||||
|
.and(warp::get())
|
||||||
.and(warp::header::optional::<String>("if-none-match"))
|
.and(warp::header::optional::<String>("if-none-match"))
|
||||||
.map({
|
.map({
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
|
@ -343,7 +351,24 @@ pub async fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let server = warp::serve(root.or(file).or(thumbnail));
|
let upload = warp::path!().and(warp::post()).map(|| {
|
||||||
|
println!("upload");
|
||||||
|
warp::reply()
|
||||||
|
});
|
||||||
|
|
||||||
|
let delete = warp::path!(String).and(warp::delete()).map(|id: String| {
|
||||||
|
println!("delete {}", id);
|
||||||
|
warp::reply()
|
||||||
|
});
|
||||||
|
|
||||||
|
let server = warp::serve(
|
||||||
|
root.or(post_handler)
|
||||||
|
.or(file)
|
||||||
|
.or(thumbnail)
|
||||||
|
.or(upload)
|
||||||
|
.or(delete)
|
||||||
|
.with(log),
|
||||||
|
);
|
||||||
server
|
server
|
||||||
.run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8002))
|
.run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8002))
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -11,30 +11,39 @@ pub fn index(files: Vec<Result<File, FileError>>) -> build_html::HtmlPage {
|
||||||
.with_encoding("multipart/form-data")
|
.with_encoding("multipart/form-data")
|
||||||
.with_container(
|
.with_container(
|
||||||
Container::new(ContainerType::Div)
|
Container::new(ContainerType::Div)
|
||||||
.with_html(Input::new("file", "file", "file-selector-input"))
|
.with_html(Input::new("file", "file"))
|
||||||
.with_html(Label::new("for-selector-input", "Select a file")),
|
.with_html(Label::new("for-selector-input", "Select a file")),
|
||||||
)
|
)
|
||||||
.with_html(Button::new("upload", "Upload file")),
|
.with_html(Button::new("Upload file")),
|
||||||
);
|
);
|
||||||
|
|
||||||
for file in files {
|
for file in files {
|
||||||
let mut container =
|
let container = match file {
|
||||||
Container::new(ContainerType::Div).with_attributes(vec![("class", "file")]);
|
Ok(ref file) => thumbnail(file).with_html(
|
||||||
match file {
|
Form::new()
|
||||||
Ok(file) => {
|
.with_path(&format!("/{}", file.info().id))
|
||||||
let tn = Container::new(ContainerType::Div)
|
.with_method("post")
|
||||||
.with_attributes(vec![("class", "thumbnail")])
|
.with_html(Input::new("hidden", "_method").with_value("delete"))
|
||||||
.with_link(
|
.with_html(Button::new("Delete")),
|
||||||
format!("/{}", file.info().id),
|
),
|
||||||
Image::new(&format!("{}/tn", file.info().id)).to_html_string(),
|
|
||||||
);
|
Err(err) => Container::new(ContainerType::Div)
|
||||||
container.add_html(tn);
|
.with_attributes(vec![("class", "file")])
|
||||||
}
|
.with_paragraph(format!("{:?}", err)),
|
||||||
Err(err) => {
|
};
|
||||||
container.add_paragraph(format!("{:?}", err));
|
page.add_container(container)
|
||||||
}
|
|
||||||
}
|
|
||||||
page.add_container(container);
|
|
||||||
}
|
}
|
||||||
page
|
page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn thumbnail(file: &File) -> Container {
|
||||||
|
let mut container = Container::new(ContainerType::Div).with_attributes(vec![("class", "file")]);
|
||||||
|
let tn = Container::new(ContainerType::Div)
|
||||||
|
.with_attributes(vec![("class", "thumbnail")])
|
||||||
|
.with_link(
|
||||||
|
format!("/{}", file.info().id),
|
||||||
|
Image::new(&format!("{}/tn", file.info().id)).to_html_string(),
|
||||||
|
);
|
||||||
|
container.add_html(tn);
|
||||||
|
container
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue