send messages to winners / losers of an auction
This commit is contained in:
@@ -154,7 +154,7 @@ mod tests {
|
|||||||
listing: PersistedListing,
|
listing: PersistedListing,
|
||||||
}
|
}
|
||||||
async fn set_up_fixtures() -> Fixtures {
|
async fn set_up_fixtures() -> Fixtures {
|
||||||
let deps = create_deps().await;
|
let Deps { deps, .. } = create_deps().await;
|
||||||
let seller = with_test_user(&deps, |seller| {
|
let seller = with_test_user(&deps, |seller| {
|
||||||
seller.username = Some("seller".to_string());
|
seller.username = Some("seller".to_string());
|
||||||
seller.telegram_id = 123.into()
|
seller.telegram_id = 123.into()
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ async fn handle_view_listing_bids(
|
|||||||
response_lines.push(format!(
|
response_lines.push(format!(
|
||||||
"💰 Current highest bid: <b>{current_bid}</b> from {buyer_name}",
|
"💰 Current highest bid: <b>{current_bid}</b> from {buyer_name}",
|
||||||
current_bid = current_bid.bid_amount.with_type(currency_type),
|
current_bid = current_bid.bid_amount.with_type(currency_type),
|
||||||
buyer_name = user_name_or_link(&buyer)
|
buyer_name = user_name_or_link(buyer)
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
response_lines.push("💰 No bids yet".to_string());
|
response_lines.push("💰 No bids yet".to_string());
|
||||||
@@ -181,7 +181,7 @@ async fn handle_view_listing_bids(
|
|||||||
response_lines.push(format!(
|
response_lines.push(format!(
|
||||||
"💰 Bid: <b>{bid_amount}</b> from {buyer_name}",
|
"💰 Bid: <b>{bid_amount}</b> from {buyer_name}",
|
||||||
bid_amount = bid.bid_amount.with_type(currency_type),
|
bid_amount = bid.bid_amount.with_type(currency_type),
|
||||||
buyer_name = user_name_or_link(&bidder)
|
buyer_name = user_name_or_link(bidder)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ use crate::{
|
|||||||
BotError, BotResult, MessageTarget,
|
BotError, BotResult, MessageTarget,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct BotMessageSender(Bot, MessageTarget);
|
pub struct BotMessageSender(Bot, Option<MessageTarget>);
|
||||||
impl BotMessageSender {
|
impl BotMessageSender {
|
||||||
pub fn new(bot: Bot, message_target: MessageTarget) -> Self {
|
pub fn new(bot: Bot, message_target: Option<MessageTarget>) -> Self {
|
||||||
Self(bot, message_target)
|
Self(bot, message_target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ impl BotMessageSender {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl MessageSender for BotMessageSender {
|
impl MessageSender for BotMessageSender {
|
||||||
fn with_target(&self, target: MessageTarget) -> BoxedMessageSender {
|
fn with_target(&self, target: MessageTarget) -> BoxedMessageSender {
|
||||||
let clone = Self(self.0.clone(), target);
|
let clone = Self(self.0.clone(), Some(target));
|
||||||
Box::new(clone)
|
Box::new(clone)
|
||||||
}
|
}
|
||||||
async fn send_html_message(
|
async fn send_html_message(
|
||||||
@@ -34,7 +34,10 @@ impl MessageSender for BotMessageSender {
|
|||||||
text: String,
|
text: String,
|
||||||
keyboard: Option<InlineKeyboardMarkup>,
|
keyboard: Option<InlineKeyboardMarkup>,
|
||||||
) -> BotResult {
|
) -> BotResult {
|
||||||
let target = self.1.clone();
|
let target = self
|
||||||
|
.1
|
||||||
|
.clone()
|
||||||
|
.ok_or(BotError::internal_str("No message target"))?;
|
||||||
if let Some(message_id) = target.message_id {
|
if let Some(message_id) = target.message_id {
|
||||||
log::info!("Editing message in chat: {target:?}");
|
log::info!("Editing message in chat: {target:?}");
|
||||||
let mut message = self
|
let mut message = self
|
||||||
@@ -107,6 +110,36 @@ impl MessageSender for BotMessageSender {
|
|||||||
self.send_bid_invalid_listing_expired(listing, buyer)
|
self.send_bid_invalid_listing_expired(listing, buyer)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
MessageType::UserHasWonListingForSeller {
|
||||||
|
listing,
|
||||||
|
buyer,
|
||||||
|
seller,
|
||||||
|
bid,
|
||||||
|
} => {
|
||||||
|
self.send_user_has_won_listing_for_seller(listing, buyer, seller, bid)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
MessageType::UserHasWonListingForBuyer {
|
||||||
|
listing,
|
||||||
|
buyer,
|
||||||
|
seller,
|
||||||
|
bid,
|
||||||
|
} => {
|
||||||
|
self.send_user_has_won_listing_for_buyer(listing, buyer, seller, bid)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
MessageType::UserHasLostListingForBuyer {
|
||||||
|
listing,
|
||||||
|
buyer,
|
||||||
|
seller,
|
||||||
|
} => {
|
||||||
|
self.send_user_has_lost_listing_for_buyer(listing, buyer, seller)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
MessageType::ListingExpiredWithNoWinnerForSeller { listing, seller } => {
|
||||||
|
self.send_listing_expired_with_no_winner_for_seller(listing, seller)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -186,4 +219,78 @@ impl BotMessageSender {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn send_user_has_won_listing_for_seller(
|
||||||
|
&self,
|
||||||
|
listing: PersistedListing,
|
||||||
|
buyer: PersistedUser,
|
||||||
|
seller: PersistedUser,
|
||||||
|
bid: PersistedBid,
|
||||||
|
) -> BotResult {
|
||||||
|
self.with_target(seller.into())
|
||||||
|
.send_html_message(
|
||||||
|
format!(
|
||||||
|
"<b>{buyer}</b> has won {title} for <b>{bid_amount}</b>",
|
||||||
|
buyer = user_name_or_link(&buyer),
|
||||||
|
title = listing.base.title,
|
||||||
|
bid_amount = bid.bid_amount.with_type(listing.base.currency_type),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_user_has_won_listing_for_buyer(
|
||||||
|
&self,
|
||||||
|
listing: PersistedListing,
|
||||||
|
buyer: PersistedUser,
|
||||||
|
seller: PersistedUser,
|
||||||
|
bid: PersistedBid,
|
||||||
|
) -> BotResult {
|
||||||
|
self.with_target(buyer.into())
|
||||||
|
.send_html_message(
|
||||||
|
format!(
|
||||||
|
"You have won {title} by {seller} for <b>{bid_amount}</b>",
|
||||||
|
title = listing.base.title,
|
||||||
|
seller = user_name_or_link(&seller),
|
||||||
|
bid_amount = bid.bid_amount.with_type(listing.base.currency_type),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_user_has_lost_listing_for_buyer(
|
||||||
|
&self,
|
||||||
|
listing: PersistedListing,
|
||||||
|
buyer: PersistedUser,
|
||||||
|
seller: PersistedUser,
|
||||||
|
) -> BotResult {
|
||||||
|
self.with_target(buyer.into())
|
||||||
|
.send_html_message(
|
||||||
|
format!(
|
||||||
|
"Auction {title} by {seller} has ended, and you were not the winner",
|
||||||
|
title = listing.base.title,
|
||||||
|
seller = user_name_or_link(&seller),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_listing_expired_with_no_winner_for_seller(
|
||||||
|
&self,
|
||||||
|
listing: PersistedListing,
|
||||||
|
seller: PersistedUser,
|
||||||
|
) -> BotResult {
|
||||||
|
self.with_target(seller.into())
|
||||||
|
.send_html_message(
|
||||||
|
format!(
|
||||||
|
"Auction {title} has ended with no winner",
|
||||||
|
title = listing.base.title
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ impl ListingDAO {
|
|||||||
pub async fn insert_listing(&self, listing: &NewListing) -> Result<PersistedListing> {
|
pub async fn insert_listing(&self, listing: &NewListing) -> Result<PersistedListing> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
|
|
||||||
let binds = binds_for_listing(&listing)
|
let binds = binds_for_listing(listing)
|
||||||
.push("seller_id", &listing.base.seller_id)
|
.push("seller_id", &listing.base.seller_id)
|
||||||
.push("starts_at", &listing.base.starts_at)
|
.push("starts_at", &listing.base.starts_at)
|
||||||
.push("ends_at", &listing.base.ends_at)
|
.push("ends_at", &listing.base.ends_at)
|
||||||
@@ -89,7 +89,7 @@ impl ListingDAO {
|
|||||||
|
|
||||||
pub async fn update_listing(&self, listing: &PersistedListing) -> Result<PersistedListing> {
|
pub async fn update_listing(&self, listing: &PersistedListing) -> Result<PersistedListing> {
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let binds = binds_for_listing(&listing).push("updated_at", &now);
|
let binds = binds_for_listing(listing).push("updated_at", &now);
|
||||||
|
|
||||||
let query_str = format!(
|
let query_str = format!(
|
||||||
r#"
|
r#"
|
||||||
|
|||||||
@@ -5,9 +5,13 @@ use crate::{
|
|||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn task(daos: DAOs, mut listing_event: Receiver<ListingUpdatedEvent>) -> BotResult<()> {
|
pub async fn task(
|
||||||
|
message_sender: BoxedMessageSender,
|
||||||
|
daos: DAOs,
|
||||||
|
mut listing_event: Receiver<ListingUpdatedEvent>,
|
||||||
|
) -> BotResult<()> {
|
||||||
loop {
|
loop {
|
||||||
match task_impl(daos.clone(), &mut listing_event).await {
|
match task_impl(&message_sender, &daos, &mut listing_event).await {
|
||||||
Ok(r) => return Ok(r),
|
Ok(r) => return Ok(r),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error in listing expiry checker task: {e}");
|
log::error!("Error in listing expiry checker task: {e}");
|
||||||
@@ -17,13 +21,17 @@ pub async fn task(daos: DAOs, mut listing_event: Receiver<ListingUpdatedEvent>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn task_impl(daos: DAOs, listing_event: &mut Receiver<ListingUpdatedEvent>) -> BotResult<()> {
|
async fn task_impl(
|
||||||
|
message_sender: &BoxedMessageSender,
|
||||||
|
daos: &DAOs,
|
||||||
|
listing_event: &mut Receiver<ListingUpdatedEvent>,
|
||||||
|
) -> BotResult<()> {
|
||||||
const MAX_CHECK_INTERVAL: Duration = Duration::seconds(10);
|
const MAX_CHECK_INTERVAL: Duration = Duration::seconds(10);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let check_again_in =
|
let check_again_in =
|
||||||
if let Some(listing) = daos.listing.find_next_ending_listing().await? {
|
if let Some(listing) = daos.listing.find_next_ending_listing().await? {
|
||||||
if handle_listing_expiry(&daos, &listing).await? {
|
if handle_listing_expiry(message_sender, daos, &listing).await? {
|
||||||
// if this listing was expired, immediately check again on the next listing
|
// if this listing was expired, immediately check again on the next listing
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -48,17 +56,184 @@ async fn task_impl(daos: DAOs, listing_event: &mut Receiver<ListingUpdatedEvent>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_listing_expiry(daos: &DAOs, listing: &PersistedListing) -> BotResult<bool> {
|
async fn handle_listing_expiry(
|
||||||
|
message_sender: &BoxedMessageSender,
|
||||||
|
daos: &DAOs,
|
||||||
|
listing: &PersistedListing,
|
||||||
|
) -> BotResult<bool> {
|
||||||
if listing.base.ends_at < Utc::now() {
|
if listing.base.ends_at < Utc::now() {
|
||||||
let expired_ago = Utc::now() - listing.base.ends_at;
|
let expired_ago = Utc::now() - listing.base.ends_at;
|
||||||
log::info!(
|
log::info!(
|
||||||
"listing expired: {listing_id} (expired {expired_ago} ago)",
|
"listing expired: {listing_id} (expired {expired_ago} ago)",
|
||||||
listing_id = listing.persisted.id,
|
listing_id = listing.persisted.id,
|
||||||
);
|
);
|
||||||
daos.listing
|
let listing = daos
|
||||||
|
.listing
|
||||||
.set_listing_is_active(listing.persisted.id, false)
|
.set_listing_is_active(listing.persisted.id, false)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let seller = daos
|
||||||
|
.user
|
||||||
|
.find_by_id(listing.base.seller_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(BotError::internal_str("Seller not found"))?;
|
||||||
|
|
||||||
|
let bids = daos.bid.bids_for_listing(listing.persisted.id).await?;
|
||||||
|
|
||||||
|
if let Some(bid) = bids.first() {
|
||||||
|
let buyer = daos
|
||||||
|
.user
|
||||||
|
.find_by_id(bid.buyer_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(BotError::internal_str("Winning buyer not found"))?;
|
||||||
|
|
||||||
|
message_sender
|
||||||
|
.send_message(MessageType::UserHasWonListingForBuyer {
|
||||||
|
listing: listing.clone(),
|
||||||
|
buyer: buyer.clone(),
|
||||||
|
seller: seller.clone(),
|
||||||
|
bid: bid.clone(),
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
message_sender
|
||||||
|
.send_message(MessageType::UserHasWonListingForSeller {
|
||||||
|
listing: listing.clone(),
|
||||||
|
buyer: buyer.clone(),
|
||||||
|
seller: seller.clone(),
|
||||||
|
bid: bid.clone(),
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// send message to all other buyers who did not win
|
||||||
|
for bid in bids.iter() {
|
||||||
|
if bid.buyer_id == buyer.persisted.id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let buyer = daos
|
||||||
|
.user
|
||||||
|
.find_by_id(bid.buyer_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(BotError::internal_str("Losing buyer not found"))?;
|
||||||
|
message_sender
|
||||||
|
.send_message(MessageType::UserHasLostListingForBuyer {
|
||||||
|
listing: listing.clone(),
|
||||||
|
buyer: buyer.clone(),
|
||||||
|
seller: seller.clone(),
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// there was no winner, send notification to the seller
|
||||||
|
message_sender
|
||||||
|
.send_message(MessageType::ListingExpiredWithNoWinnerForSeller {
|
||||||
|
listing: listing.clone(),
|
||||||
|
seller: seller.clone(),
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::db::bid::NewBid;
|
||||||
|
use crate::db::MoneyAmount;
|
||||||
|
use crate::message_sender::MockMessageSender;
|
||||||
|
use crate::test_utils::*;
|
||||||
|
use mockall::predicate::function;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_listing_expiry() {
|
||||||
|
let Deps { deps, .. } = create_deps().await;
|
||||||
|
let seller = with_test_user(&deps, |user| {
|
||||||
|
user.telegram_id = 123.into();
|
||||||
|
user.username = Some("seller".to_string())
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
let losing_buyer = with_test_user(&deps, |user| {
|
||||||
|
user.telegram_id = 789.into();
|
||||||
|
user.username = Some("losing_buyer".to_string())
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
let winning_buyer = with_test_user(&deps, |user| {
|
||||||
|
user.telegram_id = 456.into();
|
||||||
|
user.username = Some("buyer".to_string())
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
let listing = with_test_listing(&deps, &seller, |listing| {
|
||||||
|
listing.base.ends_at = Utc::now() - Duration::seconds(1);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// the losing bid
|
||||||
|
deps.get::<DAOs>()
|
||||||
|
.bid
|
||||||
|
.insert_bid(&NewBid::new_basic(
|
||||||
|
listing.persisted.id,
|
||||||
|
losing_buyer.persisted.id,
|
||||||
|
MoneyAmount::from_str("50.00").unwrap(),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// the winning bid
|
||||||
|
deps.get::<DAOs>()
|
||||||
|
.bid
|
||||||
|
.insert_bid(&NewBid::new_basic(
|
||||||
|
listing.persisted.id,
|
||||||
|
winning_buyer.persisted.id,
|
||||||
|
MoneyAmount::from_str("100.00").unwrap(),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let winner_id = winning_buyer.persisted.id;
|
||||||
|
let loser_id = losing_buyer.persisted.id;
|
||||||
|
let mut message_sender = MockMessageSender::new();
|
||||||
|
|
||||||
|
message_sender
|
||||||
|
.expect_send_message()
|
||||||
|
.with(function(move |m| match m {
|
||||||
|
MessageType::UserHasWonListingForSeller { buyer, .. } => {
|
||||||
|
buyer.persisted.id == winner_id
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| Ok(()));
|
||||||
|
|
||||||
|
message_sender
|
||||||
|
.expect_send_message()
|
||||||
|
.with(function(move |m| match m {
|
||||||
|
MessageType::UserHasWonListingForBuyer { buyer, .. } => {
|
||||||
|
buyer.persisted.id == winner_id
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| Ok(()));
|
||||||
|
|
||||||
|
message_sender
|
||||||
|
.expect_send_message()
|
||||||
|
.with(function(move |m| match m {
|
||||||
|
MessageType::UserHasLostListingForBuyer { buyer, .. } => {
|
||||||
|
buyer.persisted.id == loser_id
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| Ok(()));
|
||||||
|
|
||||||
|
let daos = (*deps.get::<DAOs>()).clone();
|
||||||
|
let message_sender: BoxedMessageSender = Box::new(message_sender);
|
||||||
|
handle_listing_expiry(&message_sender, &daos, &listing)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ async fn main() -> Result<()> {
|
|||||||
let daos = DAOs::new(db_pool.clone(), listing_expiry_checker_tx);
|
let daos = DAOs::new(db_pool.clone(), listing_expiry_checker_tx);
|
||||||
|
|
||||||
tokio::spawn(listing_expiry_checker_task::task(
|
tokio::spawn(listing_expiry_checker_task::task(
|
||||||
|
Box::new(BotMessageSender::new(*bot.clone(), None)),
|
||||||
daos.clone(),
|
daos.clone(),
|
||||||
listing_expiry_checker_rx,
|
listing_expiry_checker_rx,
|
||||||
));
|
));
|
||||||
@@ -203,7 +204,7 @@ async fn main() -> Result<()> {
|
|||||||
|bot: Box<Bot>, update: Update, daos: DAOs, bot_username: BotUsername| {
|
|bot: Box<Bot>, update: Update, daos: DAOs, bot_username: BotUsername| {
|
||||||
let target = update_into_message_target(update)?;
|
let target = update_into_message_target(update)?;
|
||||||
Some(App::new(
|
Some(App::new(
|
||||||
Box::new(BotMessageSender::new(*bot, target)),
|
Box::new(BotMessageSender::new(*bot, Some(target))),
|
||||||
daos.clone(),
|
daos.clone(),
|
||||||
bot_username.0,
|
bot_username.0,
|
||||||
))
|
))
|
||||||
@@ -278,7 +279,8 @@ mod tests {
|
|||||||
always(),
|
always(),
|
||||||
)
|
)
|
||||||
.returning(|_, _| Ok(()));
|
.returning(|_, _| Ok(()));
|
||||||
let mut deps = with_message_sender(create_deps().await, message_sender).await;
|
let Deps { deps, .. } = create_deps().await;
|
||||||
|
let mut deps = with_message_sender(deps, message_sender).await;
|
||||||
deps.insert(create_tele_update("/help"));
|
deps.insert(create_tele_update("/help"));
|
||||||
let handler = main_handler();
|
let handler = main_handler();
|
||||||
dptree::type_check(handler.sig(), &deps, &[]);
|
dptree::type_check(handler.sig(), &deps, &[]);
|
||||||
|
|||||||
@@ -20,4 +20,25 @@ pub enum MessageType {
|
|||||||
listing: PersistedListing,
|
listing: PersistedListing,
|
||||||
buyer: PersistedUser,
|
buyer: PersistedUser,
|
||||||
},
|
},
|
||||||
|
UserHasWonListingForSeller {
|
||||||
|
listing: PersistedListing,
|
||||||
|
seller: PersistedUser,
|
||||||
|
buyer: PersistedUser,
|
||||||
|
bid: PersistedBid,
|
||||||
|
},
|
||||||
|
UserHasWonListingForBuyer {
|
||||||
|
listing: PersistedListing,
|
||||||
|
buyer: PersistedUser,
|
||||||
|
seller: PersistedUser,
|
||||||
|
bid: PersistedBid,
|
||||||
|
},
|
||||||
|
UserHasLostListingForBuyer {
|
||||||
|
listing: PersistedListing,
|
||||||
|
buyer: PersistedUser,
|
||||||
|
seller: PersistedUser,
|
||||||
|
},
|
||||||
|
ListingExpiredWithNoWinnerForSeller {
|
||||||
|
listing: PersistedListing,
|
||||||
|
seller: PersistedUser,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use sqlx::SqlitePool;
|
|||||||
use std::{ops::Deref, str::FromStr, sync::Arc};
|
use std::{ops::Deref, str::FromStr, sync::Arc};
|
||||||
use teloxide::dispatching::dialogue::serializer::Json;
|
use teloxide::dispatching::dialogue::serializer::Json;
|
||||||
use teloxide::types::*;
|
use teloxide::types::*;
|
||||||
|
use tokio::sync::mpsc::Receiver;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{
|
db::{
|
||||||
@@ -15,7 +16,8 @@ use crate::{
|
|||||||
NewListing, PersistedListing,
|
NewListing, PersistedListing,
|
||||||
},
|
},
|
||||||
user::{NewUser, PersistedUser},
|
user::{NewUser, PersistedUser},
|
||||||
CurrencyType, DAOs, ListingDAO, ListingEventSender, MoneyAmount, UserDAO,
|
CurrencyType, DAOs, ListingDAO, ListingEventSender, ListingUpdatedEvent, MoneyAmount,
|
||||||
|
UserDAO,
|
||||||
},
|
},
|
||||||
message_sender::MockMessageSender,
|
message_sender::MockMessageSender,
|
||||||
sqlite_storage::SqliteStorage,
|
sqlite_storage::SqliteStorage,
|
||||||
@@ -202,7 +204,11 @@ pub fn create_tele_callback_query(callback_data: &str, from: User) -> CallbackQu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_deps() -> DependencyMap {
|
pub struct Deps {
|
||||||
|
pub deps: DependencyMap,
|
||||||
|
pub listing_event_receiver: Receiver<ListingUpdatedEvent>,
|
||||||
|
}
|
||||||
|
pub async fn create_deps() -> Deps {
|
||||||
let pool = create_test_pool().await;
|
let pool = create_test_pool().await;
|
||||||
let dialog_storage = SqliteStorage::new(pool.clone(), Json).await.unwrap();
|
let dialog_storage = SqliteStorage::new(pool.clone(), Json).await.unwrap();
|
||||||
let (tx, rx) = ListingEventSender::channel();
|
let (tx, rx) = ListingEventSender::channel();
|
||||||
@@ -216,7 +222,10 @@ pub async fn create_deps() -> DependencyMap {
|
|||||||
can_connect_to_business: true,
|
can_connect_to_business: true,
|
||||||
has_main_web_app: true,
|
has_main_web_app: true,
|
||||||
};
|
};
|
||||||
dptree::deps![dialog_storage, me, daos, rx]
|
Deps {
|
||||||
|
deps: dptree::deps![dialog_storage, me, daos],
|
||||||
|
listing_event_receiver: rx,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn with_dialogue(mut deps: DependencyMap, user: &PersistedUser) -> DependencyMap {
|
pub async fn with_dialogue(mut deps: DependencyMap, user: &PersistedUser) -> DependencyMap {
|
||||||
@@ -240,19 +249,6 @@ pub async fn with_message_sender(
|
|||||||
deps
|
deps
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_test_user(dao: &UserDAO) -> PersistedUser {
|
|
||||||
dao.insert_user(&NewUser {
|
|
||||||
persisted: (),
|
|
||||||
telegram_id: 12345.into(),
|
|
||||||
first_name: "Test User".to_string(),
|
|
||||||
last_name: None,
|
|
||||||
username: Some("testuser".to_string()),
|
|
||||||
is_banned: false,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn with_test_user(
|
pub async fn with_test_user(
|
||||||
deps: &DependencyMap,
|
deps: &DependencyMap,
|
||||||
user_fn: impl FnOnce(&mut NewUser) -> (),
|
user_fn: impl FnOnce(&mut NewUser) -> (),
|
||||||
|
|||||||
Reference in New Issue
Block a user