refactoring

This commit is contained in:
병준 박 2022-08-08 02:48:27 +00:00
parent 700b65ba2d
commit a8726765e8
10 changed files with 364 additions and 104 deletions

View File

@ -28,7 +28,7 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
tokio-cron-scheduler = { version = "0" } tokio-cron-scheduler = { version = "0" }
uuid = { version = "0", features = ["serde", "v4", "v5"] } uuid = { version = "0", features = ["serde", "v4", "v5"] }
beteran-protobuf-rust = { git = "https://gitlab.loafle.net/bet/beteran-protobuf-rust.git", tag = "v0.1.23-snapshot" } beteran-protobuf-rust = { git = "https://gitlab.loafle.net/bet/beteran-protobuf-rust.git", tag = "v0.1.24-snapshot" }
beteran-common-rust = { git = "https://gitlab.loafle.net/bet/beteran-common-rust.git", tag = "v0.1.3-snapshot" } beteran-common-rust = { git = "https://gitlab.loafle.net/bet/beteran-common-rust.git", tag = "v0.1.4-snapshot" }
[build-dependencies] [build-dependencies]

View File

@ -0,0 +1,118 @@
//!
//!
use diesel::{result::Error, sql_query, RunQueryDsl};
use super::models;
pub struct Composition {}
impl std::fmt::Debug for Composition {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Composition of members").finish()
}
}
impl Default for Composition {
fn default() -> Self {
Self::new()
}
}
impl Composition {
///
pub fn new() -> Composition {
Composition {}
}
///
pub fn select(
&self,
conn: &diesel::PgConnection,
id: uuid::Uuid,
) -> Result<Option<models::Member>, Error> {
match sql_query(
"
SELECT
m.id as m_id,
m.site_id as m_site_id,
m.member_class_id as m_member_class_id,
m.member_level_id as m_member_level_id,
m.username as m_username,
m.password as m_password,
m.nickname as m_nickname,
m.mobile_phone_number as m_mobile_phone_number,
m.state as m_state,
m.state_changed_at as m_state_changed_at,
m.referrer_member_id as m_referrer_member_id,
m.referred_count as m_referred_count,
m.last_signined_ip as m_last_signined_ip,
m.last_signined_at as m_last_signined_at,
m.created_at as m_created_at,
m.updated_at as m_updated_at,
m.deleted_at as m_deleted_at,
s.id as s_id,
s.url as s_url,
s.show as s_show,
s.can_use as s_can_use,
s.created_at as s_created_at,
s.updated_at as s_updated_at,
s.deleted_at as s_deleted_at,
mc.id as mc_id,
mc.parent_id as mc_parent_id,
mc.name as mc_name,
mc.created_at as mc_created_at,
mc.updated_at as mc_updated_at,
mc.deleted_at as mc_deleted_at,
ml.id as ml_id,
ml.name as ml_name,
ml.sort_order as ml_sort_order,
ml.created_at as ml_created_at,
ml.updated_at as ml_updated_at,
ml.deleted_at as ml_deleted_at,
_m.id as _m_id,
_m.member_site_id as _m_member_site_id,
_m.member_class_id as _m_member_class_id,
_m.member_level_id as _m_member_level_id,
_m.username as _m_username,
_m.password as _m_password,
_m.nickname as _m_nickname,
_m.mobile_phone_number as _m_mobile_phone_number,
_m.state as _m_state,
_m.state_changed_at as _m_state_changed_at,
_m.referrer_member_id as _m_referrer_member_id,
_m.referred_count as _m_referred_count,
_m.last_signined_ip as _m_last_signined_ip,
_m.last_signined_at as _m_last_signined_at,
_m.created_at as _m_created_at,
_m.updated_at as _m_updated_at,
_m.deleted_at as _m_deleted_at
FROM members as m
JOIN sites s
ON s.id = m.site_id
JOIN member_classes mc
ON mc.id = m.member_class_id
JOIN member_levels ml
ON ml.id = m.member_level_id
JOIN members _m
ON _m.id = m.referrer_member_id
WHERE
m.id = $1
",
)
.bind::<diesel::sql_types::Uuid, _>(id)
.get_result::<models::Member>(conn)
{
Ok(m) => Ok(Some(m)),
Err(e) => match e {
diesel::result::Error::NotFound => Ok(None),
_ => Err(e),
},
}
}
}

