diff --git a/admin_frontend/dev.env b/admin_frontend/dev.env new file mode 100644 index 00000000..7e13181f --- /dev/null +++ b/admin_frontend/dev.env @@ -0,0 +1 @@ +GOTRUE_URL=http://localhost:9998 diff --git a/admin_frontend/dev/README.md b/admin_frontend/dev/README.md new file mode 100644 index 00000000..725ba098 --- /dev/null +++ b/admin_frontend/dev/README.md @@ -0,0 +1,5 @@ +# Development +- Run the dev docker compose in the previous directory: `docker compose --file docker-compose-dev.yml up -d` +- cp `dev.env` to `.env` +- run the frontend: `cargo watch -x run -w .` +- web will be served at `localhost:3000` diff --git a/admin_frontend/dev/nginx.conf b/admin_frontend/dev/nginx.conf new file mode 100644 index 00000000..c968826a --- /dev/null +++ b/admin_frontend/dev/nginx.conf @@ -0,0 +1,32 @@ +# Minimal nginx configuration for AppFlowy-Cloud +# Self Hosted AppFlowy Cloud user should alter this file to suit their needs + +events { + worker_connections 1024; +} + +http { + server { + listen 80; + server_name gotrue; + + location / { + proxy_pass http://localhost:9998; + } + } + + server { + listen 80; + + # GoTrue + location ~ ^/(verify|authorize|callback|settings|user|token|admin) { + proxy_pass http://localhost:9998; + } + + # Admin Frontend + location / { + proxy_pass http://localhost:3000; + } + } + +} diff --git a/admin_frontend/src/error.rs b/admin_frontend/src/error.rs index c25c5dd9..11c2c8f9 100644 --- a/admin_frontend/src/error.rs +++ b/admin_frontend/src/error.rs @@ -1,26 +1,29 @@ -use axum::{response::IntoResponse, Json}; +use axum::{http::status, response::IntoResponse}; -#[derive(serde::Serialize)] +// #[derive(serde::Serialize)] pub struct WebApiError { - pub code: i16, - pub message: String, + pub status_code: status::StatusCode, + pub payload: String, } impl WebApiError { - pub fn new(code: i16, message: String) -> Self { - Self { code, message } + pub fn new(code: status::StatusCode, message: String) -> Self { + Self { + status_code: code, + payload: message, + } } } impl IntoResponse for WebApiError { fn into_response(self) -> axum::response::Response { - Json(self).into_response() + (self.status_code, self.payload).into_response() } } impl From for WebApiError { fn from(v: gotrue_entity::GoTrueError) -> Self { - WebApiError::new(500, v.to_string()) + WebApiError::new(status::StatusCode::UNAUTHORIZED, v.to_string()) } } diff --git a/admin_frontend/src/main.rs b/admin_frontend/src/main.rs index b3c7f08b..5737cf8e 100644 --- a/admin_frontend/src/main.rs +++ b/admin_frontend/src/main.rs @@ -14,7 +14,7 @@ async fn main() { let gotrue_client = gotrue::api::Client::new( reqwest::Client::new(), - &std::env::var("GOTRUE_URL").unwrap_or("http://localhost:9999".to_string()), + &std::env::var("GOTRUE_URL").unwrap_or("http://gotrue:9999".to_string()), ); let state = AppState { gotrue_client }; diff --git a/admin_frontend/src/models.rs b/admin_frontend/src/models.rs index d0289cdc..5c7ae5d4 100644 --- a/admin_frontend/src/models.rs +++ b/admin_frontend/src/models.rs @@ -1,7 +1,12 @@ -use serde::Deserialize; +use serde::{Deserialize, Serialize}; #[derive(Deserialize)] pub struct LoginRequest { pub email: String, pub password: String, } + +#[derive(Serialize)] +pub struct LoginResponse { + pub access_token: String, +} diff --git a/admin_frontend/src/response.rs b/admin_frontend/src/response.rs index 1e0bf973..f09f480f 100644 --- a/admin_frontend/src/response.rs +++ b/admin_frontend/src/response.rs @@ -10,6 +10,19 @@ where pub data: T, } +impl WebApiResponse +where + T: serde::Serialize, +{ + pub fn new(data: T) -> Self { + Self { + code: 0, + message: "success".to_owned(), + data, + } + } +} + impl IntoResponse for WebApiResponse where T: serde::Serialize, diff --git a/admin_frontend/src/web_api.rs b/admin_frontend/src/web_api.rs index 7114d932..27a3a691 100644 --- a/admin_frontend/src/web_api.rs +++ b/admin_frontend/src/web_api.rs @@ -1,12 +1,10 @@ -use std::borrow::Cow; - -use axum::response::Result; -use axum::{extract::State, routing::post, Json, Router}; -use axum_extra::extract::cookie::Cookie; -use axum_extra::extract::CookieJar; - use crate::error::WebApiError; +use crate::models::LoginResponse; +use crate::response::WebApiResponse; use crate::{models::LoginRequest, AppState}; +use axum::response::Result; +use axum::Json; +use axum::{extract::State, routing::post, Router}; pub fn router() -> Router { Router::new() @@ -17,10 +15,9 @@ pub fn router() -> Router { // TODO: Support OAuth2 login // login and set the cookie pub async fn login_handler( - cookie_jar: CookieJar, State(state): State, Json(param): Json, -) -> Result { +) -> Result, WebApiError> { let token = state .gotrue_client .token(&gotrue::grant::Grant::Password( @@ -31,12 +28,7 @@ pub async fn login_handler( )) .await?; - Ok(set_access_token_cookie( - cookie_jar, - token.access_token.into(), - )) -} - -fn set_access_token_cookie(jar: CookieJar, token: Cow<'static, str>) -> CookieJar { - jar.add(Cookie::new("access_token", token)) + Ok(WebApiResponse::new(LoginResponse { + access_token: token.access_token, + })) } diff --git a/admin_frontend/src/web_app.rs b/admin_frontend/src/web_app.rs index d5e10703..005d068f 100644 --- a/admin_frontend/src/web_app.rs +++ b/admin_frontend/src/web_app.rs @@ -2,7 +2,7 @@ use crate::error::RenderError; use askama::Template; use axum::response::Result; use axum::{response::Html, routing::get, Router}; -use axum_extra::extract::cookie::CookieJar; +use axum_extra::extract::cookie::{Cookie, CookieJar}; use crate::templates; @@ -11,9 +11,14 @@ pub fn router() -> Router { .route("/", get(home_handler)) .route("/home", get(home_handler)) .route("/login", get(login_handler)) + + // for testing and debugging + .route("/setcookie", get(set_cookie_handler)) + .route("/resetcookie", get(reset_cookie_handler)) } pub async fn home_handler(cookies: CookieJar) -> Result, RenderError> { + println!("cookies: {:?}", cookies); let access_token = cookies.get("access_token"); match access_token { Some(access_token) => Ok(Html(access_token.to_string())), // TODO: render home page @@ -25,3 +30,11 @@ pub async fn login_handler() -> Result, RenderError> { let s = templates::Login {}.render()?; Ok(Html(s)) } + +pub async fn set_cookie_handler(jar: CookieJar) -> CookieJar { + jar.add(Cookie::new("access_token", "test")) +} + +pub async fn reset_cookie_handler(jar: CookieJar) -> CookieJar { + jar.remove(Cookie::new("access_token", "")) +} diff --git a/admin_frontend/templates/login.html b/admin_frontend/templates/login.html index 84c373e5..3bb00d22 100644 --- a/admin_frontend/templates/login.html +++ b/admin_frontend/templates/login.html @@ -1,37 +1,62 @@ - - -

Admin Login

-
- - - - + +

Admin Login

+ +
- - - -
+ + + + + + + + +
+ + + +
+ + + +
+ +
+
- - - - - - - - + + - - - - -
- diff --git a/docker-compose.yml b/docker-compose.yml index f31ff15a..c62b448d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: depends_on: - appflowy_cloud - gotrue - - admin_frontend + # - admin_frontend volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/ssl/certificate.crt:/etc/nginx/ssl/certificate.crt @@ -95,12 +95,12 @@ services: ports: - 8000:8000 - admin_frontend: - restart: on-failure - build: - context: . - dockerfile: ./admin_frontend/Dockerfile - depends_on: - - gotrue - ports: - - 3000:3000 + #admin_frontend: + # restart: on-failure + # build: + # context: . + # dockerfile: ./admin_frontend/Dockerfile + # depends_on: + # - gotrue + # ports: + # - 3000:3000