Skip to content

Commit

Permalink
Merge pull request #4 from daystram/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
daystram authored Jan 29, 2021
2 parents af104be + 82d6194 commit faa4495
Show file tree
Hide file tree
Showing 23 changed files with 945 additions and 98 deletions.
2 changes: 2 additions & 0 deletions cut-be/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ redis = "0.19.0"
r2d2 = "0.8.9"
r2d2_redis = "0.13.0"
rand = "0.8.2"
futures = "0.3.12"
actix-form-data = "0.5.0"
6 changes: 6 additions & 0 deletions cut-be/src/app/constants.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#![allow(dead_code)]

pub const VARIANT_SNIPPET: &str = "snippet";
pub const VARIANT_URL: &str = "url";
pub const VARIANT_FILE: &str = "file";

pub const MAX_SIZE_SNIPPET: usize = 5_000_000; // 5 MB
pub const MAX_SIZE_FILE: usize = 50_000_000; // 50 MB

pub const HASH_LENGTH: usize = 8;
Empty file.
1 change: 0 additions & 1 deletion cut-be/src/app/controllers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
pub mod middlewares;
pub mod v1;
66 changes: 60 additions & 6 deletions cut-be/src/app/controllers/v1/cut.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
use crate::app::{
constants,
datatransfers::{
auth::TokenInfo,
cut::{CreateResponse, Cut},
},
datatransfers::{auth::TokenInfo, cut::Cut, response::CreateResponse},
handlers, Module,
};
use crate::core::error::HandlerErrorKind;
use actix_form_data::Value;
use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder};

#[get("/{id}")]
pub async fn get_cut_raw(m: web::Data<Module>, req: HttpRequest) -> impl Responder {
let id: String = req.match_info().query("id").parse().unwrap();
match handlers::cut::get_one(m, id) {
match handlers::cut::get_one(m.clone(), id.clone()) {
Ok(cut) => match cut.variant.as_str() {
constants::VARIANT_SNIPPET => HttpResponse::Ok()
.header("Content-Type", "text/plain")
.body(cut.data),
constants::VARIANT_URL => HttpResponse::TemporaryRedirect()
.header("Location", cut.data)
.finish(),
constants::VARIANT_FILE => {
let file = match handlers::cut::get_file(m, id) {
Ok(file) => file,
Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)),
};
HttpResponse::Ok()
.header(
"Content-Disposition",
format!("attachment; filename=\"{}\"", file.name),
)
.header("Content-Type", file.mime)
.header("Content-Length", file.size)
.body(file.file)
}
_ => HttpResponse::NotFound().finish(),
},
Err(e) => match e.kind {
Expand All @@ -29,6 +41,24 @@ pub async fn get_cut_raw(m: web::Data<Module>, req: HttpRequest) -> impl Respond
}
}

#[get("/list")]
pub async fn get_cut_list(m: web::Data<Module>, req: HttpRequest) -> impl Responder {
let user: TokenInfo = match handlers::auth::authorize(&m, &req).await {
Ok(res) => res,
Err(e) => match e.kind {
HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(),
_ => return HttpResponse::InternalServerError().finish(),
},
};
match handlers::cut::get_list(m, user.sub) {
Ok(list) => HttpResponse::Ok().json(list),
Err(e) => match e.kind {
HandlerErrorKind::CutNotFoundError => HttpResponse::NotFound().finish(),
_ => HttpResponse::InternalServerError().body(format!("{:?}", e)),
},
}
}

