create member is added

This commit is contained in:
병준 박 2022-08-12 07:44:19 +00:00
parent b9072233cb
commit c4da7de2b5
12 changed files with 1058 additions and 263 deletions

View File

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

View File

@ -1,16 +1,17 @@
CREATE TABLE IF NOT EXISTS banks (
id UUID DEFAULT uuid_generate_v4(),
name TEXT,
name TEXT NOT NULL,
sort_order INTEGER NOT NULL,
show BOOLEAN NOT NULL DEFAULT TRUE,
can_use BOOLEAN NOT NULL DEFAULT TRUE,
memo TEXT,
created_at BIGINT NOT NULL DEFAULT (extract(epoch from now()) * 1000),
updated_at BIGINT NOT NULL DEFAULT (extract(epoch from now()) * 1000),
PRIMARY KEY (id),
UNIQUE (url)
UNIQUE (name)
);
CREATE UNIQUE INDEX uidx_banks_url ON banks (url);
CREATE UNIQUE INDEX uidx_banks_name ON banks (name);
-- trigger (updated_at)
CREATE TRIGGER tg_banks_updated_at

View File

@ -88,7 +88,31 @@ INSERT INTO member_classes (id, name, parent_id, show) VALUES ('cac7b897-2549-4f
INSERT INTO member_classes (id, name, parent_id, show) VALUES ('e11cac11-3825-4f4e-9cd5-39367f23f973', '매장', 'cac7b897-2549-4f04-8415-8868f1dcb1da', true);
INSERT INTO member_classes (id, name, parent_id, show) VALUES ('4598f07a-86d1-42a4-b038-25706683a7cd', '회원', 'e11cac11-3825-4f4e-9cd5-39367f23f973', true);
INSERT INTO banks (id, name, sort_order) VALUES ('816eff0d-db96-4753-98e3-36035a9a012b', '국민은행', 0);
INSERT INTO banks (id, name, sort_order) VALUES ('20c9c093-fd6a-463d-9de4-e93d0db0e7eb', '광주은행', 1);
INSERT INTO banks (id, name, sort_order) VALUES ('f29d0f2c-3a44-4cb0-a2be-e017a8d6ca1a', '경남은행', 2);
INSERT INTO banks (id, name, sort_order) VALUES ('e87fb908-503b-45d3-9135-395379bfae40', '기업은행', 3);
INSERT INTO banks (id, name, sort_order) VALUES ('76288961-dceb-4f4f-9a11-9c78697142b4', '농협', 4);
INSERT INTO banks (id, name, sort_order) VALUES ('dda3f025-dbb5-46c4-bc4a-99d03e38a32d', '대구은행', 5);
INSERT INTO banks (id, name, sort_order) VALUES ('3a605288-f44f-48fa-9b8c-29d0f0bbb2d3', '도이치은행', 6);
INSERT INTO banks (id, name, sort_order) VALUES ('7bc942da-4f09-4d53-95e8-d3376c14e0ee', '부산은행', 7);
INSERT INTO banks (id, name, sort_order) VALUES ('233123a1-5644-4906-a250-3cde4c53e422', '새마을금고', 8);
INSERT INTO banks (id, name, sort_order) VALUES ('334ad8a2-15a8-4e5b-8d64-a3d237dc213b', '수협', 9);
INSERT INTO banks (id, name, sort_order) VALUES ('54dd2c4c-a8c2-47d8-923c-da83af072d26', '신한은행', 10);
INSERT INTO banks (id, name, sort_order) VALUES ('1d862fcc-287e-42bc-9fde-a510ebd0d922', '외환은행', 11);
INSERT INTO banks (id, name, sort_order) VALUES ('02cb96e6-6ddd-4826-ab07-280a34e4b6bc', '우리은행', 12);
INSERT INTO banks (id, name, sort_order) VALUES ('cb77185b-164d-4faa-8022-b10e1e28d35c', '우체국', 13);
INSERT INTO banks (id, name, sort_order) VALUES ('c73db022-7de6-4635-8f34-6c3923cb7b09', '전북은행', 14);
INSERT INTO banks (id, name, sort_order) VALUES ('05851cfa-96cd-4f8a-b813-5aa6c1929f0a', '제주은행', 15);
INSERT INTO banks (id, name, sort_order) VALUES ('297998cf-3fe8-4d3b-8ebe-156c200ec534', '하나은행', 16);
INSERT INTO banks (id, name, sort_order) VALUES ('e576b713-c798-4956-b89e-e23ce23524b2', '한국씨티은행', 17);
INSERT INTO banks (id, name, sort_order) VALUES ('3096a455-7280-41d8-9525-43a4060dca52', 'HSBC은행', 18);
INSERT INTO banks (id, name, sort_order) VALUES ('7f3cb09a-7746-4937-aec1-a3e7d5ce493c', 'SC제일은행', 19);
INSERT INTO banks (id, name, sort_order) VALUES ('f086a43a-e69a-4725-b4d5-868e9a32206b', '신협', 20);
INSERT INTO banks (id, name, sort_order) VALUES ('76196e64-838d-42ab-9a65-9aea66e15844', '카카오뱅크', 21);
INSERT INTO banks (id, name, sort_order) VALUES ('cb2330ee-3b72-4ff5-819d-f7ebbcd01b03', 'K뱅크', 22);
INSERT INTO banks (id, name, sort_order) VALUES ('3967f424-2457-4a21-9ad0-cbe9a6aaf4b1', '산림조합', 23);
INSERT INTO banks (id, name, sort_order) VALUES ('fd245c51-16d3-497b-b9a8-b3dc71acce87', '산업은행', 24);
INSERT INTO members(
id,

View File

@ -5,6 +5,102 @@ use super::models;
use crate::repositories;
use diesel::{result::Error, sql_query, RunQueryDsl};
static MEMBER_QUERY: &str = "
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.name as s_name,
s.path as s_path,
s.show as s_show,
s.can_use as s_can_use,
s.memo as s_memo,
s.expires_at as s_expires_at,
s.created_at as s_created_at,
s.updated_at as s_updated_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.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,
mba.id as mba_id,
mba.member_id as mba_member_id,
mba.bank_id as mba_bank_id,
mba.name as mba_name,
mba.account_number as mba_account_number,
mba.memo as mba_memo,
mba.created_at as mba_created_at,
mba.updated_at as mba_updated_at,
_b.id as _b_id,
_b.name as _b_name,
_b.sort_order as _b_sort_order,
_b.show as _b_show,
_b.can_use as _b_can_use,
_b.memo as _b_memo,
_b.created_at as _b_created_at,
_b.updated_at as _b_updated_at
FROM members as m
INNER JOIN sites s
ON s.id = m.site_id
INNER JOIN member_classes mc
ON mc.id = m.member_class_id
INNER JOIN member_levels ml
ON ml.id = m.member_level_id
LEFT OUTER JOIN members _m
ON _m.id = m.referrer_member_id
LEFT OUTER JOIN member_bank_accounts mba
ON mba.member_id = m.id
LEFT OUTER JOIN banks _b
ON _b.id = mba.bank_id
";
pub struct Composition {}
impl std::fmt::Debug for Composition {
@ -31,85 +127,18 @@ impl Composition {
conn: &diesel::PgConnection,
id: uuid::Uuid,
) -> Result<Option<models::MemberModel>, Error> {
match sql_query(
let query = format!(
"
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,
{}
WHERE
m.id = $1
",
MEMBER_QUERY
);
s.id as s_id,
s.url as s_url,
s.name as s_name,
s.path as s_path,
s.show as s_show,
s.can_use as s_can_use,
s.memo as s_memo,
s.expires_at as s_expires_at,
s.created_at as s_created_at,
s.updated_at as s_updated_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.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
FROM members as m
INNER JOIN sites s
ON s.id = m.site_id
INNER JOIN member_classes mc
ON mc.id = m.member_class_id
INNER JOIN member_levels ml
ON ml.id = m.member_level_id
LEFT OUTER JOIN members _m
ON _m.id = m.referrer_member_id
WHERE
m.id = $1
",
)
.bind::<diesel::sql_types::Uuid, _>(id)
.get_result::<models::MemberModel>(conn)
match sql_query(query)
.bind::<diesel::sql_types::Uuid, _>(id)
.get_result::<models::MemberModel>(conn)
{
Ok(m) => Ok(Some(m)),
Err(e) => match e {
@ -125,85 +154,18 @@ impl Composition {
conn: &diesel::PgConnection,
username: &str,
) -> Result<Option<models::MemberModel>, Error> {
match sql_query(
let query = format!(
"
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,
{}
WHERE
m.username = $1
",
MEMBER_QUERY
);
s.id as s_id,
s.url as s_url,
s.name as s_name,
s.path as s_path,
s.show as s_show,
s.can_use as s_can_use,
s.memo as s_memo,
s.expires_at as s_expires_at,
s.created_at as s_created_at,
s.updated_at as s_updated_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.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
FROM members as m
INNER JOIN sites s
ON s.id = m.site_id
INNER JOIN member_classes mc
ON mc.id = m.member_class_id
INNER JOIN member_levels ml
ON ml.id = m.member_level_id
LEFT OUTER JOIN members _m
ON _m.id = m.referrer_member_id
WHERE
m.username = $1
",
)
.bind::<diesel::sql_types::Text, _>(username)
.get_result::<models::MemberModel>(conn)
match sql_query(query)
.bind::<diesel::sql_types::Text, _>(username)
.get_result::<models::MemberModel>(conn)
{
Ok(m) => Ok(Some(m)),
Err(e) => match e {
@ -222,89 +184,14 @@ impl Composition {
use std::fmt::Write;
let mut query = String::new();
write!(
&mut 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.name as s_name,
s.path as s_path,
s.show as s_show,
s.can_use as s_can_use,
s.memo as s_memo,
s.expires_at as s_expires_at,
s.created_at as s_created_at,
s.updated_at as s_updated_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.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
FROM members as m
INNER JOIN sites s
ON s.id = m.site_id
INNER JOIN member_classes mc
ON mc.id = m.member_class_id
INNER JOIN member_levels ml
ON ml.id = m.member_level_id
LEFT OUTER JOIN members _m
ON _m.id = m.referrer_member_id
"
)
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
write!(&mut query, "{}", MEMBER_QUERY)
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
let mut query_where = String::new();
if let Some(sp) = find_all.site_id {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.site_id = '{}'", sp)
@ -312,7 +199,7 @@ impl Composition {
}
if let Some(sp) = find_all.member_class_id {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.member_class_id = '{}'", sp)
@ -320,7 +207,7 @@ impl Composition {
}
if let Some(sp) = find_all.member_level_id {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.member_level_id = '{}'", sp)
@ -328,7 +215,7 @@ impl Composition {
}
if let Some(sp) = &find_all.username_like {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.username like '{}'", sp)
@ -336,7 +223,7 @@ impl Composition {
}
if let Some(sp) = &find_all.nickname_like {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.nickname like '{}'", sp)
@ -344,7 +231,7 @@ impl Composition {
}
if let Some(sp) = &find_all.mobile_phone_number_like {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.mobile_phone_number like '{}'", sp)
@ -352,7 +239,7 @@ impl Composition {
}
if let Some(sp) = &find_all.last_signined_ip {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.last_signined_ip = '{}'", sp)
@ -360,7 +247,7 @@ impl Composition {
}
if let Some(sp) = find_all.state {
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
write!(&mut query_where, "m.state = '{:?}'", sp)
@ -368,19 +255,19 @@ impl Composition {
}
if !query_where.is_empty() {
write!(&mut query_where, " and ")
write!(&mut query_where, " AND ")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
if find_all.deleted_at.is_some() {
write!(&mut query_where, "m.deleted_at is NOT NULL")
write!(&mut query_where, "m.deleted_at IS NOT NULL")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
} else {
write!(&mut query_where, "m.deleted_at is NULL")
write!(&mut query_where, "m.deleted_at IS NULL")
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}
if !query_where.is_empty() {
write!(&mut query, " where {}", query_where)
write!(&mut query, " WHERE {}", query_where)
.map_err(|e| diesel::result::Error::QueryBuilderError(e.to_string().into()))?;
}

View File

@ -1,8 +1,8 @@
//!
//!
use crate::repositories::{
member::models::Member as _Member, member::schema::MemberState as _MemberState,
member_class::models::MemberClass as _MemberClass,
bank::models::Bank as _Bank, 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;
@ -31,6 +31,8 @@ pub struct MemberModel {
///
pub state_changed_at: Option<i64>,
///
pub bank_account: Option<MemberBankAccountModel>,
///
pub referrer_member: Option<_Member>,
///
pub referred_count: i64,
@ -48,12 +50,10 @@ pub struct MemberModel {
impl QueryableByName<diesel::pg::Pg> for MemberModel {
fn build<R: diesel::row::NamedRow<diesel::pg::Pg>>(row: &R) -> diesel::deserialize::Result<Self> {
let referrer_member_id = row
let referrer_member = match row
.get::<diesel::sql_types::Nullable<diesel::sql_types::Uuid>, Option<uuid::Uuid>>(
"m_referrer_member_id",
)?;
let referrer_member = match referrer_member_id {
)? {
Some(_) => Some(_Member {
id: row.get("_m_id")?,
site_id: row.get("_m_site_id")?,
@ -76,6 +76,36 @@ impl QueryableByName<diesel::pg::Pg> for MemberModel {
None => None,
};
let bank = match row
.get::<diesel::sql_types::Nullable<diesel::sql_types::Uuid>, Option<uuid::Uuid>>("_b_id")?
{
Some(_) => Some(_Bank {
id: row.get("_b_id")?,
name: row.get("_b_name")?,
sort_order: row.get("_b_sort_order")?,
show: row.get("_b_show")?,
can_use: row.get("_b_can_use")?,
memo: row.get("_b_memo")?,
created_at: row.get("_b_created_at")?,
updated_at: row.get("_b_updated_at")?,
}),
None => None,
};
let member_bank_account = match bank {
Some(bank) => Some(MemberBankAccountModel {
id: row.get("mba_id")?,
member_id: row.get("mba_member_id")?,
bank,
name: row.get("mba_name")?,
account_number: row.get("mba_account_number")?,
memo: row.get("mba_memo")?,
created_at: row.get("mba_created_at")?,
updated_at: row.get("mba_updated_at")?,
}),
None => None,
};
Ok(MemberModel {
id: row.get("m_id")?,
site: _Site {
@ -112,6 +142,7 @@ impl QueryableByName<diesel::pg::Pg> for MemberModel {
mobile_phone_number: row.get("m_mobile_phone_number")?,
state: row.get("m_state")?,
state_changed_at: row.get("m_state_changed_at")?,
bank_account: member_bank_account,
referrer_member,
referred_count: row.get("m_referred_count")?,
last_signined_ip: row.get("m_last_signined_ip")?,
@ -122,3 +153,23 @@ impl QueryableByName<diesel::pg::Pg> for MemberModel {
})
}
}
#[derive(Eq, Hash, PartialEq, Debug, Clone)]
pub struct MemberBankAccountModel {
///
pub id: uuid::Uuid,
///
pub member_id: uuid::Uuid,
///
pub bank: _Bank,
///
pub name: String,
///
pub account_number: String,
///
pub memo: Option<String>,
///
pub created_at: i64,
///
pub updated_at: i64,
}

View File

@ -76,6 +76,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
connection_server_broker.clone(),
queue_server_broker.clone(),
pool.clone(),
password_salt,
);
println!("Server service [beteran-server-service] is started");

View File

@ -8,7 +8,9 @@ pub struct Bank {
///
pub id: uuid::Uuid,
///
pub name: Option<String>,
pub name: String,
///
pub sort_order: i32,
///
pub show: bool,
///
@ -26,7 +28,9 @@ pub struct Bank {
#[table_name = "banks"]
pub struct NewBank {
///
pub name: Option<String>,
pub name: String,
///
pub sort_order: i32,
///
pub show: bool,
///
@ -40,7 +44,9 @@ pub struct NewBank {
#[table_name = "banks"]
pub struct ModifyBank {
///
pub name: Option<String>,
pub name: String,
///
pub sort_order: i32,
///
pub show: bool,
///

View File

@ -7,7 +7,9 @@ table! {
///
id -> Uuid,
///
name -> Nullable<Text>,
name -> Text,
///
sort_order -> Integer,
///
show -> Bool,
///

2
src/services/bank/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod models;
pub mod service;

View File

@ -0,0 +1,19 @@
use crate::repositories;
use beteran_protobuf_rust as bpr;
impl From<&repositories::site::models::Site> for bpr::models::domain::Site {
fn from(d: &repositories::site::models::Site) -> Self {
bpr::models::domain::Site {
id: d.id.to_string(),
url: d.url.clone(),
name: d.name.clone(),
path: d.path.clone(),
show: d.show,
can_use: d.can_use,
memo: d.memo.clone(),
expires_at: d.expires_at.map(|d| d as u64),
created_at: d.created_at as u64,
updated_at: d.updated_at as u64,
}
}
}

View File

@ -0,0 +1,548 @@
//!
//!
use std::str::FromStr;
use super::models;
use crate::compositions;
use crate::repositories;
use beteran_common_rust as bcr;
use beteran_protobuf_rust as bpr;
use diesel::{
r2d2::{ConnectionManager, Pool},
PgConnection,
};
use prost::Message;
///
pub struct Service {
connection_broker: nats::asynk::Connection,
queue_broker: String,
pool: Pool<ConnectionManager<PgConnection>>,
site_repository: repositories::site::repository::Repository,
site_composition: compositions::site::composition::Composition,
}
impl std::fmt::Debug for Service {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Service of service.member.service.identity")
.finish()
}
}
impl Service {
///
pub fn new(
connection_broker: nats::asynk::Connection,
queue_broker: String,
pool: Pool<ConnectionManager<PgConnection>>,
) -> Service {
Service {
connection_broker,
queue_broker,
pool,
site_repository: repositories::site::repository::Repository::new(),
site_composition: compositions::site::composition::Composition::new(),
}
}
pub async fn subscribe(&self) -> std::result::Result<(), std::boxed::Box<dyn std::error::Error>> {
futures::try_join!(
self.list_sites(),
self.create_site(),
self.update_site(),
self.delete_site(),
)
.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 list_sites(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self
.connection_broker
.queue_subscribe(
bpr::ss::domain::site::SUBJECT_LIST_SITES,
self.queue_broker.as_str(),
)
.await?;
while let Some(message) = s.next().await {
if let Err(e) = async {
let req = bpr::ss::domain::site::ListSitesRequest::decode(message.data.as_slice())
.map_err(|e| {
bcr::error::rpc::Error::InvalidRequest(bcr::error::rpc::InvalidRequest {
message: format!("invalid request: {}", e),
})
})?;
let client = match req.client {
Some(c) => c,
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid client information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client".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,
})
})?;
let find_all = repositories::site::models::FindAll {
url_like: None,
name_like: None,
path_like: None,
memo_like: None,
show: None,
can_use: None,
pagination: req
.pagination
.as_ref()
.map(|d| bcr::models::pagination::Pagination::from(d)),
sorts: Some(
req
.sorts
.iter()
.map(|d| beteran_common_rust::models::pagination::Sort::from(d))
.collect(),
),
};
let count = self
.site_repository
.select_all_count(&conn, &find_all)
.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,
})
})?;
let list = self
.site_repository
.select_all(&conn, &find_all)
.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,
})
})?;
message
.respond(
bpr::ss::domain::site::ListSitesResponse {
error: None,
result: Some(bpr::ss::domain::site::list_sites_response::Result {
sites: list
.iter()
.map(|d| bpr::models::domain::Site::from(d))
.collect(),
}),
}
.encode_to_vec(),
)
.await
.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,
})
})?;
Ok::<(), bcr::error::rpc::Error>(())
}
.await
{
message
.respond(
bpr::ss::domain::site::ListSitesResponse {
error: Some(bpr::protobuf::rpc::Error::from(e)),
result: None,
}
.encode_to_vec(),
)
.await?;
}
}
Ok(())
}
async fn create_site(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self
.connection_broker
.queue_subscribe(
bpr::ss::domain::site::SUBJECT_CREATE_SITE,
self.queue_broker.as_str(),
)
.await?;
while let Some(message) = s.next().await {
if let Err(e) = async {
let req = bpr::ss::domain::site::CreateSiteRequest::decode(message.data.as_slice())
.map_err(|e| {
bcr::error::rpc::Error::InvalidRequest(bcr::error::rpc::InvalidRequest {
message: format!("invalid request: {}", e),
})
})?;
let client = match req.client {
Some(c) => c,
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid client information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client".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,
})
})?;
let s = self
.site_repository
.insert(
&conn,
&repositories::site::models::NewSite {
url: req.url,
name: req.name,
path: req.path,
show: req.show,
can_use: req.can_use,
memo: req.memo,
expires_at: req.expires_at.map(|d| d as i64),
},
)
.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,
})
})?;
message
.respond(
bpr::ss::domain::site::CreateSiteResponse {
error: None,
result: Some(bpr::ss::domain::site::create_site_response::Result {
site: Some(bpr::models::domain::Site::from(&s)),
}),
}
.encode_to_vec(),
)
.await
.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,
})
})?;
Ok::<(), bcr::error::rpc::Error>(())
}
.await
{
message
.respond(
bpr::ss::domain::site::CreateSiteResponse {
error: Some(bpr::protobuf::rpc::Error::from(e)),
result: None,
}
.encode_to_vec(),
)
.await?;
}
}
Ok(())
}
async fn update_site(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self
.connection_broker
.queue_subscribe(
bpr::ss::domain::site::SUBJECT_UPDATE_SITE,
self.queue_broker.as_str(),
)
.await?;
while let Some(message) = s.next().await {
if let Err(e) = async {
let req = bpr::ss::domain::site::UpdateSiteRequest::decode(message.data.as_slice())
.map_err(|e| {
bcr::error::rpc::Error::InvalidRequest(bcr::error::rpc::InvalidRequest {
message: format!("invalid request: {}", e),
})
})?;
let id = uuid::Uuid::from_str(req.id.as_str()).map_err(|e| {
bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams {
message: "invalid id param".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "id".to_string(),
value: req.id.clone(),
error_type: bcr::error::rpc::InvalidParamsType::Required,
message: e.to_string(),
},
})
})?;
let client = match req.client {
Some(c) => c,
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid client information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client".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,
})
})?;
let _affected = self
.site_repository
.update(
&conn,
id,
&repositories::site::models::ModifySite {
url: req.url,
name: req.name,
path: req.path,
show: req.show,
can_use: req.can_use,
memo: req.memo,
expires_at: req.expires_at.map(|d| d as i64),
},
)
.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,
})
})?;
let s = self.site_repository.select(&conn, 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,
})
})?;
message
.respond(
bpr::ss::domain::site::UpdateSiteResponse {
error: None,
result: Some(bpr::ss::domain::site::update_site_response::Result {
site: s.map(|d| bpr::models::domain::Site::from(&d)),
}),
}
.encode_to_vec(),
)
.await
.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,
})
})?;
Ok::<(), bcr::error::rpc::Error>(())
}
.await
{
message
.respond(
bpr::ss::domain::site::UpdateSiteResponse {
error: Some(bpr::protobuf::rpc::Error::from(e)),
result: None,
}
.encode_to_vec(),
)
.await?;
}
}
Ok(())
}
async fn delete_site(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self
.connection_broker
.queue_subscribe(
bpr::ss::domain::site::SUBJECT_DELETE_SITE,
self.queue_broker.as_str(),
)
.await?;
while let Some(message) = s.next().await {
if let Err(e) = async {
let req = bpr::ss::domain::site::DeleteSiteRequest::decode(message.data.as_slice())
.map_err(|e| {
bcr::error::rpc::Error::InvalidRequest(bcr::error::rpc::InvalidRequest {
message: format!("invalid request: {}", e),
})
})?;
let id = uuid::Uuid::from_str(req.id.as_str()).map_err(|e| {
bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams {
message: "invalid id param".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "id".to_string(),
value: req.id.clone(),
error_type: bcr::error::rpc::InvalidParamsType::Required,
message: e.to_string(),
},
})
})?;
let client = match req.client {
Some(c) => c,
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid client information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client".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,
})
})?;
let _affected = self.site_repository.delete(&conn, 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,
})
})?;
message
.respond(
bpr::ss::domain::site::DeleteSiteResponse {
error: None,
result: Some(bpr::ss::domain::site::delete_site_response::Result {}),
}
.encode_to_vec(),
)
.await
.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,
})
})?;
Ok::<(), bcr::error::rpc::Error>(())
}
.await
{
message
.respond(
bpr::ss::domain::site::DeleteSiteResponse {
error: Some(bpr::protobuf::rpc::Error::from(e)),
result: None,
}
.encode_to_vec(),
)
.await?;
}
}
Ok(())
}
}