View File

@ -0,0 +1,7 @@
//!
//!
///
pub mod composition;
///
pub mod models;

View File

@ -0,0 +1,113 @@
//!
//!
use crate::repositories::{
member::models::Member as _Member, member::schema::MemberState as _MemberState,
member_class::models::MemberClass as _MemberClass,
member_level::models::MemberLevel as _MemberLevel, site::models::Site as _Site,
};
use diesel::deserialize::QueryableByName;
///
#[derive(Eq, Hash, PartialEq, Debug, Clone)]
pub struct Member {
///
pub id: uuid::Uuid,
///
pub site: _Site,
///
pub member_class: _MemberClass,
///
pub member_level: _MemberLevel,
///
pub username: String,
///
pub password: String,
///
pub nickname: String,
///
pub mobile_phone_number: Option<String>,
///
pub state: _MemberState,
///
pub state_changed_at: Option<i64>,
///
pub referrer_member: Option<_Member>,
///
pub referred_count: i64,
///
pub last_signined_ip: Option<String>,
///
pub last_signined_at: Option<i64>,
///
pub created_at: i64,
///
pub updated_at: i64,
///
pub deleted_at: Option<i64>,
}
impl QueryableByName<diesel::pg::Pg> for Member {
fn build<R: diesel::row::NamedRow<diesel::pg::Pg>>(row: &R) -> diesel::deserialize::Result<Self> {
let referrer_member = _Member {
id: row.get("_m_id")?,
site_id: row.get("_m_site_id")?,
member_class_id: row.get("_m_member_class_id")?,
member_level_id: row.get("_m_member_level_id")?,
username: row.get("_m_username")?,
password: row.get("_m_password")?,
nickname: row.get("_m_nickname")?,
mobile_phone_number: row.get("_m_mobile_phone_number")?,
state: row.get("_m_state")?,
state_changed_at: row.get("_m_state_changed_at")?,
referrer_member_id: row.get("_m_referrer_member_id")?,
referred_count: row.get("_m_referred_count")?,
last_signined_ip: row.get("_m_last_signined_ip")?,
last_signined_at: row.get("_m_last_signined_at")?,
created_at: row.get("_m_created_at")?,
updated_at: row.get("_m_updated_at")?,
deleted_at: row.get("_m_deleted_at")?,
};
Ok(Member {
id: row.get("m_id")?,
site: _Site {
id: row.get("s_id")?,
url: row.get("s_url")?,
show: row.get("s_show")?,
can_use: row.get("s_can_use")?,
created_at: row.get("s_created_at")?,
updated_at: row.get("s_updated_at")?,
deleted_at: row.get("s_deleted_at")?,
},
member_class: _MemberClass {
id: row.get("mc_id")?,
parent_id: row.get("mc_parent_id")?,
name: row.get("mc_name")?,
created_at: row.get("mc_created_at")?,
updated_at: row.get("mc_updated_at")?,
deleted_at: row.get("mc_deleted_at")?,
},
member_level: _MemberLevel {
id: row.get("ml_id")?,
name: row.get("ml_name")?,
sort_order: row.get("ml_sort_order")?,
created_at: row.get("ml_created_at")?,
updated_at: row.get("ml_updated_at")?,
deleted_at: row.get("ml_deleted_at")?,
},
username: row.get("m_username")?,
password: row.get("m_password")?,
nickname: row.get("m_nickname")?,
mobile_phone_number: row.get("m_mobile_phone_number")?,
state: row.get("m_state")?,
state_changed_at: row.get("m_state_changed_at")?,
referrer_member: None,
referred_count: row.get("m_referred_count")?,
last_signined_ip: row.get("m_last_signined_ip")?,
last_signined_at: row.get("m_last_signined_at")?,
created_at: row.get("m_created_at")?,
updated_at: row.get("m_updated_at")?,
deleted_at: row.get("m_deleted_at")?,
})
}
}

View File

@ -0,0 +1,2 @@
pub mod member;
pub mod site;

View File

