diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 11ba45e0..37fd62fa 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -29,6 +29,9 @@ jobs: - name: Replace values in .env run: | + # log level + sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env + sed -i 's/GOTRUE_SMTP_USER=.*/GOTRUE_SMTP_USER=${{ secrets.GOTRUE_SMTP_USER }}/' .env sed -i 's/GOTRUE_SMTP_PASS=.*/GOTRUE_SMTP_PASS=${{ secrets.GOTRUE_SMTP_PASS }}/' .env sed -i 's/GOTRUE_SMTP_ADMIN_EMAIL=.*/GOTRUE_SMTP_ADMIN_EMAIL=${{ secrets.GOTRUE_SMTP_ADMIN_EMAIL }}/' .env diff --git a/.sqlx/query-171f55ffb42bc6ae115ebf29f4cee7419690d3b13f1e27b93f03c399dd2838e6.json b/.sqlx/query-171f55ffb42bc6ae115ebf29f4cee7419690d3b13f1e27b93f03c399dd2838e6.json new file mode 100644 index 00000000..6dbee8d6 --- /dev/null +++ b/.sqlx/query-171f55ffb42bc6ae115ebf29f4cee7419690d3b13f1e27b93f03c399dd2838e6.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO af_user (uuid, email, name)\n VALUES ($1, $2, $3)\n ON CONFLICT (email) DO NOTHING;\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "171f55ffb42bc6ae115ebf29f4cee7419690d3b13f1e27b93f03c399dd2838e6" +} diff --git a/.sqlx/query-6638a972a142a500adb842843394d64d5625b0fef0a7c14b1b751bd64567f9b7.json b/.sqlx/query-6638a972a142a500adb842843394d64d5625b0fef0a7c14b1b751bd64567f9b7.json deleted file mode 100644 index cfdd1ee6..00000000 --- a/.sqlx/query-6638a972a142a500adb842843394d64d5625b0fef0a7c14b1b751bd64567f9b7.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO af_user (uuid, email, name)\n SELECT $1, $2, $3\n WHERE NOT EXISTS (\n SELECT 1 FROM public.af_user WHERE email = $2\n )\n AND NOT EXISTS (\n SELECT 1 FROM public.af_user WHERE uuid = $1\n )\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Text", - "Text" - ] - }, - "nullable": [] - }, - "hash": "6638a972a142a500adb842843394d64d5625b0fef0a7c14b1b751bd64567f9b7" -} diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index ae0f5423..1a9ca229 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -22,17 +22,16 @@ services: - ./migrations/before:/docker-entrypoint-initdb.d pgadmin: - build: - context: . - dockerfile: docker/pgadmin.Dockerfile + image: dpage/pgadmin4 depends_on: - postgres environment: - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL} - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD} - - PGADMIN_CONFIG_WTF_CSRF_ENABLED=False ports: - 5400:80 + volumes: + - ./docker/pgadmin/servers.json:/pgadmin4/servers.json redis: image: redis diff --git a/docker-compose.yml b/docker-compose.yml index 287c5298..b4f8f206 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,17 +36,16 @@ services: - ./migrations/before:/docker-entrypoint-initdb.d pgadmin: - build: - context: . - dockerfile: docker/pgadmin.Dockerfile + image: dpage/pgadmin4 depends_on: - postgres environment: - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL} - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD} - - PGADMIN_CONFIG_WTF_CSRF_ENABLED=False ports: - 5400:80 + volumes: + - ./docker/pgadmin/servers.json:/pgadmin4/servers.json redis: image: redis diff --git a/docker/pgadmin.Dockerfile b/docker/pgadmin.Dockerfile deleted file mode 100644 index 9e124dd0..00000000 --- a/docker/pgadmin.Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM dpage/pgadmin4 - -COPY ./docker/pgadmin/servers.json /pgadmin4/servers.json -COPY ./docker/pgadmin/custom_entrypoint.sh /custom_entrypoint.sh - -USER root -RUN chmod +x /custom_entrypoint.sh - -USER pgadmin - -ENTRYPOINT ["/custom_entrypoint.sh"] diff --git a/docker/pgadmin/custom_entrypoint.sh b/docker/pgadmin/custom_entrypoint.sh deleted file mode 100755 index 8cd3dfab..00000000 --- a/docker/pgadmin/custom_entrypoint.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# Call the original entrypoint -/entrypoint.sh "$@" - -# Your additional commands to invoke setup.py (example below, adjust accordingly) -python setup.py --load-servers /path/to/your/servers.json - -# Keep container running -tail -f /dev/null diff --git a/libs/client-api/src/http.rs b/libs/client-api/src/http.rs index 939945bc..1e5af6e8 100644 --- a/libs/client-api/src/http.rs +++ b/libs/client-api/src/http.rs @@ -418,7 +418,7 @@ impl Client { Ok(()) } - #[instrument(level = "debug", skip_all, err)] + #[instrument(skip_all, err)] pub async fn sign_in_password(&self, email: &str, password: &str) -> Result { let access_token_resp = self .gotrue_client diff --git a/libs/database-entity/src/database_error.rs b/libs/database-entity/src/database_error.rs index 25ee8a47..938937c3 100644 --- a/libs/database-entity/src/database_error.rs +++ b/libs/database-entity/src/database_error.rs @@ -15,6 +15,9 @@ pub enum DatabaseError { #[error(transparent)] UuidError(#[from] uuid::Error), + #[error(transparent)] + SqlxError(sqlx::Error), + #[error("Storage space not enough")] StorageSpaceNotEnough, @@ -35,7 +38,7 @@ impl From for DatabaseError { fn from(value: sqlx::Error) -> Self { match value { Error::RowNotFound => DatabaseError::RecordNotFound, - _ => DatabaseError::Internal(value.into()), + _ => DatabaseError::SqlxError(value), } } } diff --git a/libs/database/src/resource_usage.rs b/libs/database/src/resource_usage.rs index 05fe42df..7581a109 100644 --- a/libs/database/src/resource_usage.rs +++ b/libs/database/src/resource_usage.rs @@ -1,3 +1,4 @@ +use database_entity::database_error::DatabaseError; use database_entity::AFBlobMetadata; use rust_decimal::prelude::ToPrimitive; use sqlx::types::Decimal; @@ -10,7 +11,7 @@ pub async fn is_blob_metadata_exists( pool: &PgPool, workspace_id: &Uuid, file_id: &str, -) -> Result { +) -> Result { let exists: (bool,) = sqlx::query_as( r#" SELECT EXISTS ( @@ -35,8 +36,8 @@ pub async fn insert_blob_metadata( workspace_id: &Uuid, file_type: &str, file_size: i64, -) -> Result { - sqlx::query_as!( +) -> Result { + let metadata = sqlx::query_as!( AFBlobMetadata, r#" INSERT INTO af_blob_metadata @@ -53,7 +54,8 @@ pub async fn insert_blob_metadata( file_size ) .fetch_one(pg_pool) - .await + .await?; + Ok(metadata) } #[instrument(level = "trace", skip_all, err)] @@ -61,8 +63,8 @@ pub async fn delete_blob_metadata( pg_pool: &PgPool, workspace_id: &Uuid, file_id: &str, -) -> Result { - sqlx::query_as!( +) -> Result { + let metadata = sqlx::query_as!( AFBlobMetadata, r#" DELETE FROM af_blob_metadata @@ -73,7 +75,8 @@ pub async fn delete_blob_metadata( file_id, ) .fetch_one(pg_pool) - .await + .await?; + Ok(metadata) } #[instrument(level = "trace", skip_all, err)] @@ -81,8 +84,8 @@ pub async fn get_blob_metadata( pg_pool: &PgPool, workspace_id: &Uuid, file_id: &str, -) -> Result { - sqlx::query_as!( +) -> Result { + let metadata = sqlx::query_as!( AFBlobMetadata, r#" SELECT * FROM af_blob_metadata @@ -92,14 +95,15 @@ pub async fn get_blob_metadata( file_id, ) .fetch_one(pg_pool) - .await + .await?; + Ok(metadata) } #[instrument(level = "trace", skip_all, err)] pub async fn get_workspace_usage_size( pool: &PgPool, workspace_id: &Uuid, -) -> Result { +) -> Result { let row: (Option,) = sqlx::query_as(r#"SELECT SUM(file_size) FROM af_blob_metadata WHERE workspace_id = $1;"#) .bind(workspace_id) diff --git a/libs/database/src/user.rs b/libs/database/src/user.rs index 8b9af546..137ea395 100644 --- a/libs/database/src/user.rs +++ b/libs/database/src/user.rs @@ -1,10 +1,13 @@ +use anyhow::Context; +use database_entity::database_error::DatabaseError; use sqlx::PgPool; +use tracing::instrument; pub async fn update_user_name( pool: &PgPool, uuid: &uuid::Uuid, name: &str, -) -> Result<(), sqlx::Error> { +) -> Result<(), DatabaseError> { sqlx::query!( r#" UPDATE af_user @@ -19,35 +22,35 @@ pub async fn update_user_name( Ok(()) } +#[instrument(skip_all, err)] pub async fn create_user_if_not_exists( pool: &PgPool, user_uuid: &uuid::Uuid, email: &str, name: &str, -) -> Result { +) -> Result { let affected_rows = sqlx::query!( r#" INSERT INTO af_user (uuid, email, name) - SELECT $1, $2, $3 - WHERE NOT EXISTS ( - SELECT 1 FROM public.af_user WHERE email = $2 - ) - AND NOT EXISTS ( - SELECT 1 FROM public.af_user WHERE uuid = $1 - ) + VALUES ($1, $2, $3) + ON CONFLICT (email) DO NOTHING; "#, user_uuid, email, name ) .execute(pool) - .await? + .await + .context(format!( + "Fail to insert user with uuid: {}, name: {}, email: {}", + user_uuid, name, email + ))? .rows_affected(); Ok(affected_rows > 0) } -pub async fn uid_from_uuid(pool: &PgPool, gotrue_uuid: &uuid::Uuid) -> Result { +pub async fn uid_from_uuid(pool: &PgPool, gotrue_uuid: &uuid::Uuid) -> Result { let uid = sqlx::query!( r#" SELECT uid FROM af_user WHERE uuid = $1 diff --git a/libs/database/src/workspace.rs b/libs/database/src/workspace.rs index b2893493..f1700f9c 100644 --- a/libs/database/src/workspace.rs +++ b/libs/database/src/workspace.rs @@ -3,13 +3,14 @@ use sqlx::{ PgPool, }; +use database_entity::database_error::DatabaseError; use database_entity::{AFRole, AFUserProfileView, AFWorkspace, AFWorkspaceMember}; pub async fn select_all_workspaces_owned( pool: &PgPool, owner_uuid: &Uuid, -) -> Result, sqlx::Error> { - sqlx::query_as!( +) -> Result, DatabaseError> { + let workspaces = sqlx::query_as!( AFWorkspace, r#" SELECT * FROM public.af_workspace WHERE owner_uid = ( @@ -19,14 +20,15 @@ pub async fn select_all_workspaces_owned( owner_uuid ) .fetch_all(pool) - .await + .await?; + Ok(workspaces) } pub async fn select_user_is_workspace_owner( pg_pool: &PgPool, user_uuid: &Uuid, workspace_uuid: &Uuid, -) -> Result { +) -> Result { let exists = sqlx::query_scalar!( r#" SELECT EXISTS( @@ -50,7 +52,7 @@ pub async fn insert_workspace_members( workspace_id: &uuid::Uuid, member_emails: &[String], role: AFRole, -) -> Result<(), sqlx::Error> { +) -> Result<(), DatabaseError> { sqlx::query!( r#" INSERT INTO public.af_workspace_member (workspace_id, uid, role_id) @@ -74,7 +76,7 @@ pub async fn delete_workspace_members( pool: &PgPool, workspace_id: &uuid::Uuid, member_emails: &[String], -) -> Result<(), sqlx::Error> { +) -> Result<(), DatabaseError> { sqlx::query!( r#" DELETE FROM public.af_workspace_member @@ -94,8 +96,8 @@ pub async fn delete_workspace_members( pub async fn select_workspace_members( pg_pool: &PgPool, workspace_id: &uuid::Uuid, -) -> Result, sqlx::Error> { - sqlx::query_as!( +) -> Result, DatabaseError> { + let members = sqlx::query_as!( AFWorkspaceMember, r#" SELECT af_user.email, af_workspace_member.role_id AS role @@ -106,14 +108,15 @@ pub async fn select_workspace_members( workspace_id ) .fetch_all(pg_pool) - .await + .await?; + Ok(members) } pub async fn select_user_profile_view_by_uuid( pool: &PgPool, user_uuid: &Uuid, -) -> Result, sqlx::Error> { - sqlx::query_as!( +) -> Result, DatabaseError> { + let user_profile = sqlx::query_as!( AFUserProfileView, r#" SELECT * @@ -122,5 +125,6 @@ pub async fn select_user_profile_view_by_uuid( user_uuid ) .fetch_optional(pool) - .await + .await?; + Ok(user_profile) } diff --git a/libs/shared-entity/src/app_error.rs b/libs/shared-entity/src/app_error.rs index b920196c..496be407 100644 --- a/libs/shared-entity/src/app_error.rs +++ b/libs/shared-entity/src/app_error.rs @@ -45,9 +45,9 @@ impl actix_web::error::ResponseError for AppError { // impl From for AppError { fn from(err: anyhow::Error) -> Self { - match err.downcast_ref::() { - None => AppError::new(ErrorCode::Unhandled, err.to_string()), - Some(err) => err.clone(), + match err.downcast::() { + Err(err) => AppError::new(ErrorCode::Unhandled, err.to_string()), + Ok(err) => err, } } } diff --git a/nginx/nginx.conf b/nginx/nginx.conf index d01a8c4e..dcf0a209 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -41,7 +41,10 @@ http { # PgAdmin location /pgadmin/ { proxy_set_header X-Script-Name /pgadmin; + proxy_set_header X-Scheme $scheme; + proxy_set_header Host $host; proxy_pass http://pgadmin:80/; + proxy_redirect off; } # Admin Frontend diff --git a/src/api/user.rs b/src/api/user.rs index 1dfa17c4..32962ba9 100644 --- a/src/api/user.rs +++ b/src/api/user.rs @@ -18,6 +18,7 @@ use actix_web::web::{Data, Json}; use actix_web::HttpRequest; use actix_web::Result; use actix_web::{web, HttpResponse, Scope}; +use tracing_actix_web::RequestId; pub fn user_scope() -> Scope { web::scope("/api/user") @@ -33,9 +34,11 @@ pub fn user_scope() -> Scope { .service(web::resource("/password").route(web::post().to(change_password_handler))) } +#[tracing::instrument(skip(state, path), err)] async fn verify_handler( path: web::Path, state: Data, + required_id: RequestId, ) -> Result> { let access_token = path.into_inner(); let is_new = biz::user::token_verify(&state.pg_pool, &state.gotrue_client, &access_token).await?; @@ -43,19 +46,22 @@ async fn verify_handler( Ok(AppResponse::Ok().with_data(resp).into()) } -#[tracing::instrument(level = "debug", skip(state))] +#[tracing::instrument(skip(state), err)] async fn profile_handler( uuid: UserUuid, state: Data, + required_id: RequestId, ) -> Result> { let profile = biz::user::get_profile(&state.pg_pool, &uuid).await?; Ok(AppResponse::Ok().with_data(profile).into()) } +#[tracing::instrument(skip(state, auth, req), err)] async fn update_handler( auth: Authorization, req: Json, state: Data, + required_id: RequestId, ) -> Result> { let params = req.into_inner(); biz::user::update_user(&state.pg_pool, &auth.uuid()?, ¶ms.new_name).await?; diff --git a/src/component/auth/user.rs b/src/component/auth/user.rs index 7b845355..c3b1b876 100644 --- a/src/component/auth/user.rs +++ b/src/component/auth/user.rs @@ -18,6 +18,7 @@ use sqlx::{PgPool, Postgres, Transaction}; use std::sync::Arc; use token::{create_token, parse_token, TokenError}; use tokio::sync::RwLock; +use tracing::instrument; pub async fn login( email: String, @@ -51,6 +52,7 @@ pub async fn logout(logged_user: LoggedUser, cache: Arc>) { cache.write().await.unauthorized(logged_user); } +#[instrument(skip_all, err)] pub async fn register( username: String, email: String,