#[get("/{id}")]
pub async fn get_cut(m: web::Data<Module>, req: HttpRequest) -> impl Responder {
let id: String = req.match_info().query("id").parse().unwrap();
Expand All @@ -48,7 +78,7 @@ pub async fn post_snippet_create(
req: HttpRequest,
) -> impl Responder {
let user: TokenInfo = match handlers::auth::authorize(&m, &req).await {
Ok(resp) => resp,
Ok(res) => res,
Err(e) => match e.kind {
HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(),
_ => return HttpResponse::InternalServerError().finish(),
Expand All @@ -68,3 +98,27 @@ pub async fn post_snippet_create(
Err(e) => HttpResponse::InternalServerError().body(format!("{:?}", e)),
}
}

#[post("")]
pub async fn post_file_upload(
m: web::Data<Module>,
form: Value,
req: HttpRequest,
) -> impl Responder {
let user: TokenInfo = match handlers::auth::authorize(&m, &req).await {
Ok(res) => res,
Err(e) => match e.kind {
HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(),
_ => return HttpResponse::InternalServerError().finish(),
},
};
let mut cut: Cut = match Cut::from_form(form) {
Ok(cut) => cut,
Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)),
};
cut.owner = user.sub;
match handlers::cut::insert(m, cut) {
Ok(hash) => HttpResponse::Ok().json(CreateResponse { hash: hash }),
Err(e) => HttpResponse::InternalServerError().body(format!("{:?}", e)),
}
}
181 changes: 131 additions & 50 deletions cut-be/src/app/datatransfers/cut.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use crate::core::error::{HandlerError, HandlerErrorKind};
use crate::{
app::constants,
core::error::{HandlerError, HandlerErrorKind},
};
use actix_form_data::Value;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Cut {
pub name: String,
#[serde(skip_deserializing)]
pub hash: String,
#[serde(skip)]
pub owner: String,
pub variant: String,
Expand All @@ -16,6 +21,8 @@ pub struct Cut {
pub created_at: u64,
#[serde(default = "Default::default")]
pub views: u64,
#[serde(skip)]
pub file: Vec<u8>,
}

fn current_time() -> u64 {
Expand All @@ -26,58 +33,132 @@ fn current_time() -> u64 {
}

impl Cut {
pub fn from_hashmap(res: HashMap<String, String>) -> Result<Self, HandlerError> {
pub fn from_form(form: Value) -> Result<Self, HandlerError> {
let mut cut = Cut {
name: Default::default(),
hash: Default::default(),
owner: Default::default(),
variant: constants::VARIANT_FILE.into(),
metadata: Default::default(),
data: Default::default(),
expiry: Default::default(),
created_at: current_time(),
views: Default::default(),
file: Default::default(),
};
match form {
Value::Map(mut hashmap) => {
match hashmap.remove("name") {
Some(value) => match value {
Value::Text(name) => cut.name = name,
_ => return Err(HandlerErrorKind::FormParseError.into()),
},
None => return Err(HandlerErrorKind::FormParseError.into()),
};
match hashmap.remove("expiry") {
Some(value) => match value {
Value::Int(expiry) => cut.expiry = expiry,
_ => return Err(HandlerErrorKind::FormParseError.into()),
},
None => return Err(HandlerErrorKind::FormParseError.into()),
};
match hashmap.remove("metadata") {
Some(value) => match value {
Value::Text(metadata) => cut.metadata = metadata,
_ => return Err(HandlerErrorKind::FormParseError.into()),
},
None => return Err(HandlerErrorKind::FormParseError.into()),
};
match hashmap.remove("data") {
Some(value) => match value {
Value::Text(data) => cut.data = data,
_ => return Err(HandlerErrorKind::FormParseError.into()),
},
None => return Err(HandlerErrorKind::FormParseError.into()),
};
match hashmap.remove("file") {
Some(value) => match value {
Value::Bytes(file) => cut.file = file.to_vec(),
_ => return Err(HandlerErrorKind::FormParseError.into()),
},
None => return Err(HandlerErrorKind::FormParseError.into()),
};
}
_ => return Err(HandlerErrorKind::FormParseError.into()),
};
Ok(cut)
}

pub fn from_hashmap(
res: std::collections::HashMap<std::string::String, Vec<u8>>,
) -> Result<Self, HandlerError> {
Ok(Cut {
name: res
.get("name")
.ok_or(HandlerErrorKind::RedisError)?
.to_string(),
owner: res
.get("owner")
.ok_or(HandlerErrorKind::RedisError)?
.to_string(),
variant: res
.get("variant")
.ok_or(HandlerErrorKind::RedisError)?
.to_string(),
metadata: res
.get("metadata")
.ok_or(HandlerErrorKind::RedisError)?
.to_string(),
data: res
.get("data")
.ok_or(HandlerErrorKind::RedisError)?
.to_string(),
expiry: res
.get("expiry")
.ok_or(HandlerErrorKind::RedisError)?
.parse()?,
created_at: res
.get("created_at")
.ok_or(HandlerErrorKind::RedisError)?
.parse()?,
views: res
.get("views")
.ok_or(HandlerErrorKind::RedisError)?
.parse()?,
name: String::from_utf8(
res.get("name")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?,
hash: String::from_utf8(
res.get("hash")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?,
owner: String::from_utf8(
res.get("owner")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?,
variant: String::from_utf8(
res.get("variant")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?,
metadata: String::from_utf8(
res.get("metadata")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?,
data: String::from_utf8(
res.get("data")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?,
expiry: String::from_utf8(
res.get("expiry")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?
.parse()?,
created_at: String::from_utf8(
res.get("created_at")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?
.parse()?,
views: String::from_utf8(
res.get("views")
.ok_or(HandlerErrorKind::RedisError)?
.to_vec(),
)?
.parse()?,
file: Default::default(),
})
}

pub fn to_array(&self) -> [(&str, String); 8] {
pub fn to_array(&self) -> [(&str, Vec<u8>); 9] {
return [
("name", self.name.clone()),
("owner", self.owner.clone()),
("variant", self.variant.clone()),
("metadata", self.metadata.clone()),
("data", self.data.clone()),
("expiry", self.expiry.to_string()),
("created_at", self.created_at.to_string()),
("views", self.views.to_string()),
("name", self.name.as_bytes().to_vec()),
("hash", self.hash.as_bytes().to_vec()),
("owner", self.owner.as_bytes().to_vec()),
("variant", self.variant.as_bytes().to_vec()),
("metadata", self.metadata.as_bytes().to_vec()),
("data", self.data.as_bytes().to_vec()),
("expiry", self.expiry.to_string().as_bytes().to_vec()),
(
"created_at",
self.created_at.to_string().as_bytes().to_vec(),
),
("views", self.views.to_string().as_bytes().to_vec()),
];
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CreateResponse {
pub hash: String,
}
Loading

0 comments on commit faa4495

Please sign in to comment.