View File

@ -14,7 +14,7 @@ use diesel::{
use prost::Message;
///
pub struct Service {
pub struct Service<'a> {
connection_broker: nats::asynk::Connection,
queue_broker: String,
pool: Pool<ConnectionManager<PgConnection>>,
@ -22,22 +22,25 @@ pub struct Service {
member_composition: compositions::member::composition::Composition,
member_repository: repositories::member::repository::Repository,
member_session_repository: repositories::member_session::repository::Repository,
argon2_config: argon2::Config<'a>,
password_salt: String,
}
impl std::fmt::Debug for Service {
impl std::fmt::Debug for Service<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Service of service.member.service.identity")
.finish()
}
}
impl Service {
impl Service<'_> {
///
pub fn new(
connection_broker: nats::asynk::Connection,
queue_broker: String,
pool: Pool<ConnectionManager<PgConnection>>,
) -> Service {
password_salt: String,
) -> Service<'static> {
Service {
connection_broker,
queue_broker,
@ -46,11 +49,14 @@ impl Service {
member_composition: compositions::member::composition::Composition::new(),
member_repository: repositories::member::repository::Repository::new(),
member_session_repository: repositories::member_session::repository::Repository::new(),
argon2_config: argon2::Config::default(),
password_salt,
}
}
pub async fn subscribe(&self) -> std::result::Result<(), std::boxed::Box<dyn std::error::Error>> {
futures::try_join!(
self.create_member(),
self.list_members(),
self.get_member(),
self.get_member_by_username(),
@ -93,6 +99,254 @@ impl Service {
}
}
async fn create_member(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self
.connection_broker
.queue_subscribe(
bpr::ss::member::member::SUBJECT_CREATE_MEMBER,
self.queue_broker.as_str(),
)
.await?;
while let Some(message) = s.next().await {
if let Err(e) = async {
let req = bpr::ss::member::member::CreateMemberRequest::decode(message.data.as_slice())
.map_err(|e| {
bcr::error::rpc::Error::InvalidRequest(bcr::error::rpc::InvalidRequest {
message: format!("invalid request: {}", e),
})
})?;
let site_id = uuid::Uuid::from_str(req.site_id.as_str()).map_err(|e| {
bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams {
message: "invalid site_id param".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "site_id".to_string(),
value: req.site_id.clone(),
error_type: bcr::error::rpc::InvalidParamsType::Required,
message: e.to_string(),
},
})
})?;
let member_class_id = uuid::Uuid::from_str(req.member_class_id.as_str()).map_err(|e| {
bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams {
message: "invalid member_class_id param".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "member_class_id".to_string(),
value: req.member_class_id.clone(),
error_type: bcr::error::rpc::InvalidParamsType::Required,
message: e.to_string(),
},
})
})?;
let member_level_id = uuid::Uuid::from_str(req.member_level_id.as_str()).map_err(|e| {
bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams {
message: "invalid member_level_id param".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "member_level_id".to_string(),
value: req.member_level_id.clone(),
error_type: bcr::error::rpc::InvalidParamsType::Required,
message: e.to_string(),
},
})
})?;
let client = match req.client {
Some(c) => c,
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid client information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "client".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,
})
})?;
let referrer_member_id = match req.referrer_member_username {
Some(referrer_member_username) => {
match self
.member_repository
.select_by_username(&conn, referrer_member_username.as_str())
.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(m) => Some(m.id),
None => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid referrer_member_username information".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "referrer_member_username".to_string(),
value: referrer_member_username.to_string(),
error_type: bcr::error::rpc::InvalidParamsType::None,
message: "not exist".to_string(),
},
},
));
}
}
}
None => None,
};
match self
.member_repository
.select_by_username(&conn, &req.username)
.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(m) => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid username".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "username".to_string(),
value: req.username.to_string(),
error_type: bcr::error::rpc::InvalidParamsType::None,
message: "duplicated".to_string(),
},
},
));
}
None => {}
};
match self
.member_repository
.select_by_nickname(&conn, &req.nickname)
.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(m) => {
return Err(bcr::error::rpc::Error::InvalidParams(
bcr::error::rpc::InvalidParams {
message: "invalid nickname".to_string(),
detail: bcr::error::rpc::InvalidParamsDetail {
location: "request".to_string(),
param: "nickname".to_string(),
value: req.nickname.to_string(),
error_type: bcr::error::rpc::InvalidParamsType::None,
message: "duplicated".to_string(),
},
},
));
}
None => {}
};
let password_hash = argon2::hash_encoded(
req.password.as_bytes(),
self.password_salt.as_bytes(),
&self.argon2_config,
)
.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,
})
})?;
let new_member = repositories::member::models::NewMember {
site_id,
member_class_id,
member_level_id,
referrer_member_id,
username: req.username,
password: password_hash,
nickname: req.nickname,
mobile_phone_number: req.mobile_phone_number,
};
let m = self
.member_repository
.insert(&conn, &new_member)
.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,
})
})?;
let member = self.member_composition.select(&conn, m.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,
})
})?;
message
.respond(
bpr::ss::member::member::CreateMemberResponse {
error: None,
result: Some(bpr::ss::member::member::create_member_response::Result {
member: member.map(|d| bpr::models::member::MemberModel::from(&d)),
}),
}
.encode_to_vec(),
)
.await
.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,
})
})?;
Ok::<(), bcr::error::rpc::Error>(())
}
.await
{
message
.respond(
bpr::ss::member::member::CreateMemberResponse {
error: Some(bpr::protobuf::rpc::Error::from(e)),
result: None,
}
.encode_to_vec(),
)
.await?;
}
}
Ok(())
}
async fn list_members(&self) -> Result<(), Box<dyn std::error::Error>> {
let s = self
.connection_broker