From cc9f71833255fc3d0cf8daa2c68270e7d672948a Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 11:04:23 +1000 Subject: [PATCH 01/52] Added server initialization --- cut-be/.example.env | 4 +++ cut-be/.gitignore | 2 ++ cut-be/Cargo.toml | 3 ++ .../controllers/{.keep => middlewares/mod.rs} | 0 cut-be/src/app/controllers/mod.rs | 2 ++ cut-be/src/app/controllers/v1/mod.rs | 2 ++ cut-be/src/app/controllers/v1/ping.rs | 6 ++++ cut-be/src/app/controllers/v1/snippet.rs | 10 ++++++ cut-be/src/app/datatransfers/create.rs | 6 ++++ cut-be/src/app/datatransfers/mod.rs | 1 + .../{datatransfers/.keep => handlers/mod.rs} | 0 cut-be/src/app/middlewares/.keep | 0 cut-be/src/app/mod.rs | 31 +++++++++++++++++++ cut-be/src/app/router.rs | 14 +++++++++ cut-be/src/core/config.rs | 12 +++++++ cut-be/src/core/mod.rs | 1 + cut-be/src/main.rs | 28 +++-------------- cut-be/src/utils/.keep | 0 .../src/{app/handlers/.keep => utils/mod.rs} | 0 19 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 cut-be/.example.env rename cut-be/src/app/controllers/{.keep => middlewares/mod.rs} (100%) create mode 100644 cut-be/src/app/controllers/mod.rs create mode 100644 cut-be/src/app/controllers/v1/mod.rs create mode 100644 cut-be/src/app/controllers/v1/ping.rs create mode 100644 cut-be/src/app/controllers/v1/snippet.rs create mode 100644 cut-be/src/app/datatransfers/create.rs create mode 100644 cut-be/src/app/datatransfers/mod.rs rename cut-be/src/app/{datatransfers/.keep => handlers/mod.rs} (100%) delete mode 100644 cut-be/src/app/middlewares/.keep create mode 100644 cut-be/src/app/mod.rs create mode 100644 cut-be/src/app/router.rs create mode 100644 cut-be/src/core/mod.rs delete mode 100644 cut-be/src/utils/.keep rename cut-be/src/{app/handlers/.keep => utils/mod.rs} (100%) diff --git a/cut-be/.example.env b/cut-be/.example.env new file mode 100644 index 0000000..eed1777 --- /dev/null +++ b/cut-be/.example.env @@ -0,0 +1,4 @@ +HOST=localhost +PORT=9090 +ENVIRONMENT=development +CLIENT_SECRET=ratify_client_secret diff --git a/cut-be/.gitignore b/cut-be/.gitignore index c13cccd..175948b 100644 --- a/cut-be/.gitignore +++ b/cut-be/.gitignore @@ -1,6 +1,8 @@ # Created by https://www.toptal.com/developers/gitignore/api/rust,linux,macos,windows,intellij+all,visualstudiocode,vim # Edit at https://www.toptal.com/developers/gitignore?templates=rust,linux,macos,windows,intellij+all,visualstudiocode,vim +.env + ### Intellij+all ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 diff --git a/cut-be/Cargo.toml b/cut-be/Cargo.toml index b986da9..e176cb5 100644 --- a/cut-be/Cargo.toml +++ b/cut-be/Cargo.toml @@ -8,3 +8,6 @@ edition = "2018" [dependencies] actix-web = "3" +dotenv = "0.15.0" +env_logger = "0.8.2" +serde = "1.0.119" diff --git a/cut-be/src/app/controllers/.keep b/cut-be/src/app/controllers/middlewares/mod.rs similarity index 100% rename from cut-be/src/app/controllers/.keep rename to cut-be/src/app/controllers/middlewares/mod.rs diff --git a/cut-be/src/app/controllers/mod.rs b/cut-be/src/app/controllers/mod.rs new file mode 100644 index 0000000..b2b1158 --- /dev/null +++ b/cut-be/src/app/controllers/mod.rs @@ -0,0 +1,2 @@ +pub mod middlewares; +pub mod v1; diff --git a/cut-be/src/app/controllers/v1/mod.rs b/cut-be/src/app/controllers/v1/mod.rs new file mode 100644 index 0000000..1e24b00 --- /dev/null +++ b/cut-be/src/app/controllers/v1/mod.rs @@ -0,0 +1,2 @@ +pub mod ping; +pub mod snippet; diff --git a/cut-be/src/app/controllers/v1/ping.rs b/cut-be/src/app/controllers/v1/ping.rs new file mode 100644 index 0000000..21998a5 --- /dev/null +++ b/cut-be/src/app/controllers/v1/ping.rs @@ -0,0 +1,6 @@ +use actix_web::{web, HttpResponse, HttpRequest, Responder}; +use crate::app::Module; + +pub async fn get_ping(_: web::Data, _: HttpRequest) -> impl Responder { + HttpResponse::Ok().body("Pong!") +} diff --git a/cut-be/src/app/controllers/v1/snippet.rs b/cut-be/src/app/controllers/v1/snippet.rs new file mode 100644 index 0000000..7916cea --- /dev/null +++ b/cut-be/src/app/controllers/v1/snippet.rs @@ -0,0 +1,10 @@ +use actix_web::{web, HttpResponse, HttpRequest, Responder}; +use crate::app::Module; + +pub async fn get_snippet_list(m: web::Data, _req: HttpRequest) -> impl Responder { + HttpResponse::Ok().body(&m.config.client_secret) +} + +pub async fn post_snippet_create(_: web::Data, _req: HttpRequest) -> impl Responder { + HttpResponse::Ok().body("Pong!") +} diff --git a/cut-be/src/app/datatransfers/create.rs b/cut-be/src/app/datatransfers/create.rs new file mode 100644 index 0000000..f7c94a2 --- /dev/null +++ b/cut-be/src/app/datatransfers/create.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +struct CreateRequest { + name: String, +} diff --git a/cut-be/src/app/datatransfers/mod.rs b/cut-be/src/app/datatransfers/mod.rs new file mode 100644 index 0000000..c5fb369 --- /dev/null +++ b/cut-be/src/app/datatransfers/mod.rs @@ -0,0 +1 @@ +pub mod create; diff --git a/cut-be/src/app/datatransfers/.keep b/cut-be/src/app/handlers/mod.rs similarity index 100% rename from cut-be/src/app/datatransfers/.keep rename to cut-be/src/app/handlers/mod.rs diff --git a/cut-be/src/app/middlewares/.keep b/cut-be/src/app/middlewares/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/cut-be/src/app/mod.rs b/cut-be/src/app/mod.rs new file mode 100644 index 0000000..30f8d55 --- /dev/null +++ b/cut-be/src/app/mod.rs @@ -0,0 +1,31 @@ +use actix_web::{App, HttpServer}; +use crate::core; +use crate::AppConfig; + +pub mod controllers; +pub mod handlers; +pub mod router; + +#[derive(Clone)] +pub struct Module { + pub config: AppConfig, + pub rd: String, +} + +pub async fn start() -> std::io::Result<()> { + HttpServer::new(|| { + let config = core::config::init(); + let module = Module { + config: config.clone(), + rd: String::from(config.client_secret), + }; + App::new().data(module).configure(router::init) + }) + .bind(format!( + "{}:{}", + std::env::var("HOST").expect("HOST is required"), + std::env::var("PORT").expect("PORT is required") + ))? + .run() + .await +} diff --git a/cut-be/src/app/router.rs b/cut-be/src/app/router.rs new file mode 100644 index 0000000..59def64 --- /dev/null +++ b/cut-be/src/app/router.rs @@ -0,0 +1,14 @@ +use actix_web::web; +use crate::app::controllers::v1; + +pub fn init(app: &mut web::ServiceConfig) { + app.service( + web::scope("/api/v1") + .service(web::resource("ping").route(web::get().to(v1::ping::get_ping))) + .service( + web::resource("snippet") + .route(web::get().to(v1::snippet::get_snippet_list)) + .route(web::post().to(v1::snippet::post_snippet_create)), + ), + ); +} diff --git a/cut-be/src/core/config.rs b/cut-be/src/core/config.rs index e69de29..43e1c8f 100644 --- a/cut-be/src/core/config.rs +++ b/cut-be/src/core/config.rs @@ -0,0 +1,12 @@ +use std::env; + +#[derive(Clone)] +pub struct AppConfig { + pub client_secret: String, +} + +pub fn init() -> AppConfig { + return AppConfig { + client_secret: env::var("CLIENT_SECRET").expect("CLIENT_SECRET is required"), + }; +} diff --git a/cut-be/src/core/mod.rs b/cut-be/src/core/mod.rs new file mode 100644 index 0000000..ef68c36 --- /dev/null +++ b/cut-be/src/core/mod.rs @@ -0,0 +1 @@ +pub mod config; diff --git a/cut-be/src/main.rs b/cut-be/src/main.rs index 3b1ca80..27821a0 100644 --- a/cut-be/src/main.rs +++ b/cut-be/src/main.rs @@ -1,28 +1,10 @@ -use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder}; +use crate::core::config::AppConfig; -#[get("/")] -async fn hello() -> impl Responder { - HttpResponse::Ok().body("Hello world!") -} - -#[post("/echo")] -async fn echo(req_body: String) -> impl Responder { - HttpResponse::Ok().body(req_body) -} - -async fn manual_hello() -> impl Responder { - HttpResponse::Ok().body("Hey there!") -} +mod app; +mod core; #[actix_web::main] async fn main() -> std::io::Result<()> { - HttpServer::new(|| { - App::new() - .service(hello) - .service(echo) - .route("/hey", web::get().to(manual_hello)) - }) - .bind("0.0.0.0:9090")? - .run() - .await + dotenv::dotenv().ok(); + app::start().await } diff --git a/cut-be/src/utils/.keep b/cut-be/src/utils/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/cut-be/src/app/handlers/.keep b/cut-be/src/utils/mod.rs similarity index 100% rename from cut-be/src/app/handlers/.keep rename to cut-be/src/utils/mod.rs From 5cfdf107be85b1a5d034fd8df29e39001727e650 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 12:44:04 +1000 Subject: [PATCH 02/52] Added redis configs --- cut-be/.example.env | 2 ++ cut-be/src/core/config.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/cut-be/.example.env b/cut-be/.example.env index eed1777..b87fb74 100644 --- a/cut-be/.example.env +++ b/cut-be/.example.env @@ -2,3 +2,5 @@ HOST=localhost PORT=9090 ENVIRONMENT=development CLIENT_SECRET=ratify_client_secret +REDIS_HOST=localhost +REDIS_PORT=6379 \ No newline at end of file diff --git a/cut-be/src/core/config.rs b/cut-be/src/core/config.rs index 43e1c8f..196b40e 100644 --- a/cut-be/src/core/config.rs +++ b/cut-be/src/core/config.rs @@ -3,10 +3,14 @@ use std::env; #[derive(Clone)] pub struct AppConfig { pub client_secret: String, + pub redis_host: String, + pub redis_port: String, } pub fn init() -> AppConfig { return AppConfig { client_secret: env::var("CLIENT_SECRET").expect("CLIENT_SECRET is required"), + redis_host: env::var("REDIS_HOST").expect("REDIS_HOST is required"), + redis_port: env::var("REDIS_PORT").expect("REDIS_PORT is required"), }; } From 8f262bf36006662f81106ff849ffc318273f062f Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 12:45:28 +1000 Subject: [PATCH 03/52] Added logger --- cut-be/Cargo.toml | 1 + cut-be/src/app/mod.rs | 22 ++++++++++++---------- cut-be/src/main.rs | 5 +++++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/cut-be/Cargo.toml b/cut-be/Cargo.toml index e176cb5..892aa33 100644 --- a/cut-be/Cargo.toml +++ b/cut-be/Cargo.toml @@ -11,3 +11,4 @@ actix-web = "3" dotenv = "0.15.0" env_logger = "0.8.2" serde = "1.0.119" +log = "0.4.13" diff --git a/cut-be/src/app/mod.rs b/cut-be/src/app/mod.rs index 30f8d55..5d8cd97 100644 --- a/cut-be/src/app/mod.rs +++ b/cut-be/src/app/mod.rs @@ -1,25 +1,27 @@ -use actix_web::{App, HttpServer}; use crate::core; use crate::AppConfig; +use actix_web::{middleware::Logger, App, HttpServer}; pub mod controllers; pub mod handlers; pub mod router; -#[derive(Clone)] pub struct Module { pub config: AppConfig, - pub rd: String, } pub async fn start() -> std::io::Result<()> { - HttpServer::new(|| { - let config = core::config::init(); - let module = Module { - config: config.clone(), - rd: String::from(config.client_secret), - }; - App::new().data(module).configure(router::init) + // init AppConfig + let config = core::config::init(); + + // run server + HttpServer::new(move || { + App::new() + .data(Module { + config: config.clone(), + }) + .wrap(Logger::default()) + .configure(router::init) }) .bind(format!( "{}:{}", diff --git a/cut-be/src/main.rs b/cut-be/src/main.rs index 27821a0..fdcb40c 100644 --- a/cut-be/src/main.rs +++ b/cut-be/src/main.rs @@ -6,5 +6,10 @@ mod core; #[actix_web::main] async fn main() -> std::io::Result<()> { dotenv::dotenv().ok(); + if std::env::var("RUST_LOG").ok().is_none() { + std::env::set_var("RUST_LOG", "debug,actix_web=info"); + } + env_logger::init(); + app::start().await } From 5d7b6c1ccfdb95fb739c0759f84b4c11564c19fd Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 13:04:27 +1000 Subject: [PATCH 04/52] Added redis pool to module --- cut-be/Cargo.toml | 3 +++ cut-be/src/app/controllers/v1/ping.rs | 2 +- cut-be/src/app/controllers/v1/snippet.rs | 11 +++++++++-- cut-be/src/app/mod.rs | 20 ++++++++++++++++---- cut-be/src/app/router.rs | 2 +- cut-be/src/main.rs | 2 -- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/cut-be/Cargo.toml b/cut-be/Cargo.toml index 892aa33..12f8cab 100644 --- a/cut-be/Cargo.toml +++ b/cut-be/Cargo.toml @@ -12,3 +12,6 @@ dotenv = "0.15.0" env_logger = "0.8.2" serde = "1.0.119" log = "0.4.13" +redis = "0.19.0" +r2d2 = "0.8.9" +r2d2_redis = "0.13.0" diff --git a/cut-be/src/app/controllers/v1/ping.rs b/cut-be/src/app/controllers/v1/ping.rs index 21998a5..196ebca 100644 --- a/cut-be/src/app/controllers/v1/ping.rs +++ b/cut-be/src/app/controllers/v1/ping.rs @@ -1,5 +1,5 @@ -use actix_web::{web, HttpResponse, HttpRequest, Responder}; use crate::app::Module; +use actix_web::{web, HttpRequest, HttpResponse, Responder}; pub async fn get_ping(_: web::Data, _: HttpRequest) -> impl Responder { HttpResponse::Ok().body("Pong!") diff --git a/cut-be/src/app/controllers/v1/snippet.rs b/cut-be/src/app/controllers/v1/snippet.rs index 7916cea..ccabe07 100644 --- a/cut-be/src/app/controllers/v1/snippet.rs +++ b/cut-be/src/app/controllers/v1/snippet.rs @@ -1,8 +1,15 @@ -use actix_web::{web, HttpResponse, HttpRequest, Responder}; use crate::app::Module; +use actix_web::{web, HttpRequest, HttpResponse, Responder}; +use r2d2_redis::redis::Commands; pub async fn get_snippet_list(m: web::Data, _req: HttpRequest) -> impl Responder { - HttpResponse::Ok().body(&m.config.client_secret) + match &mut m.rd_pool.get() { + Ok(rd) => match rd.get::<&str, i64>("counter") { + Ok(result) => HttpResponse::Ok().body(format!("Counter: {}", result)), + Err(_) => HttpResponse::NotFound().finish(), + }, + Err(e) => HttpResponse::InternalServerError().body(format!("{}", e)), + } } pub async fn post_snippet_create(_: web::Data, _req: HttpRequest) -> impl Responder { diff --git a/cut-be/src/app/mod.rs b/cut-be/src/app/mod.rs index 5d8cd97..e997675 100644 --- a/cut-be/src/app/mod.rs +++ b/cut-be/src/app/mod.rs @@ -1,24 +1,36 @@ -use crate::core; -use crate::AppConfig; +use crate::core::config; use actix_web::{middleware::Logger, App, HttpServer}; +use r2d2::Pool; +use r2d2_redis::RedisConnectionManager; pub mod controllers; pub mod handlers; pub mod router; pub struct Module { - pub config: AppConfig, + pub config: config::AppConfig, + pub rd_pool: r2d2::Pool, } pub async fn start() -> std::io::Result<()> { // init AppConfig - let config = core::config::init(); + let config = config::init(); + + // init Redis + let rd_manager = RedisConnectionManager::new(format!( + "redis://{}:{}/", + config.redis_host, config.redis_port + )) + .unwrap(); + let rd_pool = Pool::builder().max_size(15).build(rd_manager).unwrap(); + log::info!("[INIT] Redis initialized!"); // run server HttpServer::new(move || { App::new() .data(Module { config: config.clone(), + rd_pool: rd_pool.clone(), }) .wrap(Logger::default()) .configure(router::init) diff --git a/cut-be/src/app/router.rs b/cut-be/src/app/router.rs index 59def64..b1b04fa 100644 --- a/cut-be/src/app/router.rs +++ b/cut-be/src/app/router.rs @@ -1,5 +1,5 @@ -use actix_web::web; use crate::app::controllers::v1; +use actix_web::web; pub fn init(app: &mut web::ServiceConfig) { app.service( diff --git a/cut-be/src/main.rs b/cut-be/src/main.rs index fdcb40c..da85b05 100644 --- a/cut-be/src/main.rs +++ b/cut-be/src/main.rs @@ -1,5 +1,3 @@ -use crate::core::config::AppConfig; - mod app; mod core; From 0252dac75dfef3f942602779ab1ab0e5425ca228 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 19:43:32 +1000 Subject: [PATCH 05/52] Cleaned up ping controller --- cut-be/src/app/controllers/v1/ping.rs | 5 ++--- cut-be/src/app/controllers/v1/snippet.rs | 16 ++++++++++------ cut-be/src/app/datatransfers/create.rs | 6 ------ 3 files changed, 12 insertions(+), 15 deletions(-) delete mode 100644 cut-be/src/app/datatransfers/create.rs diff --git a/cut-be/src/app/controllers/v1/ping.rs b/cut-be/src/app/controllers/v1/ping.rs index 196ebca..f3f4a7f 100644 --- a/cut-be/src/app/controllers/v1/ping.rs +++ b/cut-be/src/app/controllers/v1/ping.rs @@ -1,6 +1,5 @@ -use crate::app::Module; -use actix_web::{web, HttpRequest, HttpResponse, Responder}; +use actix_web::{HttpResponse, Responder}; -pub async fn get_ping(_: web::Data, _: HttpRequest) -> impl Responder { +pub async fn get_ping() -> impl Responder { HttpResponse::Ok().body("Pong!") } diff --git a/cut-be/src/app/controllers/v1/snippet.rs b/cut-be/src/app/controllers/v1/snippet.rs index ccabe07..24fbb24 100644 --- a/cut-be/src/app/controllers/v1/snippet.rs +++ b/cut-be/src/app/controllers/v1/snippet.rs @@ -1,14 +1,18 @@ +use crate::app::handlers; use crate::app::Module; +use crate::core::error::HandlerErrorKind; use actix_web::{web, HttpRequest, HttpResponse, Responder}; -use r2d2_redis::redis::Commands; pub async fn get_snippet_list(m: web::Data, _req: HttpRequest) -> impl Responder { - match &mut m.rd_pool.get() { - Ok(rd) => match rd.get::<&str, i64>("counter") { - Ok(result) => HttpResponse::Ok().body(format!("Counter: {}", result)), - Err(_) => HttpResponse::NotFound().finish(), + match handlers::snippet::get(m) { + Ok(Some(res)) => HttpResponse::Ok().body(format!("{}", res)), + Ok(None) => HttpResponse::Ok().body("Not found"), + Err(e) => match e.kind { + HandlerErrorKind::GeneralError => { + HttpResponse::InternalServerError().body(format!("{:?}", e)) + } + _ => HttpResponse::InternalServerError().body(format!("{:?}", e)), }, - Err(e) => HttpResponse::InternalServerError().body(format!("{}", e)), } } diff --git a/cut-be/src/app/datatransfers/create.rs b/cut-be/src/app/datatransfers/create.rs deleted file mode 100644 index f7c94a2..0000000 --- a/cut-be/src/app/datatransfers/create.rs +++ /dev/null @@ -1,6 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -struct CreateRequest { - name: String, -} From 44649b2166db1feaf6d2664959afe86735f7bfd9 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 19:44:58 +1000 Subject: [PATCH 06/52] Created handler errors --- cut-be/src/core/error.rs | 30 ++++++++++++++++++++++++++++++ cut-be/src/core/mod.rs | 1 + 2 files changed, 31 insertions(+) create mode 100644 cut-be/src/core/error.rs diff --git a/cut-be/src/core/error.rs b/cut-be/src/core/error.rs new file mode 100644 index 0000000..f446b37 --- /dev/null +++ b/cut-be/src/core/error.rs @@ -0,0 +1,30 @@ +#[derive(Debug, Copy, Clone)] +pub enum HandlerErrorKind { + SnippetNotFoundError, + RedisError, + GeneralError, +} + +#[derive(Debug)] +pub struct HandlerError { + pub kind: HandlerErrorKind, + pub message: String, +} + +impl From for HandlerError { + fn from(error: r2d2::Error) -> Self { + HandlerError { + kind: HandlerErrorKind::RedisError, + message: error.to_string(), + } + } +} + +impl From for HandlerError { + fn from(error: r2d2_redis::redis::RedisError) -> Self { + HandlerError { + kind: HandlerErrorKind::RedisError, + message: error.to_string(), + } + } +} diff --git a/cut-be/src/core/mod.rs b/cut-be/src/core/mod.rs index ef68c36..7404805 100644 --- a/cut-be/src/core/mod.rs +++ b/cut-be/src/core/mod.rs @@ -1 +1,2 @@ pub mod config; +pub mod error; From 7d478802529bfaa26bc6e25d2b5a1a9cc8e9bdd9 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sat, 16 Jan 2021 19:45:13 +1000 Subject: [PATCH 07/52] Implemented sample snipper handler --- cut-be/src/app/handlers/mod.rs | 1 + cut-be/src/app/handlers/snippet.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 cut-be/src/app/handlers/snippet.rs diff --git a/cut-be/src/app/handlers/mod.rs b/cut-be/src/app/handlers/mod.rs index e69de29..debfd99 100644 --- a/cut-be/src/app/handlers/mod.rs +++ b/cut-be/src/app/handlers/mod.rs @@ -0,0 +1 @@ +pub mod snippet; diff --git a/cut-be/src/app/handlers/snippet.rs b/cut-be/src/app/handlers/snippet.rs new file mode 100644 index 0000000..f1f4dd9 --- /dev/null +++ b/cut-be/src/app/handlers/snippet.rs @@ -0,0 +1,16 @@ +use crate::core::error::{HandlerError, HandlerErrorKind}; +use crate::app::Module; +use actix_web::web; +use r2d2_redis::redis::{Commands, ErrorKind}; + +pub fn get(m: web::Data) -> Result, HandlerError> { + let rd = &mut m.rd_pool.get()?; + match rd.get::<&str, String>("asd") { + Ok(res) => Ok(Some(res)), + Err(e) => match e.kind() { + ErrorKind::ClientError => Err(HandlerError{kind: HandlerErrorKind::GeneralError, message: format!("{:?}", e)}), + ErrorKind::AuthenticationFailed => Ok(Some("auth".into())), + _ => Err(e.into()), + }, + } +} From 65252867213e4b04803f0683afda7abdc5fc6664 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 02:51:05 +1000 Subject: [PATCH 08/52] Converted const to macros --- cut-be/src/app/constants.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 cut-be/src/app/constants.rs diff --git a/cut-be/src/app/constants.rs b/cut-be/src/app/constants.rs new file mode 100644 index 0000000..c39f8bb --- /dev/null +++ b/cut-be/src/app/constants.rs @@ -0,0 +1,13 @@ +#[macro_export] +macro_rules! RD_SNIPPET { + ($id: expr) => { + format!("snippet::{}", $id) + }; +} + +#[macro_export] +macro_rules! RD_URL { + ($id: expr) => { + format!("url::{}", $id) + }; +} From f3fd76d33825fd9f2327e47ea49432a6d4d58d6e Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 05:47:05 +1000 Subject: [PATCH 09/52] Added error impl from enum --- cut-be/src/core/error.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cut-be/src/core/error.rs b/cut-be/src/core/error.rs index f446b37..3df3efc 100644 --- a/cut-be/src/core/error.rs +++ b/cut-be/src/core/error.rs @@ -1,6 +1,6 @@ #[derive(Debug, Copy, Clone)] pub enum HandlerErrorKind { - SnippetNotFoundError, + CutNotFoundError, RedisError, GeneralError, } @@ -11,6 +11,21 @@ pub struct HandlerError { pub message: String, } +impl From for HandlerError { + fn from(error: HandlerErrorKind) -> Self { + match error { + HandlerErrorKind::CutNotFoundError => HandlerError { + kind: HandlerErrorKind::CutNotFoundError, + message: "cut not found".into(), + }, + _ => HandlerError { + kind: HandlerErrorKind::GeneralError, + message: format!("an error has occurred. {:?}", error), + }, + } + } +} + impl From for HandlerError { fn from(error: r2d2::Error) -> Self { HandlerError { From 3ba4fa65aae6f7dcfb7b8fe5fa90f478dc5480c2 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 05:51:50 +1000 Subject: [PATCH 10/52] Refactored controller structure --- cut-be/src/app/controllers/v1/mod.rs | 1 + cut-be/src/app/controllers/v1/ping.rs | 3 ++- cut-be/src/app/controllers/v1/snippet.rs | 29 +++++++++--------------- cut-be/src/app/router.rs | 9 +++----- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/cut-be/src/app/controllers/v1/mod.rs b/cut-be/src/app/controllers/v1/mod.rs index 1e24b00..c4fe1ba 100644 --- a/cut-be/src/app/controllers/v1/mod.rs +++ b/cut-be/src/app/controllers/v1/mod.rs @@ -1,2 +1,3 @@ +pub mod cut; pub mod ping; pub mod snippet; diff --git a/cut-be/src/app/controllers/v1/ping.rs b/cut-be/src/app/controllers/v1/ping.rs index f3f4a7f..b67f591 100644 --- a/cut-be/src/app/controllers/v1/ping.rs +++ b/cut-be/src/app/controllers/v1/ping.rs @@ -1,5 +1,6 @@ -use actix_web::{HttpResponse, Responder}; +use actix_web::{get, HttpResponse, Responder}; +#[get("")] pub async fn get_ping() -> impl Responder { HttpResponse::Ok().body("Pong!") } diff --git a/cut-be/src/app/controllers/v1/snippet.rs b/cut-be/src/app/controllers/v1/snippet.rs index 24fbb24..4f76a21 100644 --- a/cut-be/src/app/controllers/v1/snippet.rs +++ b/cut-be/src/app/controllers/v1/snippet.rs @@ -1,21 +1,14 @@ -use crate::app::handlers; -use crate::app::Module; -use crate::core::error::HandlerErrorKind; -use actix_web::{web, HttpRequest, HttpResponse, Responder}; +use crate::app::{datatransfers::cut::Cut, handlers, Module}; +use actix_web::{post, web, HttpRequest, HttpResponse, Responder}; -pub async fn get_snippet_list(m: web::Data, _req: HttpRequest) -> impl Responder { - match handlers::snippet::get(m) { - Ok(Some(res)) => HttpResponse::Ok().body(format!("{}", res)), - Ok(None) => HttpResponse::Ok().body("Not found"), - Err(e) => match e.kind { - HandlerErrorKind::GeneralError => { - HttpResponse::InternalServerError().body(format!("{:?}", e)) - } - _ => HttpResponse::InternalServerError().body(format!("{:?}", e)), - }, +#[post("")] +pub async fn post_snippet_create( + m: web::Data, + cut: web::Json, + _req: HttpRequest, +) -> impl Responder { + match handlers::snippet::insert(m, cut.0) { + Ok(res) => HttpResponse::Ok().body(format!("{}", res)), + Err(e) => HttpResponse::InternalServerError().body(format!("{:?}", e)), } } - -pub async fn post_snippet_create(_: web::Data, _req: HttpRequest) -> impl Responder { - HttpResponse::Ok().body("Pong!") -} diff --git a/cut-be/src/app/router.rs b/cut-be/src/app/router.rs index b1b04fa..6da5401 100644 --- a/cut-be/src/app/router.rs +++ b/cut-be/src/app/router.rs @@ -4,11 +4,8 @@ use actix_web::web; pub fn init(app: &mut web::ServiceConfig) { app.service( web::scope("/api/v1") - .service(web::resource("ping").route(web::get().to(v1::ping::get_ping))) - .service( - web::resource("snippet") - .route(web::get().to(v1::snippet::get_snippet_list)) - .route(web::post().to(v1::snippet::post_snippet_create)), - ), + .service(web::scope("/ping").service(v1::ping::get_ping)) + .service(web::scope("/cut").service(v1::cut::get_cut)) + .service(web::scope("/snippet").service(v1::snippet::post_snippet_create)), ); } From e8e93b84c017a2ae82a9c419ac526beb4dac9265 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 05:51:59 +1000 Subject: [PATCH 11/52] Implemented cut controller --- cut-be/src/app/controllers/v1/cut.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 cut-be/src/app/controllers/v1/cut.rs diff --git a/cut-be/src/app/controllers/v1/cut.rs b/cut-be/src/app/controllers/v1/cut.rs new file mode 100644 index 0000000..6ecd77b --- /dev/null +++ b/cut-be/src/app/controllers/v1/cut.rs @@ -0,0 +1,15 @@ +use crate::app::{handlers, Module}; +use crate::core::error::HandlerErrorKind; +use actix_web::{get, web, HttpRequest, HttpResponse, Responder}; + +#[get("/{id}")] +pub async fn get_cut(m: web::Data, req: HttpRequest) -> impl Responder { + let id: String = req.match_info().query("id").parse().unwrap(); + match handlers::snippet::get_one(m, id) { + Ok(res) => HttpResponse::Ok().json(res), + Err(e) => match e.kind { + HandlerErrorKind::CutNotFoundError => HttpResponse::NotFound().finish(), + _ => HttpResponse::InternalServerError().body(format!("{:?}", e)), + }, + } +} From c85b753a903a88fe749d466f2891509c5098ab97 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 05:53:12 +1000 Subject: [PATCH 12/52] Added cut frames --- cut-be/src/app/datatransfers/cut.rs | 10 ++++++++++ cut-be/src/app/datatransfers/mod.rs | 2 +- cut-be/src/app/mod.rs | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 cut-be/src/app/datatransfers/cut.rs diff --git a/cut-be/src/app/datatransfers/cut.rs b/cut-be/src/app/datatransfers/cut.rs new file mode 100644 index 0000000..30596f0 --- /dev/null +++ b/cut-be/src/app/datatransfers/cut.rs @@ -0,0 +1,10 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct Cut { + pub name: String, + pub variant: String, + pub metadata: String, + pub data: String, + pub created_at: i64, +} diff --git a/cut-be/src/app/datatransfers/mod.rs b/cut-be/src/app/datatransfers/mod.rs index c5fb369..66c48a3 100644 --- a/cut-be/src/app/datatransfers/mod.rs +++ b/cut-be/src/app/datatransfers/mod.rs @@ -1 +1 @@ -pub mod create; +pub mod cut; diff --git a/cut-be/src/app/mod.rs b/cut-be/src/app/mod.rs index e997675..958ec7a 100644 --- a/cut-be/src/app/mod.rs +++ b/cut-be/src/app/mod.rs @@ -3,7 +3,9 @@ use actix_web::{middleware::Logger, App, HttpServer}; use r2d2::Pool; use r2d2_redis::RedisConnectionManager; +pub mod constants; pub mod controllers; +pub mod datatransfers; pub mod handlers; pub mod router; From 90fecfbb9993b0cf38af3b79ee8fa0d2dff63f21 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 05:53:52 +1000 Subject: [PATCH 13/52] Replaced macro consts --- cut-be/src/app/constants.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/cut-be/src/app/constants.rs b/cut-be/src/app/constants.rs index c39f8bb..ecb10f0 100644 --- a/cut-be/src/app/constants.rs +++ b/cut-be/src/app/constants.rs @@ -1,13 +1,2 @@ -#[macro_export] -macro_rules! RD_SNIPPET { - ($id: expr) => { - format!("snippet::{}", $id) - }; -} - -#[macro_export] -macro_rules! RD_URL { - ($id: expr) => { - format!("url::{}", $id) - }; -} +pub const VARIANT_SNIPPET: &str = "snippet"; +pub const VARIANT_URL: &str = "url"; From 42a8752670d7be1ccc99d126eab279cfec1d0be2 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Sun, 17 Jan 2021 05:54:01 +1000 Subject: [PATCH 14/52] Implemented snippet handlers --- cut-be/src/app/handlers/snippet.rs | 46 +++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/cut-be/src/app/handlers/snippet.rs b/cut-be/src/app/handlers/snippet.rs index f1f4dd9..3eabc54 100644 --- a/cut-be/src/app/handlers/snippet.rs +++ b/cut-be/src/app/handlers/snippet.rs @@ -1,16 +1,42 @@ +use crate::app::{constants::VARIANT_SNIPPET, datatransfers::cut::Cut, Module}; use crate::core::error::{HandlerError, HandlerErrorKind}; -use crate::app::Module; use actix_web::web; -use r2d2_redis::redis::{Commands, ErrorKind}; +use r2d2_redis::redis::Commands; +use std::collections::HashMap; -pub fn get(m: web::Data) -> Result, HandlerError> { +pub fn get_one(m: web::Data, id: String) -> Result { let rd = &mut m.rd_pool.get()?; - match rd.get::<&str, String>("asd") { - Ok(res) => Ok(Some(res)), - Err(e) => match e.kind() { - ErrorKind::ClientError => Err(HandlerError{kind: HandlerErrorKind::GeneralError, message: format!("{:?}", e)}), - ErrorKind::AuthenticationFailed => Ok(Some("auth".into())), - _ => Err(e.into()), - }, + match rd.hgetall::>(id) { + Ok(res) => { + if res.is_empty() { + return Err(HandlerErrorKind::CutNotFoundError.into()); + } + Ok(Cut { + name: res.get("name").unwrap().to_string(), + variant: res.get("variant").unwrap().to_string(), + metadata: res.get("metadata").unwrap().to_string(), + data: res.get("data").unwrap().to_string(), + created_at: res.get("created_at").unwrap().parse().unwrap(), + }) + } + Err(e) => Err(e.into()), + } +} + +pub fn insert(m: web::Data, cut: Cut) -> Result { + let rd = &mut m.rd_pool.get()?; + let hash: String = "ID".into(); // TODO: generate random hash + match rd.hset_multiple::( + hash.clone(), + &[ + ("name", cut.name), + ("variant", VARIANT_SNIPPET.into()), + ("metadata", cut.metadata), + ("data", cut.data), + ("created_at", cut.created_at.to_string()), // TODO: user current time + ], + ) { + Ok(_) => Ok(hash), + Err(e) => Err(e.into()), } } From 1614db516881ff51c47fcd73884c0b7222fdc481 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 05:27:57 +1000 Subject: [PATCH 15/52] Added tokenInfo struct --- cut-be/src/app/datatransfers/auth.rs | 8 ++++++++ cut-be/src/app/datatransfers/mod.rs | 1 + 2 files changed, 9 insertions(+) create mode 100644 cut-be/src/app/datatransfers/auth.rs diff --git a/cut-be/src/app/datatransfers/auth.rs b/cut-be/src/app/datatransfers/auth.rs new file mode 100644 index 0000000..bb65bff --- /dev/null +++ b/cut-be/src/app/datatransfers/auth.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenInfo { + pub active: bool, + #[serde(default)] pub sub: String, + #[serde(default)] pub client_id: String, +} diff --git a/cut-be/src/app/datatransfers/mod.rs b/cut-be/src/app/datatransfers/mod.rs index 66c48a3..664488d 100644 --- a/cut-be/src/app/datatransfers/mod.rs +++ b/cut-be/src/app/datatransfers/mod.rs @@ -1 +1,2 @@ +pub mod auth; pub mod cut; From 666af16237fd6a2fbf154ca51f83653042eb8ba9 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 05:28:50 +1000 Subject: [PATCH 16/52] Added oauth configs --- cut-be/src/core/config.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cut-be/src/core/config.rs b/cut-be/src/core/config.rs index 196b40e..2a74497 100644 --- a/cut-be/src/core/config.rs +++ b/cut-be/src/core/config.rs @@ -2,6 +2,8 @@ use std::env; #[derive(Clone)] pub struct AppConfig { + pub oauth_issuer: String, + pub client_id: String, pub client_secret: String, pub redis_host: String, pub redis_port: String, @@ -9,6 +11,8 @@ pub struct AppConfig { pub fn init() -> AppConfig { return AppConfig { + oauth_issuer: env::var("OAUTH_ISSUER").expect("OAUTH_ISSUER is required"), + client_id: env::var("CLIENT_ID").expect("CLIENT_ID is required"), client_secret: env::var("CLIENT_SECRET").expect("CLIENT_SECRET is required"), redis_host: env::var("REDIS_HOST").expect("REDIS_HOST is required"), redis_port: env::var("REDIS_PORT").expect("REDIS_PORT is required"), From 648fd57b8133088a243b00a1cfd355b3ba449c7e Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 05:29:13 +1000 Subject: [PATCH 17/52] Implemented oauth retriever handler --- cut-be/src/app/handlers/auth.rs | 31 +++++++++++++++++++++++++++++++ cut-be/src/app/handlers/mod.rs | 1 + cut-be/src/core/error.rs | 20 ++++++++++++++++++++ cut-be/src/main.rs | 2 +- 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 cut-be/src/app/handlers/auth.rs diff --git a/cut-be/src/app/handlers/auth.rs b/cut-be/src/app/handlers/auth.rs new file mode 100644 index 0000000..ef80723 --- /dev/null +++ b/cut-be/src/app/handlers/auth.rs @@ -0,0 +1,31 @@ +use crate::app::{datatransfers::auth::TokenInfo, Module}; +use crate::core::error::{HandlerError, HandlerErrorKind}; +use actix_web::{client::Client, web, HttpRequest}; + +pub async fn authorize(m: &web::Data, req: &HttpRequest) -> Result { + let access_token: &str = match req.headers().get("Authorization") { + Some(header_value) => match header_value.to_str() { + Ok(access_token) => access_token.trim_start_matches("Bearer "), + Err(_) => return Err(HandlerErrorKind::GeneralError.into()), + }, + _ => return Err(HandlerErrorKind::UnauthorizedError.into()), + }; + match Client::default() + .post(format!("{}/oauth/introspect", m.config.oauth_issuer)) + .header("Content-Type", "application/x-www-form-urlencoded") + .send_body(format!( + "token={}&client_id={}&client_secret={}&token_type_hint=access_token", + access_token, m.config.client_id, m.config.client_secret + )) + .await + { + Ok(mut res) => match res.json::().await { + Ok(token_info) => match token_info.active { + true => Ok(token_info), + false => Err(HandlerErrorKind::UnauthorizedError.into()), + }, + Err(_) => Err(HandlerErrorKind::UnauthorizedError.into()), + }, + Err(_) => Err(HandlerErrorKind::GeneralError.into()), + } +} diff --git a/cut-be/src/app/handlers/mod.rs b/cut-be/src/app/handlers/mod.rs index debfd99..c510881 100644 --- a/cut-be/src/app/handlers/mod.rs +++ b/cut-be/src/app/handlers/mod.rs @@ -1 +1,2 @@ +pub mod auth; pub mod snippet; diff --git a/cut-be/src/core/error.rs b/cut-be/src/core/error.rs index 3df3efc..18f4971 100644 --- a/cut-be/src/core/error.rs +++ b/cut-be/src/core/error.rs @@ -1,5 +1,6 @@ #[derive(Debug, Copy, Clone)] pub enum HandlerErrorKind { + UnauthorizedError, CutNotFoundError, RedisError, GeneralError, @@ -14,6 +15,10 @@ pub struct HandlerError { impl From for HandlerError { fn from(error: HandlerErrorKind) -> Self { match error { + HandlerErrorKind::UnauthorizedError => HandlerError { + kind: HandlerErrorKind::UnauthorizedError, + message: "request unauthorized".into(), + }, HandlerErrorKind::CutNotFoundError => HandlerError { kind: HandlerErrorKind::CutNotFoundError, message: "cut not found".into(), @@ -43,3 +48,18 @@ impl From for HandlerError { } } } + +impl From for HandlerError { + fn from(error: reqwest::Error) -> Self { + HandlerError { + kind: HandlerErrorKind::UnauthorizedError, + message: error.to_string(), + } + } +} + impl std::fmt::Display for HandlerError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.message) + } + } + \ No newline at end of file diff --git a/cut-be/src/main.rs b/cut-be/src/main.rs index da85b05..133cd66 100644 --- a/cut-be/src/main.rs +++ b/cut-be/src/main.rs @@ -5,7 +5,7 @@ mod core; async fn main() -> std::io::Result<()> { dotenv::dotenv().ok(); if std::env::var("RUST_LOG").ok().is_none() { - std::env::set_var("RUST_LOG", "debug,actix_web=info"); + std::env::set_var("RUST_LOG", "info,actix_web=info"); } env_logger::init(); From dc02ce64617d9ef513ddf294a1e5f9358aaf4507 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 05:29:24 +1000 Subject: [PATCH 18/52] Added oauth layer --- cut-be/src/app/controllers/v1/cut.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cut-be/src/app/controllers/v1/cut.rs b/cut-be/src/app/controllers/v1/cut.rs index 6ecd77b..6b2f28a 100644 --- a/cut-be/src/app/controllers/v1/cut.rs +++ b/cut-be/src/app/controllers/v1/cut.rs @@ -4,6 +4,14 @@ use actix_web::{get, web, HttpRequest, HttpResponse, Responder}; #[get("/{id}")] pub async fn get_cut(m: web::Data, req: HttpRequest) -> impl Responder { + match handlers::auth::authorize(&m, &req).await { + Ok(resp) => resp, + Err(e) => match e.kind { + HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(), + _ => return HttpResponse::InternalServerError().finish(), + }, + }; + let id: String = req.match_info().query("id").parse().unwrap(); match handlers::snippet::get_one(m, id) { Ok(res) => HttpResponse::Ok().json(res), From 964833c226d2d03f6d8027f709e68ef7f92836ac Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 05:31:02 +1000 Subject: [PATCH 19/52] Added openssl for actix --- cut-be/.example.env | 3 +++ cut-be/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cut-be/.example.env b/cut-be/.example.env index b87fb74..c73c40e 100644 --- a/cut-be/.example.env +++ b/cut-be/.example.env @@ -1,6 +1,9 @@ HOST=localhost PORT=9090 ENVIRONMENT=development + +OAUTH_ISSUER=https://ratify.daystram.com CLIENT_SECRET=ratify_client_secret + REDIS_HOST=localhost REDIS_PORT=6379 \ No newline at end of file diff --git a/cut-be/Cargo.toml b/cut-be/Cargo.toml index 12f8cab..4cb500c 100644 --- a/cut-be/Cargo.toml +++ b/cut-be/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "3" +actix-web = { version = "3", features = ["openssl"] } dotenv = "0.15.0" env_logger = "0.8.2" serde = "1.0.119" From e3ecbd472d0671216b4a35a20644568e0b3a9b61 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 05:31:16 +1000 Subject: [PATCH 20/52] Removed reqwest error implementation --- cut-be/src/core/error.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/cut-be/src/core/error.rs b/cut-be/src/core/error.rs index 18f4971..ef673ce 100644 --- a/cut-be/src/core/error.rs +++ b/cut-be/src/core/error.rs @@ -48,18 +48,3 @@ impl From for HandlerError { } } } - -impl From for HandlerError { - fn from(error: reqwest::Error) -> Self { - HandlerError { - kind: HandlerErrorKind::UnauthorizedError, - message: error.to_string(), - } - } -} - impl std::fmt::Display for HandlerError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.message) - } - } - \ No newline at end of file From 95d2a705602bf8f11f5656403bb8f238977bad86 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 07:47:53 +1000 Subject: [PATCH 21/52] Added hash generator util --- cut-be/src/main.rs | 1 + cut-be/src/utils/hash.rs | 10 ++++++++++ cut-be/src/utils/mod.rs | 1 + 3 files changed, 12 insertions(+) create mode 100644 cut-be/src/utils/hash.rs diff --git a/cut-be/src/main.rs b/cut-be/src/main.rs index 133cd66..726350c 100644 --- a/cut-be/src/main.rs +++ b/cut-be/src/main.rs @@ -1,5 +1,6 @@ mod app; mod core; +mod utils; #[actix_web::main] async fn main() -> std::io::Result<()> { diff --git a/cut-be/src/utils/hash.rs b/cut-be/src/utils/hash.rs new file mode 100644 index 0000000..130be61 --- /dev/null +++ b/cut-be/src/utils/hash.rs @@ -0,0 +1,10 @@ +use rand::distributions::Alphanumeric; +use rand::{thread_rng, Rng}; + +pub fn generate(length: usize) -> String { + thread_rng() + .sample_iter(&Alphanumeric) + .take(length) + .map(char::from) + .collect() +} diff --git a/cut-be/src/utils/mod.rs b/cut-be/src/utils/mod.rs index e69de29..ec5d33c 100644 --- a/cut-be/src/utils/mod.rs +++ b/cut-be/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod hash; From 9a37b683533fa0cb647ea23ab163788cb7b9b048 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 07:48:17 +1000 Subject: [PATCH 22/52] Added response frames --- cut-be/src/app/datatransfers/auth.rs | 6 ++++-- cut-be/src/app/datatransfers/cut.rs | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cut-be/src/app/datatransfers/auth.rs b/cut-be/src/app/datatransfers/auth.rs index bb65bff..e5ca16d 100644 --- a/cut-be/src/app/datatransfers/auth.rs +++ b/cut-be/src/app/datatransfers/auth.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct TokenInfo { pub active: bool, - #[serde(default)] pub sub: String, - #[serde(default)] pub client_id: String, + #[serde(default)] + pub sub: String, + #[serde(default)] + pub client_id: String, } diff --git a/cut-be/src/app/datatransfers/cut.rs b/cut-be/src/app/datatransfers/cut.rs index 30596f0..39fa132 100644 --- a/cut-be/src/app/datatransfers/cut.rs +++ b/cut-be/src/app/datatransfers/cut.rs @@ -1,10 +1,18 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct Cut { pub name: String, + #[serde(skip)] + pub owner: String, + #[serde(skip_deserializing)] pub variant: String, pub metadata: String, pub data: String, pub created_at: i64, } + +#[derive(Debug, Serialize, Deserialize)] +pub struct CreateResponse { + pub hash: String, +} From dee2f329bac3e456d853db889901343d579d94b0 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 07:48:42 +1000 Subject: [PATCH 23/52] Fixed bearer token parsing --- cut-be/src/app/handlers/auth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cut-be/src/app/handlers/auth.rs b/cut-be/src/app/handlers/auth.rs index ef80723..0d55e64 100644 --- a/cut-be/src/app/handlers/auth.rs +++ b/cut-be/src/app/handlers/auth.rs @@ -5,7 +5,7 @@ use actix_web::{client::Client, web, HttpRequest}; pub async fn authorize(m: &web::Data, req: &HttpRequest) -> Result { let access_token: &str = match req.headers().get("Authorization") { Some(header_value) => match header_value.to_str() { - Ok(access_token) => access_token.trim_start_matches("Bearer "), + Ok(access_token) => access_token.strip_prefix("Bearer ").unwrap_or_else(|| access_token), Err(_) => return Err(HandlerErrorKind::GeneralError.into()), }, _ => return Err(HandlerErrorKind::UnauthorizedError.into()), From 503c61879c022741feaa6316a2aa07dd11d6ee0c Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 07:49:44 +1000 Subject: [PATCH 24/52] Added snippet create handler --- cut-be/src/app/constants.rs | 2 ++ cut-be/src/app/controllers/v1/snippet.rs | 23 ++++++++++--- cut-be/src/app/handlers/cut.rs | 43 ++++++++++++++++++++++++ cut-be/src/app/handlers/mod.rs | 1 + cut-be/src/app/handlers/snippet.rs | 38 ++++++++------------- cut-be/src/core/error.rs | 9 +++++ 6 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 cut-be/src/app/handlers/cut.rs diff --git a/cut-be/src/app/constants.rs b/cut-be/src/app/constants.rs index ecb10f0..89b556d 100644 --- a/cut-be/src/app/constants.rs +++ b/cut-be/src/app/constants.rs @@ -1,2 +1,4 @@ pub const VARIANT_SNIPPET: &str = "snippet"; pub const VARIANT_URL: &str = "url"; + +pub const HASH_LENGTH: usize = 8; diff --git a/cut-be/src/app/controllers/v1/snippet.rs b/cut-be/src/app/controllers/v1/snippet.rs index 4f76a21..d0afa74 100644 --- a/cut-be/src/app/controllers/v1/snippet.rs +++ b/cut-be/src/app/controllers/v1/snippet.rs @@ -1,14 +1,29 @@ -use crate::app::{datatransfers::cut::Cut, handlers, Module}; +use crate::app::{ + datatransfers::{ + auth::TokenInfo, + cut::{CreateResponse, Cut}, + }, + handlers, Module, +}; +use crate::core::error::HandlerErrorKind; use actix_web::{post, web, HttpRequest, HttpResponse, Responder}; #[post("")] pub async fn post_snippet_create( m: web::Data, cut: web::Json, - _req: HttpRequest, + req: HttpRequest, ) -> impl Responder { - match handlers::snippet::insert(m, cut.0) { - Ok(res) => HttpResponse::Ok().body(format!("{}", res)), + let user: TokenInfo = match handlers::auth::authorize(&m, &req).await { + Ok(resp) => resp, + Err(e) => match e.kind { + HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(), + _ => return HttpResponse::InternalServerError().finish(), + }, + }; + + match handlers::snippet::insert(m, user.sub, cut.0) { + Ok(hash) => HttpResponse::Ok().json(CreateResponse { hash: hash }), Err(e) => HttpResponse::InternalServerError().body(format!("{:?}", e)), } } diff --git a/cut-be/src/app/handlers/cut.rs b/cut-be/src/app/handlers/cut.rs new file mode 100644 index 0000000..9768527 --- /dev/null +++ b/cut-be/src/app/handlers/cut.rs @@ -0,0 +1,43 @@ +use crate::app::{datatransfers::cut::Cut, Module}; +use crate::core::error::{HandlerError, HandlerErrorKind}; +use actix_web::web; +use r2d2_redis::redis::Commands; +use std::collections::HashMap; + +pub fn get_one(m: web::Data, id: String) -> Result { + let rd = &mut m.rd_pool.get()?; + match rd.hgetall::>(id) { + Ok(res) => { + if res.is_empty() { + return Err(HandlerErrorKind::CutNotFoundError.into()); + } + Ok(Cut { + name: res + .get("name") + .ok_or(HandlerErrorKind::CutNotFoundError)? + .to_string(), + owner: res + .get("owner") + .ok_or(HandlerErrorKind::CutNotFoundError)? + .to_string(), + variant: res + .get("variant") + .ok_or(HandlerErrorKind::CutNotFoundError)? + .to_string(), + metadata: res + .get("metadata") + .ok_or(HandlerErrorKind::CutNotFoundError)? + .to_string(), + data: res + .get("data") + .ok_or(HandlerErrorKind::CutNotFoundError)? + .to_string(), + created_at: res + .get("created_at") + .ok_or(HandlerErrorKind::CutNotFoundError)? + .parse()?, + }) + } + Err(e) => Err(e.into()), + } +} diff --git a/cut-be/src/app/handlers/mod.rs b/cut-be/src/app/handlers/mod.rs index c510881..5e04588 100644 --- a/cut-be/src/app/handlers/mod.rs +++ b/cut-be/src/app/handlers/mod.rs @@ -1,2 +1,3 @@ pub mod auth; +pub mod cut; pub mod snippet; diff --git a/cut-be/src/app/handlers/snippet.rs b/cut-be/src/app/handlers/snippet.rs index 3eabc54..a7ea07b 100644 --- a/cut-be/src/app/handlers/snippet.rs +++ b/cut-be/src/app/handlers/snippet.rs @@ -1,35 +1,25 @@ -use crate::app::{constants::VARIANT_SNIPPET, datatransfers::cut::Cut, Module}; -use crate::core::error::{HandlerError, HandlerErrorKind}; +use crate::app::{ + constants::{HASH_LENGTH, VARIANT_SNIPPET}, + datatransfers::cut::Cut, + Module, +}; +use crate::core::error::{HandlerError}; +use crate::utils::hash; use actix_web::web; use r2d2_redis::redis::Commands; -use std::collections::HashMap; -pub fn get_one(m: web::Data, id: String) -> Result { +pub fn insert( + m: web::Data, + user_subject: String, + cut: Cut, +) -> Result { let rd = &mut m.rd_pool.get()?; - match rd.hgetall::>(id) { - Ok(res) => { - if res.is_empty() { - return Err(HandlerErrorKind::CutNotFoundError.into()); - } - Ok(Cut { - name: res.get("name").unwrap().to_string(), - variant: res.get("variant").unwrap().to_string(), - metadata: res.get("metadata").unwrap().to_string(), - data: res.get("data").unwrap().to_string(), - created_at: res.get("created_at").unwrap().parse().unwrap(), - }) - } - Err(e) => Err(e.into()), - } -} - -pub fn insert(m: web::Data, cut: Cut) -> Result { - let rd = &mut m.rd_pool.get()?; - let hash: String = "ID".into(); // TODO: generate random hash + let hash: String = hash::generate(HASH_LENGTH).into(); // TODO: generate random hash match rd.hset_multiple::( hash.clone(), &[ ("name", cut.name), + ("owner", user_subject), ("variant", VARIANT_SNIPPET.into()), ("metadata", cut.metadata), ("data", cut.data), diff --git a/cut-be/src/core/error.rs b/cut-be/src/core/error.rs index ef673ce..6d20656 100644 --- a/cut-be/src/core/error.rs +++ b/cut-be/src/core/error.rs @@ -31,6 +31,15 @@ impl From for HandlerError { } } +impl From for HandlerError { + fn from(error: std::num::ParseIntError) -> Self { + HandlerError { + kind: HandlerErrorKind::GeneralError, + message: error.to_string(), + } + } +} + impl From for HandlerError { fn from(error: r2d2::Error) -> Self { HandlerError { From d8170a9e6a8c80fba5224742ecc732356b64860d Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 07:50:04 +1000 Subject: [PATCH 25/52] Updated controllers --- cut-be/Cargo.toml | 1 + cut-be/src/app/controllers/v1/cut.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cut-be/Cargo.toml b/cut-be/Cargo.toml index 4cb500c..7a5dcd1 100644 --- a/cut-be/Cargo.toml +++ b/cut-be/Cargo.toml @@ -15,3 +15,4 @@ log = "0.4.13" redis = "0.19.0" r2d2 = "0.8.9" r2d2_redis = "0.13.0" +rand = "0.8.2" diff --git a/cut-be/src/app/controllers/v1/cut.rs b/cut-be/src/app/controllers/v1/cut.rs index 6b2f28a..3820992 100644 --- a/cut-be/src/app/controllers/v1/cut.rs +++ b/cut-be/src/app/controllers/v1/cut.rs @@ -13,7 +13,7 @@ pub async fn get_cut(m: web::Data, req: HttpRequest) -> impl Responder { }; let id: String = req.match_info().query("id").parse().unwrap(); - match handlers::snippet::get_one(m, id) { + match handlers::cut::get_one(m, id) { Ok(res) => HttpResponse::Ok().json(res), Err(e) => match e.kind { HandlerErrorKind::CutNotFoundError => HttpResponse::NotFound().finish(), From 907e958d38b2697a4033b6bc75851e11367cb0ed Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 08:01:28 +1000 Subject: [PATCH 26/52] Added creation time --- cut-be/src/app/datatransfers/cut.rs | 3 ++- cut-be/src/app/handlers/snippet.rs | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cut-be/src/app/datatransfers/cut.rs b/cut-be/src/app/datatransfers/cut.rs index 39fa132..b49b6d6 100644 --- a/cut-be/src/app/datatransfers/cut.rs +++ b/cut-be/src/app/datatransfers/cut.rs @@ -9,7 +9,8 @@ pub struct Cut { pub variant: String, pub metadata: String, pub data: String, - pub created_at: i64, + #[serde(skip_deserializing)] + pub created_at: u64, } #[derive(Debug, Serialize, Deserialize)] diff --git a/cut-be/src/app/handlers/snippet.rs b/cut-be/src/app/handlers/snippet.rs index a7ea07b..de5385f 100644 --- a/cut-be/src/app/handlers/snippet.rs +++ b/cut-be/src/app/handlers/snippet.rs @@ -3,10 +3,11 @@ use crate::app::{ datatransfers::cut::Cut, Module, }; -use crate::core::error::{HandlerError}; +use crate::core::error::{HandlerError, HandlerErrorKind}; use crate::utils::hash; use actix_web::web; use r2d2_redis::redis::Commands; +use std::time::{SystemTime, UNIX_EPOCH}; pub fn insert( m: web::Data, @@ -14,7 +15,11 @@ pub fn insert( cut: Cut, ) -> Result { let rd = &mut m.rd_pool.get()?; - let hash: String = hash::generate(HASH_LENGTH).into(); // TODO: generate random hash + let hash: String = hash::generate(HASH_LENGTH).into(); + let created_at = match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(duration) => duration.as_secs(), + Err(_) => return Err(HandlerErrorKind::GeneralError.into()), + }; match rd.hset_multiple::( hash.clone(), &[ @@ -23,7 +28,7 @@ pub fn insert( ("variant", VARIANT_SNIPPET.into()), ("metadata", cut.metadata), ("data", cut.data), - ("created_at", cut.created_at.to_string()), // TODO: user current time + ("created_at", created_at.to_string()), ], ) { Ok(_) => Ok(hash), From 340475e632d39481ee9c6d867dc340e576241c74 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 09:08:35 +1000 Subject: [PATCH 27/52] Refactored controller structure --- cut-be/src/app/controllers/v1/cut.rs | 45 ++++++++++++++++++------ cut-be/src/app/controllers/v1/mod.rs | 1 - cut-be/src/app/controllers/v1/snippet.rs | 29 --------------- cut-be/src/app/datatransfers/cut.rs | 1 - cut-be/src/app/handlers/cut.rs | 35 ++++++++++++++++-- cut-be/src/app/handlers/mod.rs | 1 - cut-be/src/app/handlers/snippet.rs | 37 ------------------- cut-be/src/app/router.rs | 7 ++-- 8 files changed, 72 insertions(+), 84 deletions(-) delete mode 100644 cut-be/src/app/controllers/v1/snippet.rs delete mode 100644 cut-be/src/app/handlers/snippet.rs diff --git a/cut-be/src/app/controllers/v1/cut.rs b/cut-be/src/app/controllers/v1/cut.rs index 3820992..ea84986 100644 --- a/cut-be/src/app/controllers/v1/cut.rs +++ b/cut-be/src/app/controllers/v1/cut.rs @@ -1,23 +1,46 @@ -use crate::app::{handlers, Module}; +use crate::app::{ + constants, + datatransfers::{ + auth::TokenInfo, + cut::{CreateResponse, Cut}, + }, + handlers, Module, +}; use crate::core::error::HandlerErrorKind; -use actix_web::{get, web, HttpRequest, HttpResponse, Responder}; +use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder}; #[get("/{id}")] pub async fn get_cut(m: web::Data, req: HttpRequest) -> impl Responder { - match handlers::auth::authorize(&m, &req).await { - Ok(resp) => resp, - Err(e) => match e.kind { - HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(), - _ => return HttpResponse::InternalServerError().finish(), - }, - }; - let id: String = req.match_info().query("id").parse().unwrap(); match handlers::cut::get_one(m, id) { - Ok(res) => HttpResponse::Ok().json(res), + Ok(cut) => HttpResponse::Ok().json(cut), Err(e) => match e.kind { HandlerErrorKind::CutNotFoundError => HttpResponse::NotFound().finish(), _ => HttpResponse::InternalServerError().body(format!("{:?}", e)), }, } } + +#[post("")] +pub async fn post_snippet_create( + m: web::Data, + cut: web::Json, + req: HttpRequest, +) -> impl Responder { + let user: TokenInfo = match handlers::auth::authorize(&m, &req).await { + Ok(resp) => resp, + Err(e) => match e.kind { + HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(), + _ => return HttpResponse::InternalServerError().finish(), + }, + }; + match cut.variant.as_str() { + constants::VARIANT_SNIPPET => (), + constants::VARIANT_URL => (), + _ => return HttpResponse::BadRequest().finish(), + }; + match handlers::cut::insert(m, user.sub, cut.0) { + Ok(hash) => HttpResponse::Ok().json(CreateResponse { hash: hash }), + Err(e) => HttpResponse::InternalServerError().body(format!("{:?}", e)), + } +} diff --git a/cut-be/src/app/controllers/v1/mod.rs b/cut-be/src/app/controllers/v1/mod.rs index c4fe1ba..7907e7f 100644 --- a/cut-be/src/app/controllers/v1/mod.rs +++ b/cut-be/src/app/controllers/v1/mod.rs @@ -1,3 +1,2 @@ pub mod cut; pub mod ping; -pub mod snippet; diff --git a/cut-be/src/app/controllers/v1/snippet.rs b/cut-be/src/app/controllers/v1/snippet.rs deleted file mode 100644 index d0afa74..0000000 --- a/cut-be/src/app/controllers/v1/snippet.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::app::{ - datatransfers::{ - auth::TokenInfo, - cut::{CreateResponse, Cut}, - }, - handlers, Module, -}; -use crate::core::error::HandlerErrorKind; -use actix_web::{post, web, HttpRequest, HttpResponse, Responder}; - -#[post("")] -pub async fn post_snippet_create( - m: web::Data, - cut: web::Json, - req: HttpRequest, -) -> impl Responder { - let user: TokenInfo = match handlers::auth::authorize(&m, &req).await { - Ok(resp) => resp, - Err(e) => match e.kind { - HandlerErrorKind::UnauthorizedError => return HttpResponse::Unauthorized().finish(), - _ => return HttpResponse::InternalServerError().finish(), - }, - }; - - match handlers::snippet::insert(m, user.sub, cut.0) { - Ok(hash) => HttpResponse::Ok().json(CreateResponse { hash: hash }), - Err(e) => HttpResponse::InternalServerError().body(format!("{:?}", e)), - } -} diff --git a/cut-be/src/app/datatransfers/cut.rs b/cut-be/src/app/datatransfers/cut.rs index b49b6d6..b69edd6 100644 --- a/cut-be/src/app/datatransfers/cut.rs +++ b/cut-be/src/app/datatransfers/cut.rs @@ -5,7 +5,6 @@ pub struct Cut { pub name: String, #[serde(skip)] pub owner: String, - #[serde(skip_deserializing)] pub variant: String, pub metadata: String, pub data: String, diff --git a/cut-be/src/app/handlers/cut.rs b/cut-be/src/app/handlers/cut.rs index 9768527..aad82f0 100644 --- a/cut-be/src/app/handlers/cut.rs +++ b/cut-be/src/app/handlers/cut.rs @@ -1,8 +1,12 @@ -use crate::app::{datatransfers::cut::Cut, Module}; +use crate::app::{constants::HASH_LENGTH, datatransfers::cut::Cut, Module}; use crate::core::error::{HandlerError, HandlerErrorKind}; +use crate::utils::hash; use actix_web::web; use r2d2_redis::redis::Commands; -use std::collections::HashMap; +use std::{ + collections::HashMap, + time::{SystemTime, UNIX_EPOCH}, +}; pub fn get_one(m: web::Data, id: String) -> Result { let rd = &mut m.rd_pool.get()?; @@ -41,3 +45,30 @@ pub fn get_one(m: web::Data, id: String) -> Result { Err(e) => Err(e.into()), } } + +pub fn insert( + m: web::Data, + user_subject: String, + cut: Cut, +) -> Result { + let rd = &mut m.rd_pool.get()?; + let hash: String = hash::generate(HASH_LENGTH).into(); + let created_at = match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(duration) => duration.as_secs(), + Err(_) => return Err(HandlerErrorKind::GeneralError.into()), + }; + match rd.hset_multiple::( + hash.clone(), + &[ + ("name", cut.name), + ("owner", user_subject), + ("variant", cut.variant), + ("metadata", cut.metadata), + ("data", cut.data), + ("created_at", created_at.to_string()), + ], + ) { + Ok(_) => Ok(hash), + Err(e) => Err(e.into()), + } +} diff --git a/cut-be/src/app/handlers/mod.rs b/cut-be/src/app/handlers/mod.rs index 5e04588..664488d 100644 --- a/cut-be/src/app/handlers/mod.rs +++ b/cut-be/src/app/handlers/mod.rs @@ -1,3 +1,2 @@ pub mod auth; pub mod cut; -pub mod snippet; diff --git a/cut-be/src/app/handlers/snippet.rs b/cut-be/src/app/handlers/snippet.rs deleted file mode 100644 index de5385f..0000000 --- a/cut-be/src/app/handlers/snippet.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::app::{ - constants::{HASH_LENGTH, VARIANT_SNIPPET}, - datatransfers::cut::Cut, - Module, -}; -use crate::core::error::{HandlerError, HandlerErrorKind}; -use crate::utils::hash; -use actix_web::web; -use r2d2_redis::redis::Commands; -use std::time::{SystemTime, UNIX_EPOCH}; - -pub fn insert( - m: web::Data, - user_subject: String, - cut: Cut, -) -> Result { - let rd = &mut m.rd_pool.get()?; - let hash: String = hash::generate(HASH_LENGTH).into(); - let created_at = match SystemTime::now().duration_since(UNIX_EPOCH) { - Ok(duration) => duration.as_secs(), - Err(_) => return Err(HandlerErrorKind::GeneralError.into()), - }; - match rd.hset_multiple::( - hash.clone(), - &[ - ("name", cut.name), - ("owner", user_subject), - ("variant", VARIANT_SNIPPET.into()), - ("metadata", cut.metadata), - ("data", cut.data), - ("created_at", created_at.to_string()), - ], - ) { - Ok(_) => Ok(hash), - Err(e) => Err(e.into()), - } -} diff --git a/cut-be/src/app/router.rs b/cut-be/src/app/router.rs index 6da5401..9996294 100644 --- a/cut-be/src/app/router.rs +++ b/cut-be/src/app/router.rs @@ -5,7 +5,10 @@ pub fn init(app: &mut web::ServiceConfig) { app.service( web::scope("/api/v1") .service(web::scope("/ping").service(v1::ping::get_ping)) - .service(web::scope("/cut").service(v1::cut::get_cut)) - .service(web::scope("/snippet").service(v1::snippet::post_snippet_create)), + .service( + web::scope("/cut") + .service(v1::cut::get_cut) + .service(v1::cut::post_snippet_create), + ), ); } From f58f74f58cd7375a084984d0ab50f8a6983c59c9 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Mon, 18 Jan 2021 09:15:24 +1000 Subject: [PATCH 28/52] Added raw controllers --- cut-be/src/app/controllers/v1/cut.rs | 18 ++++++++++++++++++ cut-be/src/app/router.rs | 19 ++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/cut-be/src/app/controllers/v1/cut.rs b/cut-be/src/app/controllers/v1/cut.rs index ea84986..bb70413 100644 --- a/cut-be/src/app/controllers/v1/cut.rs +++ b/cut-be/src/app/controllers/v1/cut.rs @@ -9,6 +9,24 @@ use crate::app::{ use crate::core::error::HandlerErrorKind; use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder}; +#[get("/{id}")] +pub async fn get_cut_raw(m: web::Data, req: HttpRequest) -> impl Responder { + let id: String = req.match_info().query("id").parse().unwrap(); + match handlers::cut::get_one(m, id) { + Ok(cut) => match cut.variant.as_str() { + constants::VARIANT_SNIPPET => HttpResponse::Ok().body(cut.data), + constants::VARIANT_URL => HttpResponse::TemporaryRedirect() + .header("Location", cut.data) + .finish(), + _ => HttpResponse::NotFound().finish(), + }, + 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, req: HttpRequest) -> impl Responder { let id: String = req.match_info().query("id").parse().unwrap(); diff --git a/cut-be/src/app/router.rs b/cut-be/src/app/router.rs index 9996294..771c58f 100644 --- a/cut-be/src/app/router.rs +++ b/cut-be/src/app/router.rs @@ -2,13 +2,14 @@ use crate::app::controllers::v1; use actix_web::web; pub fn init(app: &mut web::ServiceConfig) { - app.service( - web::scope("/api/v1") - .service(web::scope("/ping").service(v1::ping::get_ping)) - .service( - web::scope("/cut") - .service(v1::cut::get_cut) - .service(v1::cut::post_snippet_create), - ), - ); + app.service(web::scope("/raw").service(v1::cut::get_cut_raw)) + .service( + web::scope("/api/v1") + .service(web::scope("/ping").service(v1::ping::get_ping)) + .service( + web::scope("/cut") + .service(v1::cut::get_cut) + .service(v1::cut::post_snippet_create), + ), + ); } From d6736fa4412ba5e5f063aa76e2c9dc7ea15ad66b Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 10:05:25 +1000 Subject: [PATCH 29/52] Added deps --- cut-fe/package.json | 4 ++++ cut-fe/yarn.lock | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/cut-fe/package.json b/cut-fe/package.json index 221c880..0fcb1f0 100644 --- a/cut-fe/package.json +++ b/cut-fe/package.json @@ -9,19 +9,23 @@ }, "dependencies": { "axios": "^0.21.1", + "babel-plugin-prismjs": "^2.0.1", "core-js": "^3.6.5", "jwt-decode": "^3.1.2", "pkce-challenge": "^2.1.0", + "prismjs": "^1.23.0", "register-service-worker": "^1.7.1", "uuid": "^8.3.2", "vue": "^2.6.11", "vue-class-component": "^7.2.3", + "vue-prism-editor": "^1.2.2", "vue-property-decorator": "^9.1.2", "vue-router": "^3.2.0", "vuetify": "^2.2.11", "vuex": "^3.4.0" }, "devDependencies": { + "@types/prismjs": "^1.16.2", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^2.33.0", "@typescript-eslint/parser": "^2.33.0", diff --git a/cut-fe/yarn.lock b/cut-fe/yarn.lock index 162e739..924f7e3 100644 --- a/cut-fe/yarn.lock +++ b/cut-fe/yarn.lock @@ -1026,6 +1026,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/prismjs@^1.16.2": + version "1.16.2" + resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.2.tgz#c130c977191c988cb35e97585da5d580948cc2d2" + integrity sha512-1M/j21xgTde7RPtpJVQebW5rzrquj7S+wnqt4x9uWrIPpr0Ya/uXypcqC2aUQL5gtLXFCKSH7GnjfAijMdfbuA== + "@types/q@^1.5.1": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" @@ -1955,6 +1960,11 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" +babel-plugin-prismjs@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-prismjs/-/babel-plugin-prismjs-2.0.1.tgz#b56095f423926662259de8f5ee50a7afbcf0fd92" + integrity sha512-GqQGa3xX3Z2ft97oDbGvEFoxD8nKqb3ZVszrOc5H7icnEUA56BIjVYm86hfZZA82uuHLwTIfCXbEKzKG1BzKzg== + babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -2565,6 +2575,15 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +clipboard@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376" + integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg== + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + clipboardy@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290" @@ -3248,6 +3267,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -4379,6 +4403,13 @@ globby@^9.2.0: pify "^4.0.1" slash "^2.0.0" +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= + dependencies: + delegate "^3.1.2" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" @@ -6898,6 +6929,13 @@ pretty-error@^2.0.2: lodash "^4.17.20" renderkid "^2.0.4" +prismjs@^1.23.0: + version "1.23.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33" + integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA== + optionalDependencies: + clipboard "^2.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -7456,6 +7494,11 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= + selfsigned@^1.10.8: version "1.10.8" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.8.tgz#0d17208b7d12c33f8eac85c41835f27fc3d81a30" @@ -8193,6 +8236,11 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-emitter@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -8671,6 +8719,11 @@ vue-loader@^15.9.2: vue-hot-reload-api "^2.3.0" vue-style-loader "^4.1.0" +vue-prism-editor@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/vue-prism-editor/-/vue-prism-editor-1.2.2.tgz#023cfd4329848f191aac851f2f5e6c7a8c2e059f" + integrity sha512-Lq2VgVygTx3Whn/tC8gD4m1ajA4lzSyCTqPLZA1Dq/ErbBaZA93FWRblwCoDR7AD2nXhGWuiTzb5ih3guzB7DA== + vue-property-decorator@^9.1.2: version "9.1.2" resolved "https://registry.yarnpkg.com/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz#266a2eac61ba6527e2e68a6933cfb98fddab5457" From 86150043a568af2cf84a875907be0a6a181080d0 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 10:06:01 +1000 Subject: [PATCH 30/52] Added PrismJS editor plugin --- cut-fe/src/main.ts | 1 + cut-fe/src/plugins/prismjs.ts | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 cut-fe/src/plugins/prismjs.ts diff --git a/cut-fe/src/main.ts b/cut-fe/src/main.ts index 227c149..466d9f5 100644 --- a/cut-fe/src/main.ts +++ b/cut-fe/src/main.ts @@ -4,6 +4,7 @@ import "./registerServiceWorker"; import router from "./router"; import store from "./store"; import vuetify from "./plugins/vuetify"; +import "./plugins/prismjs"; import { StatusMixin } from "@/constants/status"; import "@/styles/App.sass"; diff --git a/cut-fe/src/plugins/prismjs.ts b/cut-fe/src/plugins/prismjs.ts new file mode 100644 index 0000000..d8d612b --- /dev/null +++ b/cut-fe/src/plugins/prismjs.ts @@ -0,0 +1,5 @@ +import Vue from "vue"; +import { PrismEditor } from "vue-prism-editor"; +import "vue-prism-editor/dist/prismeditor.min.css"; + +Vue.component("PrismEditor", PrismEditor); From 8d4bc8d1e2d1f2e07ef18a6e09df0167b182751f Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 10:06:41 +1000 Subject: [PATCH 31/52] Added snippet mode for Create page --- cut-fe/src/styles/Create.sass | 22 ++++ cut-fe/src/styles/prism-atom-dark.css | 143 ++++++++++++++++++++++++++ cut-fe/src/views/manage/Create.vue | 109 +++++++++++++++++++- 3 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 cut-fe/src/styles/Create.sass create mode 100644 cut-fe/src/styles/prism-atom-dark.css diff --git a/cut-fe/src/styles/Create.sass b/cut-fe/src/styles/Create.sass new file mode 100644 index 0000000..2abe9d6 --- /dev/null +++ b/cut-fe/src/styles/Create.sass @@ -0,0 +1,22 @@ +.snippet-editor + background: #2d2d2d + color: #ecf0ed + font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace + font-size: 14px + line-height: 1.5 + padding: 20px 5px + +.v-input__control > .v-input__slot:before, .v-input__slot:after + border: none !important + +.prism-editor__textarea:focus + outline: none + +.prism-editor__textarea + width: 40960px !important + +.prism-editor__editor + white-space: pre !important + +.prism-editor__container + overflow-x: hidden !important diff --git a/cut-fe/src/styles/prism-atom-dark.css b/cut-fe/src/styles/prism-atom-dark.css new file mode 100644 index 0000000..eff090e --- /dev/null +++ b/cut-fe/src/styles/prism-atom-dark.css @@ -0,0 +1,143 @@ +/** + * atom-dark theme for `prism.js` + * Based on Atom's `atom-dark` theme: https://github.com/atom/atom-dark-syntax + * @author Joe Gibson (@gibsjose) + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #ecf0ed; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier, monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border-radius: 0.3em; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #1d1f21; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #7C7C7C; +} + +.token.punctuation { + color: #c5c8c6; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.keyword, +.token.tag { + color: #96CBFE; +} + +.token.class-name { + color: #FFFFB6; + text-decoration: underline; +} + +.token.boolean, +.token.constant { + color: #99CC99; +} + +.token.symbol, +.token.deleted { + color: #f92672; +} + +.token.number { + color: #FF73FD; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #68ff70; +} + +.token.variable { + color: #C6C5FE; +} + +.token.operator { + color: #EDEDED; +} + +.token.entity { + color: #FFFFB6; + cursor: help; +} + +.token.url { + color: #96CBFE; +} + +.language-css .token.string, +.style .token.string { + color: #87C38A; +} + +.token.atrule, +.token.attr-value { + color: #F9EE98; +} + +.token.function { + color: #DAD085; +} + +.token.regex { + color: #E9C062; +} + +.token.important { + color: #fd971f; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} diff --git a/cut-fe/src/views/manage/Create.vue b/cut-fe/src/views/manage/Create.vue index 8f287b8..eb63b5f 100644 --- a/cut-fe/src/views/manage/Create.vue +++ b/cut-fe/src/views/manage/Create.vue @@ -3,13 +3,87 @@