@ -0,0 +1,62 @@
//!
//!
use super::models;
use crate::repositories;
use diesel::{result::Error, sql_query, RunQueryDsl};
pub struct Composition {
site_repository: repositories::site::repository::Repository,
}
impl std::fmt::Debug for Composition {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Composition of members").finish()
}
}
impl Default for Composition {
fn default() -> Self {
Self::new()
}
}
impl Composition {
///
pub fn new() -> Composition {
Composition {
site_repository: repositories::site::repository::Repository::new(),
}
}
///
pub fn select_by_url(
&self,
conn: &diesel::PgConnection,
url: Option<String>,
site_id: uuid::Uuid,
) -> Result<Option<repositories::site::models::Site>, Error> {
let site_url = match url {
Some(site_url) => site_url,
None => {
return Ok(None);
}
};
let ms = match self.site_repository.select(conn, site_id)? {
Some(s) => s,
None => {
return Ok(None);
}
};
if ms.url.eq("*") {
return Ok(Some(ms));
}
if !ms.url.eq(&site_url) {
return Ok(None);
}
Ok(Some(ms))
}
}

View File

@ -0,0 +1,7 @@
//!
//!
///
pub mod composition;
///
pub mod models;

View File

@ -0,0 +1 @@

View File

@ -27,10 +27,18 @@ impl Repository {
} }
/// ///
pub fn select(&self, conn: &diesel::PgConnection, id: uuid::Uuid) -> Result<models::Site, Error> { pub fn select(
sites::table &self,
.find(id as uuid::Uuid) conn: &diesel::PgConnection,
.first::<models::Site>(conn) id: uuid::Uuid,
) -> Result<Option<models::Site>, Error> {
match sites::table.find(id).first::<models::Site>(conn) {
Ok(m) => Ok(Some(m)),
Err(e) => match e {
diesel::result::Error::NotFound => Ok(None),
_ => Err(e),
},
}
} }
/// ///

View File

