adds buy/sell endpoints
This commit is contained in:
@@ -121,51 +121,79 @@ impl<'q> AsPlayer<'q> {
|
||||
pub fn loot(self) -> QueryResult<Vec<models::Item>> {
|
||||
Ok(models::Item::owned_by(self.id).load(self.conn)?)
|
||||
}
|
||||
/// Buy an item and add it to this player chest
|
||||
/// TODO: Items should be picked from a custom list
|
||||
/// Buy a batch of items and add them to this player chest
|
||||
///
|
||||
/// Items can only be bought from inventory. Hence, the use
|
||||
/// of the entity's id in 'items' table.
|
||||
///
|
||||
/// # Params
|
||||
/// List of (Item's id in inventory, Option<Price modifier>)
|
||||
///
|
||||
/// # Returns
|
||||
/// Result containing the difference in coins after operation
|
||||
pub fn buy<'a>(self, name: &'a str, price: i32) -> ActionResult<(i32, i32, i32, i32)> {
|
||||
self.conn.transaction(|| {
|
||||
let new_item = models::item::NewLoot::to_player(self.id, (name, price));
|
||||
let _item_added = diesel::insert_into(schema::looted::table)
|
||||
.values(&new_item)
|
||||
.execute(self.conn)
|
||||
.map(|rows_updated| match rows_updated {
|
||||
1 => (),
|
||||
_ => panic!("RuntimeError: Buy made no changes at all"),
|
||||
})?;
|
||||
self.update_wealth(-(price as f32))
|
||||
})
|
||||
pub fn buy<'a>(self, params: &Vec<(i32, Option<f32>)>) -> ActionResult<(i32, i32, i32, i32)> {
|
||||
let mut all_results: Vec<(i32, i32, i32, i32)> = Vec::with_capacity(params.len());
|
||||
for (item_id, price_mod) in params.into_iter() {
|
||||
let res = self.conn.transaction(|| {
|
||||
let item = schema::items::table.find(item_id).first::<models::Item>(self.conn)?;
|
||||
let new_item = models::item::NewLoot::to_player(self.id, (&item.name, item.base_price));
|
||||
let _item_added = diesel::insert_into(schema::looted::table)
|
||||
.values(&new_item)
|
||||
.execute(self.conn)
|
||||
.map(|rows_updated| match rows_updated {
|
||||
1 => (),
|
||||
_ => panic!("RuntimeError: Buy made no changes at all"),
|
||||
})?;
|
||||
let sell_price = match price_mod {
|
||||
Some(modifier) => item.base_price as f32 * modifier,
|
||||
None => item.base_price as f32
|
||||
};
|
||||
DbApi::with_conn(self.conn).as_player(self.id).update_wealth(-sell_price)
|
||||
});
|
||||
if let Ok(diff) = res { all_results.push(diff); }
|
||||
}
|
||||
Ok(all_results.into_iter().fold((0,0,0,0), |sum, diff| {
|
||||
(sum.0 + diff.0, sum.1 + diff.1, sum.2 + diff.2, sum.3 + diff.3)
|
||||
}))
|
||||
}
|
||||
/// Sell an item from this player chest
|
||||
/// Sell a set of items from this player chest
|
||||
///
|
||||
/// # Returns
|
||||
/// Result containing the difference in coins after operation
|
||||
pub fn sell(
|
||||
self,
|
||||
loot_id: i32,
|
||||
price_mod: Option<f32>,
|
||||
params: &Vec<(i32, Option<f32>)>,
|
||||
) -> ActionResult<(i32, i32, i32, i32)> {
|
||||
self.conn.transaction(|| {
|
||||
use schema::looted::dsl::*;
|
||||
let loot = looted
|
||||
.find(loot_id)
|
||||
.first::<models::Loot>(self.conn)?;
|
||||
if loot.owner != self.id {
|
||||
// If the item does not belong to player,
|
||||
// it can't be what we're looking for
|
||||
return Err(diesel::result::Error::NotFound);
|
||||
let mut all_results: Vec<(i32, i32, i32, i32)> = Vec::with_capacity(params.len());
|
||||
for (loot_id, price_mod) in params.into_iter() {
|
||||
let res = self.conn.transaction(|| {
|
||||
use schema::looted::dsl::*;
|
||||
let loot = looted
|
||||
.find(loot_id)
|
||||
.first::<models::Loot>(self.conn)?;
|
||||
if loot.owner != self.id {
|
||||
// If the item does not belong to player,
|
||||
// it can't be what we're looking for
|
||||
return Err(diesel::result::Error::NotFound);
|
||||
}
|
||||
let mut sell_value = loot.base_price as f32 / 2.0;
|
||||
if let Some(modifier) = price_mod {
|
||||
sell_value *= modifier;
|
||||
}
|
||||
let _deleted = diesel::delete(looted.find(loot_id))
|
||||
.execute(self.conn)?;
|
||||
DbApi::with_conn(self.conn).as_player(self.id).update_wealth(sell_value)
|
||||
});
|
||||
if let Ok(diff) = res {
|
||||
all_results.push(diff)
|
||||
} else {
|
||||
// TODO: need to find a better way to deal with errors
|
||||
return Err(diesel::result::Error::NotFound)
|
||||
}
|
||||
let mut sell_value = (loot.base_price / 2) as f32;
|
||||
if let Some(modifier) = price_mod {
|
||||
sell_value *= modifier;
|
||||
}
|
||||
let _deleted = diesel::delete(looted.find(loot_id))
|
||||
.execute(self.conn)?;
|
||||
self.update_wealth(sell_value)
|
||||
})
|
||||
}
|
||||
Ok(all_results.into_iter().fold((0,0,0,0), |sum, diff| {
|
||||
(sum.0 + diff.0, sum.1 + diff.1, sum.2 + diff.2, sum.3 + diff.3)
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
@@ -243,6 +271,13 @@ impl<'q> AsAdmin<'q> {
|
||||
}
|
||||
|
||||
/// Adds a list of items to the group loot
|
||||
///
|
||||
/// This offers complete control other created items, so that unique
|
||||
/// items can be easily added. A user interface shall deal with
|
||||
/// filling theses values for known items in inventory.
|
||||
///
|
||||
/// # Params
|
||||
/// List of (name, base_price) values for the new items
|
||||
pub fn add_loot(self, items: Vec<(&str, i32)>) -> ActionResult<()> {
|
||||
for item_desc in items.into_iter() {
|
||||
let new_item = models::item::NewLoot::to_group(item_desc);
|
||||
@@ -457,6 +492,14 @@ mod tests {
|
||||
#[test]
|
||||
fn as_player_simple_buy_sell() {
|
||||
let conn = test_connection();
|
||||
// Adds a sword into inventory
|
||||
{
|
||||
use schema::items::dsl::*;
|
||||
diesel::insert_into(items)
|
||||
.values((name.eq("Sword"), base_price.eq(800)))
|
||||
.execute(&conn)
|
||||
.expect("Could not set up items table");
|
||||
}
|
||||
DbApi::with_conn(&conn)
|
||||
.as_admin()
|
||||
.add_player("Player", 1000.0)
|
||||
@@ -464,7 +507,7 @@ mod tests {
|
||||
// Buy an item
|
||||
let bought = DbApi::with_conn(&conn)
|
||||
.as_player(1)
|
||||
.buy("Sword", 800);
|
||||
.buy(&vec![(1, None)]);
|
||||
assert_eq!(bought.ok(), Some((0, 0, 0, -8))); // Returns diff of player wealth ?
|
||||
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
|
||||
assert_eq!(chest.len(), 1);
|
||||
@@ -475,10 +518,10 @@ mod tests {
|
||||
let player = players.get(1).unwrap();
|
||||
assert_eq!(player.pp, 2);
|
||||
// A player cannot sell loot from an other's chest
|
||||
let result = DbApi::with_conn(&conn).as_player(0).sell(loot.id, None);
|
||||
let result = DbApi::with_conn(&conn).as_player(0).sell(&vec![(loot.id, None)]);
|
||||
assert_eq!(result.is_ok(), false);
|
||||
// Sell back
|
||||
let sold = DbApi::with_conn(&conn).as_player(1).sell(loot.id, None);
|
||||
let sold = DbApi::with_conn(&conn).as_player(1).sell(&vec![(loot.id, None)]);
|
||||
assert_eq!(sold.ok(), Some((0, 0, 0, 4)));
|
||||
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
|
||||
assert_eq!(chest.len(), 0);
|
||||
|
||||
Reference in New Issue
Block a user