- Cuts + Create Cut

- MOCK CREATE + + + + Snippet + + + URL + + + File + + + + + + + + + + + + + + + + + + + + + + + + + + + URL EDITOR + + + + + FILE EDITOR + + + + + + + Create + + + + @@ -18,10 +92,41 @@ From 7005bd10b8ce8a972e6fc85b6b86eeed484a6239 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 10:06:51 +1000 Subject: [PATCH 32/52] Added supported language list --- cut-fe/babel.config.js | 63 ++++++++++++++++++++++++++++++- cut-fe/src/constants/languages.ts | 56 +++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 cut-fe/src/constants/languages.ts diff --git a/cut-fe/babel.config.js b/cut-fe/babel.config.js index 397abca..6d41090 100644 --- a/cut-fe/babel.config.js +++ b/cut-fe/babel.config.js @@ -1,3 +1,64 @@ module.exports = { - presets: ["@vue/cli-plugin-babel/preset"] + presets: ["@vue/cli-plugin-babel/preset"], + plugins: [ + [ + "prismjs", + { + languages: [ + "html", + "css", + "js", + "applescript", + "shell", + "basic", + "brainfuck", + "c", + "cs", + "cpp", + "coffee", + "d", + "dart", + "docker", + "erlang", + "fortran", + "go", + "graphql", + "groovy", + "hs", + "hlsl", + "java", + "json", + "julia", + "kt", + "tex", + "less", + "lisp", + "lua", + "makefile", + "md", + "matlab", + "objc", + "pascal", + "perl", + "php", + "powershell", + "python", + "r", + "rb", + "rust", + "sass", + "scala", + "sql", + "swift", + "toml", + "ts", + "vb", + "wasm", + "xml", + "yml" + ], + plugins: ["line-numbers"] + } + ] + ] }; diff --git a/cut-fe/src/constants/languages.ts b/cut-fe/src/constants/languages.ts new file mode 100644 index 0000000..81f8fb2 --- /dev/null +++ b/cut-fe/src/constants/languages.ts @@ -0,0 +1,56 @@ +import Prism from "prismjs"; + +export const languages = { + Plaintext: { grammar: null, language: "" }, + HTML: { grammar: Prism.languages.html, language: "html" }, + CSS: { grammar: Prism.languages.css, language: "css" }, + Javascript: { grammar: Prism.languages.js, language: "js" }, + AppleScript: { grammar: Prism.languages.applescript, language: "applescipt" }, + Bash: { grammar: Prism.languages.shell, language: "shell" }, + BASIC: { grammar: Prism.languages.basic, language: "basic" }, + Brainfuck: { grammar: Prism.languages.brainfuck, language: "brainfuck" }, + C: { grammar: Prism.languages.c, language: "c" }, + "C#": { grammar: Prism.languages.cs, language: "cs" }, + "C++": { grammar: Prism.languages.cpp, language: "cpp" }, + CoffeeScript: { grammar: Prism.languages.coffee, language: "coffee" }, + D: { grammar: Prism.languages.d, language: "d" }, + Dart: { grammar: Prism.languages.dart, language: "dart" }, + Docker: { grammar: Prism.languages.docker, language: "docker" }, + Erlang: { grammar: Prism.languages.erlang, language: "erlang" }, + Fortran: { grammar: Prism.languages.fortran, language: "fortran" }, + Go: { grammar: Prism.languages.go, language: "go" }, + GraphQL: { grammar: Prism.languages.graphql, language: "graphql" }, + Groovy: { grammar: Prism.languages.groovy, language: "groovy" }, + Haskell: { grammar: Prism.languages.hs, language: "hs" }, + HLSL: { grammar: Prism.languages.hlsl, language: "hlsl" }, + Java: { grammar: Prism.languages.java, language: "java" }, + JSON: { grammar: Prism.languages.json, language: "json" }, + Julia: { grammar: Prism.languages.julia, language: "julia" }, + Kotlin: { grammar: Prism.languages.kt, language: "kt" }, + LaTeX: { grammar: Prism.languages.tex, language: "tex" }, + Less: { grammar: Prism.languages.less, language: "less" }, + Lisp: { grammar: Prism.languages.lisp, language: "lisp" }, + Lua: { grammar: Prism.languages.lua, language: "lua" }, + Makefile: { grammar: Prism.languages.makefile, language: "makefile" }, + Markdown: { grammar: Prism.languages.md, language: "md" }, + Matlab: { grammar: Prism.languages.matlab, language: "matlab" }, + "Objective-C": { grammar: Prism.languages.objc, language: "objc" }, + Pascal: { grammar: Prism.languages.pascal, language: "pascal" }, + Perl: { grammar: Prism.languages.perl, language: "perl" }, + PHP: { grammar: Prism.languages.php, language: "php" }, + PowerShell: { grammar: Prism.languages.powershell, language: "powershell" }, + Python: { grammar: Prism.languages.python, language: "python" }, + R: { grammar: Prism.languages.r, language: "r" }, + Ruby: { grammar: Prism.languages.rb, language: "rb" }, + Rust: { grammar: Prism.languages.rust, language: "rust" }, + Sass: { grammar: Prism.languages.sass, language: "sass" }, + Scala: { grammar: Prism.languages.scala, language: "scala" }, + SQL: { grammar: Prism.languages.sql, language: "sql" }, + Swift: { grammar: Prism.languages.swift, language: "swift" }, + TOML: { grammar: Prism.languages.toml, language: "toml" }, + TypeScript: { grammar: Prism.languages.ts, language: "ts" }, + "Visual Basic": { grammar: Prism.languages.vb, language: "vb" }, + WebAssembly: { grammar: Prism.languages.wasm, language: "wasm" }, + XML: { grammar: Prism.languages.xml, language: "xml" }, + YAML: { grammar: Prism.languages.yml, language: "yml" } +}; From de43193e3bc51d02d85f2b4d03bc7276f105b595 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 10:07:05 +1000 Subject: [PATCH 33/52] Added mock route --- cut-fe/src/router/index.ts | 10 +++++++++- cut-fe/src/views/manage/Manage.vue | 10 ++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/cut-fe/src/router/index.ts b/cut-fe/src/router/index.ts index 7fd7102..436701a 100644 --- a/cut-fe/src/router/index.ts +++ b/cut-fe/src/router/index.ts @@ -33,7 +33,15 @@ const routes: Array = [ name: "manage:create", component: Create, meta: { - title: "Create | Cut" + title: "Create Cut | Cut" + } + }, + { + path: "list", + name: "manage:list", + component: {}, + meta: { + title: "My Cuts | Cut" } } ] diff --git a/cut-fe/src/views/manage/Manage.vue b/cut-fe/src/views/manage/Manage.vue index 8ba20c8..de1160f 100644 --- a/cut-fe/src/views/manage/Manage.vue +++ b/cut-fe/src/views/manage/Manage.vue @@ -69,9 +69,15 @@ - + - + + + + + + + From b615d382e28eec6482e645d3851ec8b7251ff428 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 16:08:05 +1000 Subject: [PATCH 34/52] Change auth storagemanager --- cut-fe/src/auth/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cut-fe/src/auth/index.ts b/cut-fe/src/auth/index.ts index afb9c2b..b835645 100644 --- a/cut-fe/src/auth/index.ts +++ b/cut-fe/src/auth/index.ts @@ -10,7 +10,7 @@ const authManager = new AuthManager({ clientId: CLIENT_ID, redirectUri: REDIRECT_URI, issuer: ISSUER, - storage: sessionStorage + storage: localStorage }); const login = function() { From 019d182c22c12e06c89b3b02fedfc05c4dcea3c6 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 16:08:18 +1000 Subject: [PATCH 35/52] Updated apis --- cut-fe/src/apis/api.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cut-fe/src/apis/api.ts b/cut-fe/src/apis/api.ts index 4e007b8..35eebac 100644 --- a/cut-fe/src/apis/api.ts +++ b/cut-fe/src/apis/api.ts @@ -1,10 +1,10 @@ -import axios, { AxiosInstance } from "axios"; +import axios, { AxiosInstance, AxiosResponse } from "axios"; import { authManager, refreshAuth } from "@/auth"; import { ACCESS_TOKEN } from "@/auth/AuthManager"; import router from "@/router"; const apiClient: AxiosInstance = axios.create({ - baseURL: "/api/v1/" + baseURL: "http://localhost:9090/api/v1/" }); apiClient.interceptors.response.use( @@ -25,4 +25,13 @@ const withAuth = () => ({ } }); -export default {}; +export default { + cut: { + get: function(hash: string): Promise { + return apiClient.get(`cut/${hash}`); + }, + create: function(cut: object): Promise { + return apiClient.post(`cut`, cut, withAuth()); + } + } +}; From e385b9d76181c988edc40608ab0a87800b050a4c Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 16:08:55 +1000 Subject: [PATCH 36/52] Added vuelidate --- cut-fe/package.json | 2 ++ cut-fe/src/main.ts | 1 + cut-fe/src/plugins/vuelidate.ts | 4 ++++ cut-fe/yarn.lock | 12 ++++++++++++ 4 files changed, 19 insertions(+) create mode 100644 cut-fe/src/plugins/vuelidate.ts diff --git a/cut-fe/package.json b/cut-fe/package.json index 0fcb1f0..d6cc751 100644 --- a/cut-fe/package.json +++ b/cut-fe/package.json @@ -21,12 +21,14 @@ "vue-prism-editor": "^1.2.2", "vue-property-decorator": "^9.1.2", "vue-router": "^3.2.0", + "vuelidate": "^0.7.6", "vuetify": "^2.2.11", "vuex": "^3.4.0" }, "devDependencies": { "@types/prismjs": "^1.16.2", "@types/uuid": "^8.3.0", + "@types/vuelidate": "^0.7.13", "@typescript-eslint/eslint-plugin": "^2.33.0", "@typescript-eslint/parser": "^2.33.0", "@vue/cli-plugin-babel": "~4.5.0", diff --git a/cut-fe/src/main.ts b/cut-fe/src/main.ts index 466d9f5..e3d82ca 100644 --- a/cut-fe/src/main.ts +++ b/cut-fe/src/main.ts @@ -5,6 +5,7 @@ import router from "./router"; import store from "./store"; import vuetify from "./plugins/vuetify"; import "./plugins/prismjs"; +import "./plugins/vuelidate"; import { StatusMixin } from "@/constants/status"; import "@/styles/App.sass"; diff --git a/cut-fe/src/plugins/vuelidate.ts b/cut-fe/src/plugins/vuelidate.ts new file mode 100644 index 0000000..497cc86 --- /dev/null +++ b/cut-fe/src/plugins/vuelidate.ts @@ -0,0 +1,4 @@ +import Vue from "vue"; +import Vuelidate from "vuelidate"; + +Vue.use(Vuelidate); diff --git a/cut-fe/yarn.lock b/cut-fe/yarn.lock index 924f7e3..01ae693 100644 --- a/cut-fe/yarn.lock +++ b/cut-fe/yarn.lock @@ -1076,6 +1076,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== +"@types/vuelidate@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@types/vuelidate/-/vuelidate-0.7.13.tgz#6e7249e1d6b72b3aed14f4439a082e14662c485e" + integrity sha512-CFyaS5yov3HjwoZrQyehiE1cNkyuN0/EDQfpeneWQFC9onJ0ieQL6dgFxN6zzPMHDZ87If3UH9WcgkPB4vbcoQ== + dependencies: + vue "^2.6.11" + "@types/webpack-dev-server@^3.11.0": version "3.11.1" resolved "https://registry.yarnpkg.com/@types/webpack-dev-server/-/webpack-dev-server-3.11.1.tgz#f8f4dac1da226d530bd15a1d5dc34b23ba766ccb" @@ -8760,6 +8767,11 @@ vue@^2.6.11: resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123" integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg== +vuelidate@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.6.tgz#84100c13b943470660d0416642845cd2a1edf4b2" + integrity sha512-suzIuet1jGcyZ4oUSW8J27R2tNrJ9cIfklAh63EbAkFjE380iv97BAiIeolRYoB9bF9usBXCu4BxftWN1Dkn3g== + vuetify-loader@^1.3.0: version "1.6.0" resolved "https://registry.yarnpkg.com/vuetify-loader/-/vuetify-loader-1.6.0.tgz#05df0805b3ab2ff0de198109d34f9da3f69da667" From 4e9ceee13117507f593dd667aa4215116dcfb717 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 16:11:10 +1000 Subject: [PATCH 37/52] Added typings --- cut-fe/src/constants/languages.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cut-fe/src/constants/languages.ts b/cut-fe/src/constants/languages.ts index 81f8fb2..e6279cf 100644 --- a/cut-fe/src/constants/languages.ts +++ b/cut-fe/src/constants/languages.ts @@ -1,7 +1,12 @@ import Prism from "prismjs"; -export const languages = { - Plaintext: { grammar: null, language: "" }, +export const languages: { + [name: string]: { + grammar: Prism.Grammar; + language: string; + }; +} = { + Plaintext: { grammar: Prism.languages.text, language: "" }, HTML: { grammar: Prism.languages.html, language: "html" }, CSS: { grammar: Prism.languages.css, language: "css" }, Javascript: { grammar: Prism.languages.js, language: "js" }, From b1c8bddb68d2cea0563e624d0d579a5239899f18 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Tue, 19 Jan 2021 16:11:30 +1000 Subject: [PATCH 38/52] Implemented snippet submission --- cut-fe/src/styles/Create.sass | 3 + cut-fe/src/views/manage/Create.vue | 150 +++++++++++++++++++++++++++-- 2 files changed, 145 insertions(+), 8 deletions(-) diff --git a/cut-fe/src/styles/Create.sass b/cut-fe/src/styles/Create.sass index 2abe9d6..0b76c6f 100644 --- a/cut-fe/src/styles/Create.sass +++ b/cut-fe/src/styles/Create.sass @@ -6,6 +6,9 @@ line-height: 1.5 padding: 20px 5px +.code-field + font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace + .v-input__control > .v-input__slot:before, .v-input__slot:after border: none !important diff --git a/cut-fe/src/views/manage/Create.vue b/cut-fe/src/views/manage/Create.vue index eb63b5f..d5b9dfc 100644 --- a/cut-fe/src/views/manage/Create.vue +++ b/cut-fe/src/views/manage/Create.vue @@ -29,6 +29,7 @@ @@ -48,6 +54,8 @@ background-color="#2d2d2d" class="rounded" style="border: none !important" + required + :disabled="formLoadStatus === STATUS.LOADING" /> @@ -79,11 +87,91 @@ - Create + + Create + + + + + + + Cut Created + + + + + + + + + + +
+ + + +
+ Use the following link to share your cut. +
+
+ +
+
+ To get view the raw cut, use the following. +
+
+ +
+
+
+
+
+
@@ -91,41 +179,87 @@ diff --git a/cut-fe/src/views/index.ts b/cut-fe/src/views/index.ts index f3f29f9..4c6c284 100644 --- a/cut-fe/src/views/index.ts +++ b/cut-fe/src/views/index.ts @@ -1,3 +1,4 @@ export const Create = () => import("./manage/Create.vue"); export const Home = () => import("./Home.vue"); export const Manage = () => import("./manage/Manage.vue"); +export const View = () => import("./View.vue"); From 06ad696d4a79420884fdfe1b7406a2dd3f21557d Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Wed, 20 Jan 2021 23:32:39 +1000 Subject: [PATCH 50/52] Added dev api base url --- cut-fe/src/apis/api.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cut-fe/src/apis/api.ts b/cut-fe/src/apis/api.ts index e7b975d..a3e7656 100644 --- a/cut-fe/src/apis/api.ts +++ b/cut-fe/src/apis/api.ts @@ -4,7 +4,8 @@ import { authManager, refreshAuth } from "@/auth"; import router from "@/router"; const apiClient: AxiosInstance = axios.create({ - baseURL: "/api/v1/" + baseURL: `${process.env.NODE_ENV === "development" && + process.env.VUE_APP_DEV_BASE_API}/api/v1/` }); apiClient.interceptors.response.use( From 5b5c96a369fd895087648c1056aebef0e6c09889 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Wed, 20 Jan 2021 23:33:10 +1000 Subject: [PATCH 51/52] Updated router --- cut-fe/src/router/index.ts | 21 +++++++++++++++++---- cut-fe/src/views/manage/Create.vue | 8 ++++---- cut-fe/src/views/manage/Manage.vue | 16 +++++++++++++--- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/cut-fe/src/router/index.ts b/cut-fe/src/router/index.ts index 436701a..c29ed03 100644 --- a/cut-fe/src/router/index.ts +++ b/cut-fe/src/router/index.ts @@ -8,7 +8,7 @@ import { logout, unAuthenticatedOnly } from "@/auth"; -import { Manage, Create } from "@/views"; +import { Manage, Create, View } from "@/views"; Vue.use(VueRouter); @@ -24,13 +24,12 @@ const routes: Array = [ }, { path: "/", - beforeEnter: authenticatedOnly, component: Manage, - redirect: "/create", children: [ { path: "create", name: "manage:create", + beforeEnter: authenticatedOnly, component: Create, meta: { title: "Create Cut | Cut" @@ -39,6 +38,7 @@ const routes: Array = [ { path: "list", name: "manage:list", + beforeEnter: authenticatedOnly, component: {}, meta: { title: "My Cuts | Cut" @@ -64,7 +64,20 @@ const routes: Array = [ beforeEnter: unAuthenticatedOnly, component: callback }, - { path: "*", redirect: { name: "home", query: {} } } + { + path: "*", + component: Manage, + children: [ + { + path: "/:hash", + name: "view", + component: View, + meta: { + title: "View Cut | Cut" + } + } + ] + } ]; const router = new VueRouter({ diff --git a/cut-fe/src/views/manage/Create.vue b/cut-fe/src/views/manage/Create.vue index 308e468..bd8e41d 100644 --- a/cut-fe/src/views/manage/Create.vue +++ b/cut-fe/src/views/manage/Create.vue @@ -25,7 +25,7 @@ - + - + - + FILE EDITOR - +
diff --git a/cut-fe/src/views/manage/Manage.vue b/cut-fe/src/views/manage/Manage.vue index de1160f..11cc56f 100644 --- a/cut-fe/src/views/manage/Manage.vue +++ b/cut-fe/src/views/manage/Manage.vue @@ -2,6 +2,7 @@
@@ -9,13 +10,14 @@ + - + @@ -75,7 +85,7 @@ - + From ef9bea93ca0a3dc9c99ac20568134d8d1de4e4c4 Mon Sep 17 00:00:00 2001 From: Danny August Ramaputra Date: Thu, 21 Jan 2021 00:29:46 +1000 Subject: [PATCH 52/52] Fixed dev api base --- cut-fe/src/apis/api.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cut-fe/src/apis/api.ts b/cut-fe/src/apis/api.ts index a3e7656..f74f8fd 100644 --- a/cut-fe/src/apis/api.ts +++ b/cut-fe/src/apis/api.ts @@ -4,8 +4,11 @@ import { authManager, refreshAuth } from "@/auth"; import router from "@/router"; const apiClient: AxiosInstance = axios.create({ - baseURL: `${process.env.NODE_ENV === "development" && - process.env.VUE_APP_DEV_BASE_API}/api/v1/` + baseURL: `${ + process.env.NODE_ENV === "development" + ? process.env.VUE_APP_DEV_BASE_API + : "" + }/api/v1/` }); apiClient.interceptors.response.use(