@ -1,6 +1,7 @@
//! //!
//! //!
use super::super::super::compositions;
use super::super::super::repositories; use super::super::super::repositories;
use beteran_common_rust as bcr; use beteran_common_rust as bcr;
use beteran_protobuf_rust as bpr; use beteran_protobuf_rust as bpr;
@ -16,8 +17,9 @@ pub struct Service<'a> {
queue_broker: String, queue_broker: String,
pool: Pool<ConnectionManager<PgConnection>>, pool: Pool<ConnectionManager<PgConnection>>,
member_repository: repositories::member::repository::Repository, member_repository: repositories::member::repository::Repository,
member_site_repository: repositories::site::repository::Repository,
member_session_repository: repositories::member_session::repository::Repository, member_session_repository: repositories::member_session::repository::Repository,
site_repository: repositories::site::repository::Repository,
site_composition: compositions::site::composition::Composition,
argon2_config: argon2::Config<'a>, argon2_config: argon2::Config<'a>,
captcha_salt: String, captcha_salt: String,
password_salt: String, password_salt: String,
@ -44,8 +46,9 @@ impl Service<'_> {
queue_broker, queue_broker,
pool, pool,
member_repository: repositories::member::repository::Repository::new(), member_repository: repositories::member::repository::Repository::new(),
member_site_repository: repositories::site::repository::Repository::new(),
member_session_repository: repositories::member_session::repository::Repository::new(), member_session_repository: repositories::member_session::repository::Repository::new(),
site_repository: repositories::site::repository::Repository::new(),
site_composition: compositions::site::composition::Composition::new(),
argon2_config: argon2::Config::default(), argon2_config: argon2::Config::default(),
captcha_salt, captcha_salt,
password_salt, password_salt,
@ -62,6 +65,38 @@ impl Service<'_> {
.map(|_| ()) .map(|_| ())
} }
fn check_site(
&self,
conn: &diesel::PgConnection,
url: Option<String>,
site_id: uuid::Uuid,
) -> Result<repositories::site::models::Site, bcr::error::rpc::Error> {
match self
.site_composition
.select_by_url(conn, url, site_id)
.map_err(|e| {
bcr::error::rpc::Error::Server(bcr::error::rpc::Server {
code: bpr::protobuf::rpc::Error::SERVER_00,
message: format!("server {}", e),
data: None,
})
})? {
Some(s) => Ok(s),
None => Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid site_url information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client.site_url".to_string(),
value: "".to_string(),
error_type: bcr::error::rpc::InvalidParamsType::None,
message: "".to_string(),
},
},
)),
}
}
async fn check_username_for_duplication(&self) -> Result<(), Box<dyn std::error::Error>> { async fn check_username_for_duplication(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self let s = self
.connection_broker .connection_broker
@ -274,7 +309,7 @@ impl Service<'_> {
}) })
})?; })?;
let client = match req.client { let _client = match req.client {
Some(c) => c, Some(c) => c,
None => { None => {
return Err(bcr::error::rpc::Error::InvalidParams( return Err(bcr::error::rpc::Error::InvalidParams(
@ -292,59 +327,6 @@ impl Service<'_> {
} }
}; };
// let site_url = match client.site_url {
// Some(site_url) => site_url,
// None => {
// return Err(bcr::error::rpc::Error::InvalidParams(
// bcr::error::rpc::InvalidParams {
// message: "invalid site_url information".to_string(),
// detail: bcr::error::rpc::InvalidParamsDetail {
// location: "request".to_string(),
// param: "client.site_url".to_string(),
// value: "".to_string(),
// error_type: bcr::error::rpc::InvalidParamsType::Required,
// message: "".to_string(),
// },
// },
// ));
// }
// };
let conn = self.pool.get().map_err(|e| {
bcr::error::rpc::Error::Server(bcr::error::rpc::Server {
code: bpr::protobuf::rpc::Error::SERVER_00,
message: format!("server {}", e),
data: None,
})
})?;
// match self
// .member_site_repository
// .select_by_url(&conn, &site_url)
// .map_err(|e| {
// bcr::error::rpc::Error::Server(bcr::error::rpc::Server {
// code: bpr::protobuf::rpc::Error::SERVER_00,
// message: format!("server {}", e),
// data: None,
// })
// })? {
// Some(ms) => ms,
// None => {
// return Err(bcr::error::rpc::Error::InvalidParams(
// bcr::error::rpc::InvalidParams {
// message: "invalid site_url information".to_string(),
// detail: bcr::error::rpc::InvalidParamsDetail {
// location: "request".to_string(),
// param: "client.site_url".to_string(),
// value: "".to_string(),
// error_type: bcr::error::rpc::InvalidParamsType::None,
// message: "".to_string(),
// },
// },
// ));
// }
// };
let mut c = captcha::Captcha::new(); let mut c = captcha::Captcha::new();
let c = c let c = c
@ -454,33 +436,6 @@ impl Service<'_> {
}) })
})?; })?;
let ms = match self
.member_site_repository
.select_by_url(&conn, client.site_url())
.map_err(|e| {
bcr::error::rpc::Error::Server(bcr::error::rpc::Server {
code: bpr::protobuf::rpc::Error::SERVER_00,
message: format!("server {}", e),
data: None,
})
})? {
Some(ms) => ms,
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid site_url information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client.site_url".to_string(),
value: "".to_string(),
error_type: bcr::error::rpc::InvalidParamsType::None,
message: "".to_string(),
},
},
));
}
};
let security_code_hash = req.security_code_hash; let security_code_hash = req.security_code_hash;
let security_code = req.security_code; let security_code = req.security_code;
let username = req.username; let username = req.username;
@ -544,21 +499,6 @@ impl Service<'_> {
} }
}; };
if m.site_id != ms.id {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid site_url".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "header".to_string(),
param: "client.site_url".to_string(),
value: client.site_url().to_string(),
error_type: bcr::error::rpc::InvalidParamsType::EqualsTo,
message: "".to_string(),
},
},
));
}
if !(argon2::verify_encoded(&m.password, password.as_bytes()).map_err(|e| { if !(argon2::verify_encoded(&m.password, password.as_bytes()).map_err(|e| {
bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams { bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams {
message: "invalid password".to_string(), message: "invalid password".to_string(),
@ -585,6 +525,8 @@ impl Service<'_> {
)); ));
} }
let _s = self.check_site(&conn, client.site_url.clone(), m.site_id)?;
let expires_at = (chrono::Utc::now() + chrono::Duration::minutes(30)).timestamp(); let expires_at = (chrono::Utc::now() + chrono::Duration::minutes(30)).timestamp();
let session = self let session = self
.member_session_repository .member_session_repository