Compare commits
2 Commits
1f2a940968
...
ee0b7b2b7a
| Author | SHA1 | Date | |
|---|---|---|---|
| ee0b7b2b7a | |||
| 089aaf9a6d |
@@ -18,9 +18,9 @@ mod schema;
|
||||
|
||||
pub use models::{
|
||||
claim::{Claim, Claims},
|
||||
item::{Item, LootManager, Inventory},
|
||||
player::{Player, Wealth, Players, AsPlayer},
|
||||
history::{Event, UpdateList},
|
||||
item::{Inventory, Item, LootManager},
|
||||
player::{AsPlayer, Player, Players, Wealth},
|
||||
};
|
||||
|
||||
/// The connection used
|
||||
@@ -29,6 +29,7 @@ pub type DbConnection = SqliteConnection;
|
||||
pub type Pool = r2d2::Pool<ConnectionManager<DbConnection>>;
|
||||
/// The result of a query on DB
|
||||
pub type QueryResult<T> = Result<T, diesel::result::Error>;
|
||||
pub type UpdateResult = QueryResult<Update>;
|
||||
|
||||
/// Sets up a connection pool and returns it.
|
||||
/// Uses the DATABASE_URL environment variable (must be set)
|
||||
@@ -41,7 +42,6 @@ pub fn create_pool() -> Pool {
|
||||
.expect("Failed to create pool.")
|
||||
}
|
||||
|
||||
|
||||
/// Every possible update which can happen during a query
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Update {
|
||||
@@ -54,24 +54,25 @@ pub enum Update {
|
||||
|
||||
impl Update {
|
||||
/// Change back what has been updated
|
||||
fn undo(&self, conn: &DbConnection, id: i32) -> QueryResult<Self> {
|
||||
fn undo(&self, conn: &DbConnection, id: i32) -> UpdateResult {
|
||||
Ok(match self {
|
||||
Update::Wealth(diff) => {
|
||||
Update::Wealth(AsPlayer(conn, id).update_wealth(-diff.to_gp())?)
|
||||
},
|
||||
Update::ItemAdded(item) => {
|
||||
Update::ItemRemoved(LootManager(conn, id).remove(item.id)?)
|
||||
},
|
||||
Update::ItemRemoved(item) => {
|
||||
Update::ItemAdded(LootManager(conn, id).add_from(&item)?)
|
||||
},
|
||||
Update::Wealth(diff) => AsPlayer(conn, id).update_wealth(-diff.to_gp())?,
|
||||
Update::ItemAdded(item) => LootManager(conn, id).find(item.id)?.remove(conn)?,
|
||||
Update::ItemRemoved(item) => LootManager(conn, id).add_from(&item)?,
|
||||
// Unused for now
|
||||
Update::ClaimAdded(claim) => { Update::ClaimRemoved(*claim) },
|
||||
Update::ClaimRemoved(claim) => { Update::ClaimAdded(*claim) },
|
||||
Update::ClaimAdded(claim) => Update::ClaimRemoved(*claim),
|
||||
Update::ClaimRemoved(claim) => Update::ClaimAdded(*claim),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: use this to wrap update in UpdateResult, allowing unified interface
|
||||
/// whether a query makes multiple updates or just one.
|
||||
enum OneOrMore {
|
||||
One(Update),
|
||||
More(Vec<Update>),
|
||||
}
|
||||
|
||||
/// Every value which can be queried
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
@@ -107,17 +108,19 @@ pub fn sell_item_transaction(
|
||||
id: i32,
|
||||
loot_id: i32,
|
||||
price_mod: Option<f64>,
|
||||
) -> QueryResult<(Item, Wealth)> {
|
||||
) -> QueryResult<(Update, Wealth)> {
|
||||
conn.transaction(|| {
|
||||
let deleted = LootManager(conn, id)
|
||||
.remove(loot_id)?;
|
||||
let mut sell_value = deleted.sell_value() as f64;
|
||||
let to_delete = LootManager(conn, id).find(loot_id)?;
|
||||
let mut sell_value = to_delete.sell_value() as f64;
|
||||
if let Some(modifier) = price_mod {
|
||||
sell_value *= modifier;
|
||||
}
|
||||
let wealth = AsPlayer(conn, id)
|
||||
.update_wealth(sell_value)?;
|
||||
Ok((deleted, wealth))
|
||||
let deleted = to_delete.remove(conn)?;
|
||||
if let Update::Wealth(wealth) = AsPlayer(conn, id).update_wealth(sell_value)? {
|
||||
Ok((deleted, wealth))
|
||||
} else {
|
||||
Err(diesel::result::Error::RollbackTransaction)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -131,7 +134,7 @@ pub fn buy_item_from_inventory(
|
||||
id: i32,
|
||||
item_id: i32,
|
||||
price_mod: Option<f64>,
|
||||
) -> QueryResult<(Item, Wealth)> {
|
||||
) -> QueryResult<(Update, Wealth)> {
|
||||
conn.transaction(|| {
|
||||
// Find item in inventory
|
||||
let item = Inventory(conn).find(item_id)?;
|
||||
@@ -140,9 +143,11 @@ pub fn buy_item_from_inventory(
|
||||
Some(modifier) => item.value() as f64 * modifier,
|
||||
None => item.value() as f64,
|
||||
};
|
||||
AsPlayer(conn, id)
|
||||
.update_wealth(-sell_price)
|
||||
.map(|diff| (new_item, diff))
|
||||
if let Update::Wealth(diff) = AsPlayer(conn, id).update_wealth(-sell_price)? {
|
||||
Ok((new_item, diff))
|
||||
} else {
|
||||
Err(diesel::result::Error::RollbackTransaction)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -161,35 +166,39 @@ pub fn resolve_claims(conn: &DbConnection) -> QueryResult<()> {
|
||||
for (item, mut claims) in data {
|
||||
if claims.len() > 1 {
|
||||
// TODO: better sorting mechanism :)
|
||||
claims.sort_by(|a,b| a.resolve.cmp(&b.resolve));
|
||||
claims.sort_by(|a, b| a.resolve.cmp(&b.resolve));
|
||||
}
|
||||
let winner = claims.get(0).expect("Claims should not be empty !");
|
||||
let player_id = winner.player_id;
|
||||
winner.resolve_claim(conn)?;
|
||||
models::player::AsPlayer(conn, player_id)
|
||||
.update_debt(item.sell_value())?;
|
||||
winner.resolve_claim(conn)?;
|
||||
models::player::AsPlayer(conn, player_id).update_debt(item.sell_value())?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Split up and share group money among selected players
|
||||
pub fn split_and_share(conn: &DbConnection, amount: i32, players: Vec<i32>) -> QueryResult<Wealth> {
|
||||
pub fn split_and_share(
|
||||
conn: &DbConnection,
|
||||
amount: i32,
|
||||
players: &Vec<i32>,
|
||||
) -> QueryResult<Wealth> {
|
||||
let share = (
|
||||
amount / (players.len() + 1) as i32 // +1 share for the group
|
||||
amount / (players.len() + 1) as i32
|
||||
// +1 share for the group
|
||||
) as f64;
|
||||
conn.transaction(|| {
|
||||
for p in players.into_iter() {
|
||||
let player = Players(conn).find(p)?;
|
||||
for p in players {
|
||||
let player = Players(conn).find(*p)?;
|
||||
// Take debt into account
|
||||
match share - player.debt as f64 {
|
||||
rest if rest > 0.0 => {
|
||||
AsPlayer(conn, p).update_debt(-player.debt)?;
|
||||
AsPlayer(conn, p).update_wealth(rest)?;
|
||||
AsPlayer(conn, *p).update_debt(-player.debt)?;
|
||||
AsPlayer(conn, *p).update_wealth(rest)?;
|
||||
AsPlayer(conn, 0).update_wealth(-rest)?;
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
AsPlayer(conn, p).update_debt(-share as i32)?;
|
||||
AsPlayer(conn, *p).update_debt(-share as i32)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use diesel::expression::exists::Exists;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::schema::{items, looted};
|
||||
use crate::{DbConnection, QueryResult};
|
||||
use crate::{DbConnection, QueryResult, Update, UpdateResult };
|
||||
type ItemColumns = (looted::id, looted::name, looted::base_price);
|
||||
const ITEM_COLUMNS: ItemColumns = (looted::id, looted::name, looted::base_price);
|
||||
type OwnedBy = Select<OwnedLoot, ItemColumns>;
|
||||
@@ -27,6 +27,11 @@ impl Item {
|
||||
self.base_price / 2
|
||||
}
|
||||
|
||||
pub fn remove(self, conn: &DbConnection) -> UpdateResult {
|
||||
diesel::delete(looted::table.find(self.id)).execute(conn)?;
|
||||
Ok(Update::ItemRemoved(self))
|
||||
}
|
||||
|
||||
fn owned_by(player: i32) -> OwnedBy {
|
||||
Loot::owned_by(player).select(ITEM_COLUMNS)
|
||||
}
|
||||
@@ -124,7 +129,7 @@ impl<'q> LootManager<'q> {
|
||||
.first(self.0)?)
|
||||
}
|
||||
|
||||
pub(crate) fn add<S: Into<String>>(self, name: S, base_price: i32) -> QueryResult<Item> {
|
||||
pub(crate) fn add<S: Into<String>>(self, name: S, base_price: i32) -> UpdateResult {
|
||||
self.add_from(&Item {
|
||||
id: 0,
|
||||
name: name.into(),
|
||||
@@ -133,7 +138,7 @@ impl<'q> LootManager<'q> {
|
||||
}
|
||||
|
||||
/// Adds a copy of the given item inside player chest
|
||||
pub fn add_from(self, item: &Item) -> QueryResult<Item> {
|
||||
pub fn add_from(self, item: &Item) -> UpdateResult {
|
||||
let new_item = NewLoot {
|
||||
name: &item.name,
|
||||
base_price: item.base_price,
|
||||
@@ -142,13 +147,7 @@ impl<'q> LootManager<'q> {
|
||||
diesel::insert_into(looted::table)
|
||||
.values(&new_item)
|
||||
.execute(self.0)?;
|
||||
self.last()
|
||||
}
|
||||
|
||||
pub fn remove(self, item_id: i32) -> QueryResult<Item> {
|
||||
let deleted = self.find(item_id)?;
|
||||
diesel::delete(looted::table.find(deleted.id)).execute(self.0)?;
|
||||
Ok(deleted)
|
||||
Ok(Update::ItemAdded(self.last()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::schema::players;
|
||||
use crate::{DbConnection, QueryResult};
|
||||
use crate::{DbConnection, QueryResult, Update, UpdateResult};
|
||||
use diesel::prelude::*;
|
||||
|
||||
mod notification;
|
||||
@@ -50,10 +50,7 @@ impl<'q> Players<'q> {
|
||||
|
||||
/// Notify all players of an event
|
||||
pub fn notifiy_all(&self, text: &str) -> QueryResult<()> {
|
||||
for id in self.all()?
|
||||
.into_iter()
|
||||
.map(|p| p.id)
|
||||
{
|
||||
for id in self.all()?.into_iter().map(|p| p.id) {
|
||||
self.notify(id, text);
|
||||
}
|
||||
Ok(())
|
||||
@@ -75,7 +72,7 @@ impl<'q> AsPlayer<'q> {
|
||||
notification::pop_all_for(self.1, self.0)
|
||||
}
|
||||
/// Updates this player's wealth, returning the difference
|
||||
pub fn update_wealth(&self, value_in_gp: f64) -> QueryResult<Wealth> {
|
||||
pub fn update_wealth(&self, value_in_gp: f64) -> UpdateResult {
|
||||
use crate::schema::players::dsl::*;
|
||||
let current_wealth = players
|
||||
.find(self.1)
|
||||
@@ -86,7 +83,7 @@ impl<'q> AsPlayer<'q> {
|
||||
.filter(id.eq(self.1))
|
||||
.set(&updated_wealth)
|
||||
.execute(self.0)?;
|
||||
Ok(updated_wealth - current_wealth)
|
||||
Ok(Update::Wealth(updated_wealth - current_wealth))
|
||||
}
|
||||
|
||||
/// Updates this player's debt
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<PlayerView
|
||||
:id="player_id"
|
||||
:players="playersId"
|
||||
v-slot="{ player, loot, notifications, actions, claims }"
|
||||
>
|
||||
<main id="app" class="container">
|
||||
@@ -142,7 +143,7 @@ export default {
|
||||
api.fetch("items", "GET", null),
|
||||
])
|
||||
.then(([players, loot, items]) => {
|
||||
this.playerList = players.value;
|
||||
this.$set(this, 'playerList', players.value);
|
||||
this.groupLoot = loot.value;
|
||||
this.itemsInventory = items.value;
|
||||
})
|
||||
@@ -177,6 +178,7 @@ export default {
|
||||
showPlayerChest () { return this.activeView == 'player' },
|
||||
isAdding () { return this.activeView == 'adding' },
|
||||
playerIsGroup () { return this.player_id == 0 },
|
||||
playersId () { return this.playerList.map(p => p.id).filter(i => i != 0); }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { api } from '../lootalot.js'
|
||||
|
||||
export default {
|
||||
props: ["id"],
|
||||
props: ["id", "players"],
|
||||
data () { return {
|
||||
player: {
|
||||
name: "Loading",
|
||||
@@ -76,7 +76,15 @@ export default {
|
||||
putClaim (itemId) { this.call("claims", "PUT", itemId) },
|
||||
withdrawClaim (itemId) { this.call("claims", "DELETE", itemId) },
|
||||
buyItems(items) { this.call("loot", "PUT", items) },
|
||||
sellItems (items) { this.call("loot", "DELETE", { items, global_mod: null, players: null }) },
|
||||
sellItems (items) {
|
||||
let players;
|
||||
if (this.player.id == 0) {
|
||||
players = this.players;
|
||||
} else {
|
||||
players = null;
|
||||
}
|
||||
this.call("loot", "DELETE", { items, global_mod: null, players })
|
||||
},
|
||||
undoLastAction () { this.call("events/last", "DELETE", null) },
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -113,9 +113,7 @@ pub fn execute(
|
||||
None
|
||||
}
|
||||
ApiActions::UpdateWealth(id, amount) => {
|
||||
response.push_update(Update::Wealth(
|
||||
db::AsPlayer(conn, id).update_wealth(amount)?,
|
||||
));
|
||||
response.push_update(db::AsPlayer(conn, id).update_wealth(amount)?);
|
||||
response.notify(format!("Mis à jour ({}po)!", amount));
|
||||
Some((id, "Argent mis à jour"))
|
||||
}
|
||||
@@ -165,15 +163,17 @@ pub fn execute(
|
||||
.fold(db::Wealth::from_gp(0.0), |acc, i| acc + i);
|
||||
match id {
|
||||
0 => {
|
||||
let players = params.players.expect("The player list should be passed in !");
|
||||
let share = db::split_and_share(
|
||||
conn,
|
||||
total_amount.to_gp() as i32,
|
||||
params.players.expect("Should not be None"),
|
||||
&players,
|
||||
)?;
|
||||
response.notify(format!(
|
||||
"Les objets ont été vendus, chaque joueur a reçu {} po",
|
||||
share.to_gp()
|
||||
));
|
||||
//response.push_update(Update::GroupShare(players, share));
|
||||
response.push_update(Update::Wealth(share));
|
||||
}
|
||||
_ => {
|
||||
|
||||
Reference in New Issue
Block a user