diff --git a/crates/rtsa_db/src/password_util.rs b/crates/rtsa_db/src/password_util.rs index 83ce24d..34ef1ab 100644 --- a/crates/rtsa_db/src/password_util.rs +++ b/crates/rtsa_db/src/password_util.rs @@ -62,8 +62,10 @@ mod tests { #[test] fn test_md5() { - let input = "hello"; + // let input = "hello"; + let input = "joylink0503"; let output = md5(input); - assert_eq!(output, "5d41402abc4b2a76b9719d911017c592"); + println!("{}", output); + // assert_eq!(output, "5d41402abc4b2a76b9719d911017c592"); } } diff --git a/crates/rtsa_dto/build.rs b/crates/rtsa_dto/build.rs index 9b9e224..fc2d097 100644 --- a/crates/rtsa_dto/build.rs +++ b/crates/rtsa_dto/build.rs @@ -29,6 +29,10 @@ fn main() { "common.DataType", "#[derive(sqlx::Type, async_graphql::Enum, serde::Serialize, serde::Deserialize)]", ) + .type_attribute( + "common.LineType", + "#[derive(async_graphql::Enum, serde::Serialize, serde::Deserialize)]", + ) .type_attribute( "common.IscsStyle", "#[derive(async_graphql::Enum, serde::Serialize, serde::Deserialize)]", diff --git a/crates/rtsa_dto/src/pb/common.rs b/crates/rtsa_dto/src/pb/common.rs index 2ba4331..3e89a13 100644 --- a/crates/rtsa_dto/src/pb/common.rs +++ b/crates/rtsa_dto/src/pb/common.rs @@ -199,6 +199,56 @@ impl DataType { } } } +/// 线路类型 +#[derive( + async_graphql::Enum, + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration, +)] +#[repr(i32)] +pub enum LineType { + /// 未知 + Unknown = 0, + /// 城市轨道交通 + Ur = 1, + /// 城际轨道交通 + Ir = 2, + /// 市域轨道交通 + Cr = 3, +} +impl LineType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + LineType::Unknown => "LineType_Unknown", + LineType::Ur => "LineType_Ur", + LineType::Ir => "LineType_Ir", + LineType::Cr => "LineType_Cr", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "LineType_Unknown" => Some(Self::Unknown), + "LineType_Ur" => Some(Self::Ur), + "LineType_Ir" => Some(Self::Ir), + "LineType_Cr" => Some(Self::Cr), + _ => None, + } + } +} #[derive( async_graphql::Enum, serde::Serialize, diff --git a/manager/src/apis/data_options_def.rs b/manager/src/apis/data_options_def.rs index 9a21c95..494d916 100644 --- a/manager/src/apis/data_options_def.rs +++ b/manager/src/apis/data_options_def.rs @@ -1,16 +1,28 @@ use async_graphql::{InputObject, InputType, OutputType, SimpleObject}; use rtsa_db::{common::TableColumn, model::DraftDataColumn}; -use rtsa_dto::common::IscsStyle; +use rtsa_dto::common::{IscsStyle, LineType}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json::Value; pub trait DataOptions: InputType + OutputType + Serialize + DeserializeOwned { fn to_data_options_filter_clause(&self) -> String; } -impl DataOptions for Value { +// impl DataOptions for Value { +// fn to_data_options_filter_clause(&self) -> String { +// format!("{} @> '{}'", DraftDataColumn::Options.name(), self) +// } +// } + +impl DataOptions for T +where + T: ?Sized + Serialize + DeserializeOwned + OutputType + InputType, +{ fn to_data_options_filter_clause(&self) -> String { - format!("{} @> '{}'", DraftDataColumn::Options.name(), self) + format!( + "{} @> '{}'", + DraftDataColumn::Options.name(), + serde_json::to_string(self).unwrap() + ) } } @@ -20,14 +32,14 @@ pub struct IscsDataOptions { pub style: IscsStyle, } -impl DataOptions for IscsDataOptions { - fn to_data_options_filter_clause(&self) -> String { - let options_column = DraftDataColumn::Options.name(); - format!( - "{options_column} @> '{}'", - serde_json::to_string(self).unwrap() - ) - } +#[derive(Debug, Clone, InputObject, SimpleObject, Serialize, Deserialize)] +#[graphql(input_name = "LineInfoOptionsInput")] +pub struct LineInfoOptions { + pub line_type: LineType, + /// 城轨线路所属城市 + pub city: Option, + /// 城轨线路编号 + pub line_code: Option, } #[cfg(test)] diff --git a/manager/src/apis/draft_data.rs b/manager/src/apis/draft_data.rs index b46856a..114c640 100644 --- a/manager/src/apis/draft_data.rs +++ b/manager/src/apis/draft_data.rs @@ -11,7 +11,7 @@ use serde_json::Value; use crate::apis::{PageDto, PageQueryDto}; use crate::loader::RtsaDbLoader; -use super::data_options_def::{DataOptions, IscsDataOptions}; +use super::data_options_def::{DataOptions, IscsDataOptions, LineInfoOptions}; use super::release_data::ReleaseDataId; use super::user::UserId; @@ -39,6 +39,37 @@ impl DraftDataQuery { .await?; Ok(paging_result.into()) } + /// 分页查询用户电子地图草稿数据 + #[graphql(guard = "RoleGuard::new(Role::User)")] + async fn user_draft_em_data_paging<'ctx>( + &self, + ctx: &Context<'ctx>, + paging: PageQueryDto, + mut query: UserDraftDataFilterDto, + ) -> async_graphql::Result> { + let claims = ctx.data::()?.decode()?; + query = query.with_data_type_and_user_id(DataType::Em, claims.uid); + let db_accessor = ctx.data::()?; + let paging_result = db_accessor + .paging_query_draft_data(query.into(), paging.into()) + .await?; + Ok(paging_result.into()) + } + /// 分页查询共享的草稿电子地图数据 + #[graphql(guard = "RoleGuard::new(Role::User)")] + async fn shared_draft_em_data_paging<'ctx>( + &self, + ctx: &Context<'ctx>, + paging: PageQueryDto, + mut query: DraftDataFilterDto, + ) -> async_graphql::Result> { + let db_accessor = ctx.data::()?; + query.data_type = Some(DataType::Em); + let paging_result = db_accessor + .paging_query_draft_data(query.into(), paging.into()) + .await?; + Ok(paging_result.into()) + } /// 分页查询用户的草稿ISCS数据 #[graphql(guard = "RoleGuard::new(Role::User)")] async fn user_draft_iscs_data_paging<'ctx>( @@ -48,8 +79,7 @@ impl DraftDataQuery { mut query: UserDraftDataFilterDto, ) -> async_graphql::Result> { let claims = ctx.data::()?.decode()?; - query.user_id = claims.uid; - query.data_type = Some(DataType::Iscs); + query = query.with_data_type_and_user_id(DataType::Iscs, claims.uid); let db_accessor = ctx.data::()?; let paging_result = db_accessor .paging_query_draft_data(query.into(), paging.into()) @@ -98,6 +128,20 @@ impl DraftDataQuery { #[Object] impl DraftDataMutation { + /// 创建电子地图草稿数据 + #[graphql(guard = "RoleGuard::new(Role::User)")] + async fn create_draft_em_data( + &self, + ctx: &Context<'_>, + mut input: CreateDraftDataDto, + ) -> async_graphql::Result { + let claims = ctx.data::()?.decode()?; + input = input.with_data_type_and_user_id(DataType::Em, claims.uid); + let db_accessor = ctx.data::()?; + let draft_data = db_accessor.create_draft_data(input.into()).await?; + Ok(draft_data.into()) + } + /// 创建草稿ISCS数据 #[graphql(guard = "RoleGuard::new(Role::User)")] async fn create_draft_iscs_data( @@ -194,6 +238,7 @@ impl DraftDataMutation { #[derive(Debug, InputObject)] #[graphql(concrete(name = "CreateDraftIscsDto", params(IscsDataOptions)))] +#[graphql(concrete(name = "CreateDraftEmDto", params(LineInfoOptions)))] pub struct CreateDraftDataDto { #[graphql(skip)] pub data_type: Option, @@ -228,6 +273,7 @@ impl From> for rtsa_db::CreateDraftData { /// 用户的草稿数据查询条件 #[derive(Debug, InputObject)] +#[graphql(concrete(name = "UserDraftEmDataFilterDto", params(LineInfoOptions)))] #[graphql(concrete(name = "UserDraftIscsDataFilterDto", params(IscsDataOptions)))] pub struct UserDraftDataFilterDto { #[graphql(skip)] @@ -239,6 +285,14 @@ pub struct UserDraftDataFilterDto { pub is_shared: Option, } +impl UserDraftDataFilterDto { + pub fn with_data_type_and_user_id(mut self, data_type: DataType, id: i32) -> Self { + self.data_type = Some(data_type); + self.user_id = id; + self + } +} + impl From> for rtsa_db::DraftDataQuery { fn from(value: UserDraftDataFilterDto) -> Self { Self { @@ -254,6 +308,7 @@ impl From> for rtsa_db::DraftDataQuery /// 共享的草稿数据查询条件 #[derive(Debug, InputObject)] #[graphql(concrete(name = "DraftDataFilterDto", params(Value)))] +#[graphql(concrete(name = "SharedDraftEmDataFilterDto", params(LineInfoOptions)))] #[graphql(concrete(name = "SharedDraftIscsDataFilterDto", params(IscsDataOptions)))] pub struct DraftDataFilterDto { @@ -336,6 +391,26 @@ impl From for DraftDataDto { } } +/// 草稿电子地图数据 +#[derive(Debug, SimpleObject)] +pub struct DraftEmDataDto { + pub draft_data: DraftDataDto, + pub options: Option, +} + +impl From for DraftEmDataDto { + fn from(value: rtsa_db::model::DraftDataModel) -> Self { + Self { + options: value + .options + .clone() + .map(|o| serde_json::from_value(o).unwrap()), + draft_data: value.into(), + } + } +} + +/// ISCS草稿数据 #[derive(Debug, SimpleObject)] pub struct DraftIscsDataDto { pub draft_data: DraftDataDto, diff --git a/manager/src/apis/mod.rs b/manager/src/apis/mod.rs index ec0cd10..8430449 100644 --- a/manager/src/apis/mod.rs +++ b/manager/src/apis/mod.rs @@ -67,6 +67,7 @@ impl From for rtsa_db::common::PageQuery { #[derive(Debug, SimpleObject)] #[graphql(concrete(name = "UserPageDto", params(user::UserDto)))] #[graphql(concrete(name = "DraftDataPageDto", params(draft_data::DraftDataDto)))] +#[graphql(concrete(name = "DraftEmDataPageDto", params(draft_data::DraftEmDataDto)))] #[graphql(concrete(name = "DraftIscsDataPageDto", params(draft_data::DraftIscsDataDto)))] #[graphql(concrete(name = "ReleaseDataPageDto", params(release_data::ReleaseDataDto)))] #[graphql(concrete( diff --git a/manager/src/sys_init/mod.rs b/manager/src/sys_init/mod.rs index 204c7e0..3d2b383 100644 --- a/manager/src/sys_init/mod.rs +++ b/manager/src/sys_init/mod.rs @@ -72,6 +72,13 @@ mod tests { assert_eq!(org.name, DEFAULT_ORG_NAME); assert_eq!(org.creator_id, user.id); + let user = db_accessor + .query_user_login(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) + .await?; + assert_eq!(user.username, ADMIN_USER_NAME); + assert_eq!(user.nickname, ADMIN_USER_NAME); + assert_eq!(user.roles, json!([Role::Admin])); + Ok(()) } } diff --git a/manager/src/user_auth/mod.rs b/manager/src/user_auth/mod.rs index a4fd1c9..9ff0e01 100644 --- a/manager/src/user_auth/mod.rs +++ b/manager/src/user_auth/mod.rs @@ -1,7 +1,7 @@ use async_graphql::Guard; use rtsa_db::prelude::*; use rtsa_dto::common::Role; -use rtsa_log::tracing::{info, warn}; +use rtsa_log::tracing::{error, info, warn}; use serde_json::json; mod jwt_auth; @@ -113,9 +113,24 @@ pub(crate) async fn handle_login( )) } } - _ => Err(BusinessError::AuthError( - "用户不存在或密码不正确".to_string(), - )), + DbAccessError::PasswordNotMatch => { + warn!( + "密码不匹配: username={}, password={}, org_id={}", + user_login_dto.username, user_login_dto.password, org_id + ); + Err(BusinessError::AuthError( + "用户不存在或密码不正确".to_string(), + )) + } + _ => { + error!( + "查询用户登录验证错误: username={}, org_id={}, error={:?}", + user_login_dto.username, org_id, e + ); + Err(BusinessError::AuthError( + "用户不存在或密码不正确".to_string(), + )) + } } } } diff --git a/rtsa-proto-msg b/rtsa-proto-msg index 867c075..a30bf52 160000 --- a/rtsa-proto-msg +++ b/rtsa-proto-msg @@ -1 +1 @@ -Subproject commit 867c075833ffbe64b0291db921adddc9d5d5a7a3 +Subproject commit a30bf52339620075e8d666be363eb3d93d532656