def update_asset(managed_portfolio: portfolio.Portfolio, managed_asset: asset.Asset, asset_name: Optional[Text] = None, asset_price: Optional[float] = None, asset_currency: Optional[Text] = None) -> asset.Asset: """Updates an asset information. Args: managed_asset: Asset to update. asset_name: New name of the asset. asset_price: Price of the asset. asset_currency: Currency of the asset price. Returns: Asset updated. """ if asset_name and asset_name != managed_asset.name: managed_asset.name = asset_name if asset_price and asset_price != managed_asset.current_price: managed_asset.current_price = asset_price if asset_currency and asset_currency != managed_asset.currency: managed_asset.currency = asset_currency portfolio_manager.store_portfolio(managed_portfolio) return managed_asset
def get_account_info(client): """Get user's balance info.""" assets = [] total = 0 response = client.query_private('Balance', {}) balance = response.get('result') if not balance: from app import sentry sentry.captureMessage(response.get('error')) return None, None # TODO: # Collect all paris used in balance and query them once together. pair_list = [asset + 'ZUSD' for asset in balance.keys() if asset[0] == 'X'] response = client.query_public('Ticker', {'pair': ','.join(pair_list)}) pair_price = response.get('result') print(response) for asset in balance.keys(): if asset[0] == 'X': pair_name = asset + 'ZUSD' new_asset = Asset(asset, float(balance.get(asset)), float(pair_price.get(pair_name).get('c')[0])) else: new_asset = Asset(asset, amount=float(balance.get(asset)), total=float(balance.get(asset))) assets.append(new_asset.to_dict()) total += new_asset.total return assets, total
def update_asset_stats(managed_asset: asset.Asset) -> stats.AssetStats: """Updates stats of given assets. Args: managed_asset: Asset for which to update stats. Returns: Stats of the given asset. """ tracker = managed_asset.get_tracker() price = managed_asset.current_price if not tracker: return stats.StockStats(managed_asset=managed_asset, price=price) try: fetched_price = _parse_and_format_value( stock_info.get_live_price(tracker)) except AssertionError: fetched_price = None if not fetched_price: return stats.StockStats(managed_asset=managed_asset, price=price) price = fetched_price managed_asset.current_price = price stock_data = stock_info.get_stats(tracker) if stock_data.empty: return stats.StockStats(managed_asset=managed_asset, price=price) try: # TODO: handle all types of assets instead of only stocks. stock_stats = stats.StockStats( managed_asset=managed_asset, price=price, debt_to_equity=_get_stock_stat_value( stock_data, StockAttribute.DEBT_TO_EQUITY), dividend_yield=_get_stock_stat_value( stock_data, StockAttribute.DIVIDEND_YIELD), eps=_get_stock_stat_value(stock_data, StockAttribute.EPS), pe=_get_stock_stat_value(stock_data, StockAttribute.PE), profit_margin=_get_stock_stat_value(stock_data, StockAttribute.PROFIT_MARGIN), return_on_equity=_get_stock_stat_value( stock_data, StockAttribute.RETURN_ON_EQUITY), revenue_growth=_get_stock_stat_value( stock_data, StockAttribute.REVENUE_GROWTH), value_over_ebitda=_get_stock_stat_value( stock_data, StockAttribute.VALUE_OVER_EBITDA), ) managed_asset.stats = stock_stats return stock_stats except Exception: return stats.StockStats(managed_asset=managed_asset, price=price)
def test_normal_scenario_with_two_users(self): # First create some users user1 = User.create_user(self.session, 'user1', 'abcd') user2 = User.create_user(self.session, 'user2', 'abcd') # Make sure user1 has 1 BTC for later deposit into a futures contract btc = Asset.create_asset('BTC') user1.increase_volume_of_asset(self.session, btc, Decimal('1')) # Create a futures contract worth 1 BTC in +14 days contract, asset = FuturesContract.create_contract( self.session, user1, datetime.now() + timedelta(days=14), btc, Decimal('1'), 'FUTURE', Decimal('100')) # This will fail if user1 has insufficient funds (i.e. < 1 BTC) assert contract is not None assert asset is not None self.session.commit() # Create an order for this contract (i.e. newly created asset) usd = Asset.create_asset('USD') ask_order = Order.create_order(self.session, user1, Decimal('20'), usd, contract, Decimal('50'), False, OrderType.limit_order.value) # Make sure we have enough funds assert ask_order is not None self.session.commit() # Put order into market assert put_order(self.session, ask_order) is None # Create a bid order from user2 user2.increase_volume_of_asset(self.session, usd, Decimal('20')) bid_order1 = Order.create_order(self.session, user2, Decimal('20'), usd, contract, Decimal('50'), True, OrderType.limit_order.value) # Make sure we have enough funds assert bid_order1 is not None transaction = put_order(self.session, bid_order1) assert isinstance(transaction, Transaction) assert transaction.ask_order is ask_order assert transaction.bid_order is bid_order1 contract.expire(self.session) assert user1.volume_of_asset(self.session, btc) == Decimal('0.5') assert user2.volume_of_asset(self.session, btc) == Decimal('0.5') # Run it again. Must be idempotent. contract.expire(self.session) assert user1.volume_of_asset(self.session, btc) == Decimal('0.5') assert user2.volume_of_asset(self.session, btc) == Decimal('0.5')
def test_normal_scenario_with_two_users(self): # First create some users user1 = User.create_user(self.session, "user1", "abcd") user2 = User.create_user(self.session, "user2", "abcd") # Make sure user1 has 1 BTC for later deposit into a futures contract btc = Asset.create_asset("BTC") user1.increase_volume_of_asset(self.session, btc, Decimal("1")) # Create a futures contract worth 1 BTC in +14 days contract, asset = FuturesContract.create_contract( self.session, user1, datetime.now() + timedelta(days=14), btc, Decimal("1"), "FUTURE", Decimal("100") ) # This will fail if user1 has insufficient funds (i.e. < 1 BTC) assert contract is not None assert asset is not None self.session.commit() # Create an order for this contract (i.e. newly created asset) usd = Asset.create_asset("USD") ask_order = Order.create_order( self.session, user1, Decimal("20"), usd, contract, Decimal("50"), False, OrderType.limit_order.value ) # Make sure we have enough funds assert ask_order is not None self.session.commit() # Put order into market assert put_order(self.session, ask_order) is None # Create a bid order from user2 user2.increase_volume_of_asset(self.session, usd, Decimal("20")) bid_order1 = Order.create_order( self.session, user2, Decimal("20"), usd, contract, Decimal("50"), True, OrderType.limit_order.value ) # Make sure we have enough funds assert bid_order1 is not None transaction = put_order(self.session, bid_order1) assert isinstance(transaction, Transaction) assert transaction.ask_order is ask_order assert transaction.bid_order is bid_order1 contract.expire(self.session) assert user1.volume_of_asset(self.session, btc) == Decimal("0.5") assert user2.volume_of_asset(self.session, btc) == Decimal("0.5") # Run it again. Must be idempotent. contract.expire(self.session) assert user1.volume_of_asset(self.session, btc) == Decimal("0.5") assert user2.volume_of_asset(self.session, btc) == Decimal("0.5")
def subscribe_asset(self, symbol, exchange, secType): asset_key = f"{symbol}@{exchange}" self.assetCache[asset_key] = Asset(symbol=symbol, exchange=exchange, secType=secType, client=self) return asset_key
def get(self) -> Response: """Endpoint (private) provides the price of a specified asset on a given day. Returns: Response -- The flask Response object. """ args = PRICING_PARSER.parse_args() asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} given.") if args['date'] is None: return make_response(jsonify({"price": asset.get_price()}), 200) try: date = parser.parse(args['date']) except Exception: abort(400, "Invalid {date} given.") candle = asset.get_daily_candle(date.date()) if candle is None: if date.date() == datetime.utcnow().date(): return make_response(jsonify({"price": asset.get_price()}), 200) return abort( 400, "The specified {date} is outside the data available for the asset." ) return make_response(jsonify({"price": candle.get_close()}), 200)
def get(self) -> Response: """Endpoint (private) for providing the Google Trends data associated with an Asset. Returns: Response -- The Flask response object. """ args = TRENDS_READ_PARSER.parse_args() asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} given.") if args['start_date'] is None: start_date = None else: try: start_date = parser.parse(args['start_date']) except Exception: abort(400, "Invalid {start_date} given.") if args['end_date'] is None: end_date = None else: try: end_date = parser.parse(args['end_date']) except Exception: abort(400, "Invalid {end_date} given.") trends = asset.get_trends(start=start_date, finish=end_date) trends_dict = [trend.as_dict() for trend in trends] return make_response(jsonify(trends_dict), 200)
def delete_asset(managed_portfolio: portfolio.Portfolio, managed_asset: asset.Asset): """Deletes an asset from the portfolio. Args: managed_portfolio: Portfolio from which to delete asset. managed_asset: Asset to delete. Raises: ValueError: Asset does not exist in portfolio. Returns: Removed asset. """ asset_id = managed_asset.get_id() if asset_id not in managed_portfolio.assets.keys(): raise ValueError( f'{managed_asset} does not exist in {managed_portfolio}') # There is no need to remove operations as pickle will drop the asset and # all the operations linked to it. del managed_portfolio.assets[asset_id] portfolio_manager.store_portfolio(managed_portfolio) return managed_asset
def get(self) -> Response: """Endpoint (private) provides the historical candle data for a given asset. Returns: Response -- The flask Response object. """ args = HISTORICAL_DAILY_PARSER.parse_args() asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} given.") if args['start_date'] is None: start_date = None else: try: start_date = parser.parse(args['start_date']) except Exception: abort(400, "Invalid {start_date} given.") if args['end_date'] is None: end_date = None else: try: end_date = parser.parse(args['end_date']) except Exception: abort(400, "Invalid {end_date} given.") candles = asset.get_candles_within(start=start_date, finish=end_date, exclude_filler=True) candles_dict = [candle.as_dict() for candle in candles] return make_response(jsonify(candles_dict), 200)
def test_cancel_contract(self): # Create a user and asset user = User.create_user(self.session, 'user', 'abcd') usd = Asset.create_asset('USD') self.session.add_all([user, usd]) self.session.commit() # Add funds to user1 so that we can create a contract user.increase_volume_of_asset(self.session, usd, Decimal('1')) # Let this user create a contract contract, asset = FuturesContract.create_contract( self.session, user, datetime.now() + timedelta(days=14), usd, Decimal('1'), 'FUTURE', Decimal('100')) assert contract is not None assert asset is not None # Now, money have been withdrawn from user1's account assert user.volume_of_asset(self.session, usd) == Decimal('0') # Cancel the contract assert contract.cancel(self.session) is True assert inspect(contract).deleted is True assert user.volume_of_asset(self.session, usd) == Decimal('1') # OK, the contract is cancelled. # Now do the same thing, but this time, create an order and verify that the cancelled flag is set instead contract, asset = FuturesContract.create_contract( self.session, user, datetime.now() + timedelta(days=14), usd, Decimal('1'), 'FUTURE', Decimal('100')) assert contract is not None assert asset is not None assert user.volume_of_asset(self.session, usd) == Decimal('0') ask_order = Order.create_order(self.session, user, Decimal('20'), usd, contract, Decimal('50'), False, OrderType.limit_order.value) assert ask_order is not None assert user.volume_of_asset(self.session, asset) == Decimal('50') # Assert that we cannot cancel the contract if there are created orders assert contract.cancel(self.session) is False # Put order into market assert put_order(self.session, ask_order) is None # Assert that we cannot cancel the contract if there are orders in the market assert contract.cancel(self.session) is False # It should be possible to cancel this order assert ask_order.cancel(self.session) is True assert user.volume_of_asset(self.session, asset) == Decimal('100') # Check that order is in the expected state assert contract.cancel(self.session) is True assert inspect(contract).deleted is False assert contract.cancelled is True
def get(self) -> Response: """Endpoint (public) provides a list of all the Assets and associated information. Returns: Response -- The flask Response object. """ assets = Asset.get() assets_dict = [asset.as_dict() for asset in assets] return make_response(jsonify(assets_dict), 200)
def test_cancel_contract(self): # Create a user and asset user = User.create_user(self.session, "user", "abcd") usd = Asset.create_asset("USD") self.session.add_all([user, usd]) self.session.commit() # Add funds to user1 so that we can create a contract user.increase_volume_of_asset(self.session, usd, Decimal("1")) # Let this user create a contract contract, asset = FuturesContract.create_contract( self.session, user, datetime.now() + timedelta(days=14), usd, Decimal("1"), "FUTURE", Decimal("100") ) assert contract is not None assert asset is not None # Now, money have been withdrawn from user1's account assert user.volume_of_asset(self.session, usd) == Decimal("0") # Cancel the contract assert contract.cancel(self.session) is True assert inspect(contract).deleted is True assert user.volume_of_asset(self.session, usd) == Decimal("1") # OK, the contract is cancelled. # Now do the same thing, but this time, create an order and verify that the cancelled flag is set instead contract, asset = FuturesContract.create_contract( self.session, user, datetime.now() + timedelta(days=14), usd, Decimal("1"), "FUTURE", Decimal("100") ) assert contract is not None assert asset is not None assert user.volume_of_asset(self.session, usd) == Decimal("0") ask_order = Order.create_order( self.session, user, Decimal("20"), usd, contract, Decimal("50"), False, OrderType.limit_order.value ) assert ask_order is not None assert user.volume_of_asset(self.session, asset) == Decimal("50") # Assert that we cannot cancel the contract if there are created orders assert contract.cancel(self.session) is False # Put order into market assert put_order(self.session, ask_order) is None # Assert that we cannot cancel the contract if there are orders in the market assert contract.cancel(self.session) is False # It should be possible to cancel this order assert ask_order.cancel(self.session) is True assert user.volume_of_asset(self.session, asset) == Decimal("100") # Check that order is in the expected state assert contract.cancel(self.session) is True assert inspect(contract).deleted is False assert contract.cancelled is True
def get(self) -> Response: """Endpoint (public) provides the details of all assets containing the given asset_name. Returns: Response -- The flask Response object. """ args = AUTOCOMPLETE_PARSER.parse_args() assets = Asset.autocomplete_by_name(args['asset_name']) assets_dict = [asset.as_dict_autocomplete() for asset in assets] return make_response(jsonify(assets_dict), 200)
def get(self) -> Response: """Endpoint (private) provides the performance of a specified asset over the current and previous day. Returns: Response -- The flask Response object. """ args = PERFORMANCE_DAILY_PARSER.parse_args() asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} given.") return make_response(jsonify(asset.get_daily_performance()), 200)
def get(self) -> Response: """Endpoint (private) provides the data associated with an Asset. Returns: Response -- The flask Response object. """ args = READ_ASSET_PARSER.parse_args() asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} given.") asset_dict = asset.as_dict() return make_response(jsonify(asset_dict), 200)
def create_contract(cls, session, user, expires_at, asset, asset_volume, contract_asset_name, contract_volume): if user.volume_of_asset(session, asset) < asset_volume: return None, None contract_asset = Asset.create_asset(contract_asset_name) contract = cls(created_at=datetime.now(), contract_type='Future', issuer=user, expires_at=expires_at, volume=asset_volume, asset=asset, contract_asset=contract_asset) session.add_all([contract_asset, contract]) user.increase_volume_of_asset(session, contract_asset, contract_volume) user.decrease_volume_of_asset(session, asset, asset_volume) logger.info('Created futures contract instance and asset with name "{}"'.format(contract_asset_name)) return contract, contract_asset
def test_insufficient_funds(self): # Create a user and asset user = User.create_user(self.session, "user", "abcd") usd = Asset.create_asset("USD") self.session.add_all([user, usd]) self.session.commit() # This user creates a contract without proper funding contract, asset = FuturesContract.create_contract( self.session, user, datetime.now() + timedelta(days=14), usd, Decimal("1"), "FUTURE", Decimal("100") ) # Assert that this does not work assert contract is None assert asset is None
def test_insufficient_funds(self): # Create a user and asset user = User.create_user(self.session, 'user', 'abcd') usd = Asset.create_asset('USD') self.session.add_all([user, usd]) self.session.commit() # This user creates a contract without proper funding contract, asset = FuturesContract.create_contract( self.session, user, datetime.now() + timedelta(days=14), usd, Decimal('1'), 'FUTURE', Decimal('100')) # Assert that this does not work assert contract is None assert asset is None
def create_contract(cls, session, user, expires_at, asset, asset_volume, contract_asset_name, contract_volume): if user.volume_of_asset(session, asset) < asset_volume: return None, None contract_asset = Asset.create_asset(contract_asset_name) contract = cls(created_at=datetime.now(), contract_type='Future', issuer=user, expires_at=expires_at, volume=asset_volume, asset=asset, contract_asset=contract_asset) session.add_all([contract_asset, contract]) user.increase_volume_of_asset(session, contract_asset, contract_volume) user.decrease_volume_of_asset(session, asset, asset_volume) logger.info( 'Created futures contract instance and asset with name "{}"'. format(contract_asset_name)) return contract, contract_asset
def patch(self) -> Response: """Endpoint (private) allows a User to update their profile details. Returns: Response -- The Flask response object. """ args = UPDATE_PARSER.parse_args() user = User.get_by_email(get_jwt_identity()) if user is None: return abort(401, "You are not permitted to access this endpoint.") if args['fullname'] is not None: if args['fullname'] == "": return abort(400, "Your {fullname} cannot be empty.") user.set_name(args['fullname']) if args['currency_id'] is not None: currency = Asset.get_by_id(args['currency_id']) if currency is None: return abort(400, "An invalid {currency_id} was given as a base currency.") if currency.get_asset_class() != "Currency": return abort(400, "The provided {currency_id} is not a currency.") user.set_base_currency(currency) user.save() return make_response(jsonify({"msg": "The user details have been successfully updated."}), 200)
def insert(self, dto): reg = Asset() reg.map(dto) reg.calculate() return AssetDb().insert(reg)
def post(self) -> Response: """Endpoint (private) responsible for allowing a User to create a Transaction. Returns: Response -- The Flask response object. """ args = CREATE_PARSER.parse_args() user = User.get_by_email(get_jwt_identity()) if user is None: return abort(403, "You are not permitted to create a transaction.") asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} has been specified.") try: asset_quantity = float(args['quantity']) except Exception: return abort(400, "Invalid asset {quantity} specified.") if asset_quantity <= 0: return abort(400, "The {quantity} cannot be less than or equal to 0.") try: date_purchased = parser.parse(args['date_purchased']) date_purchased = date_purchased.replace(tzinfo=None) except Exception: return abort(400, "Invalid {date_purchased} specified.") if date_purchased > datetime.utcnow(): return abort(400, "The {date_purchased} cannot be ahead of time.") purchase_candle = asset.get_daily_candle(date_purchased) if purchase_candle is None and date_purchased.date( ) != datetime.utcnow().date(): return abort( 400, "The given {date_purchased} is prior to the platform's pricing history for the asset." ) if args['price_purchased'] is None: if purchase_candle is None: price_purchased = asset.get_price() else: price_purchased = purchase_candle.get_close() else: try: price_purchased = float(args['price_purchased']) except Exception: return abort(400, "Invalid {price_purchased} given.") if price_purchased <= 0: return abort( 400, "The {price_purchased} cannot be less than or equal to 0.") if args['date_sold'] is None or args['date_sold'] == "": date_sold = None price_sold = None else: try: date_sold = parser.parse(args['date_sold']) date_sold = date_sold.replace(tzinfo=None) except Exception: return abort(400, "Invalid {date_sold} specified.") if date_sold > datetime.utcnow(): return abort(400, "The {date_sold} cannot be ahead of time.") if date_sold <= date_purchased: return abort( 400, "The {date_sold} must be further in time than the {date_purchased}." ) if args['price_sold'] is None: if date_sold.date() == datetime.utcnow().date(): price_sold = asset.get_price() else: sell_candle = asset.get_daily_candle(date_sold) if sell_candle is None: return abort( 400, "The given {date_sold} has no data for the asset in the platform's pricing history." ) price_sold = sell_candle.get_close() else: if date_sold.date() != datetime.utcnow().date(): sell_candle = asset.get_daily_candle(date_sold) if sell_candle is None: return abort( 400, "The given {date_sold} has no data for the asset in the platform's pricing history." ) try: price_sold = float(args['price_sold']) except Exception: return abort(400, "Invalid {price_sold} given.") if price_sold < 0: return abort(400, "The {price_sold} cannot be less than 0.") new_transaction = Transaction.create(user, asset, asset_quantity, date_purchased, date_sold, price_purchased, price_sold) if new_transaction is None: return abort(500, "An error occurred in creating the transaction.") return make_response( jsonify({"msg": "The transaction has been successfully created."}), 200)
def patch(self) -> Response: """Endpoint (private) responsible for updating the details of a User's Transaction. Returns: Response -- The Flask response object. """ args = UPDATE_PARSER.parse_args() transaction = Transaction.get_by_id(args['transaction_id']) if transaction is None: return abort(400, "Invalid {transaction_id} specified.") if transaction.get_user().get_email() != get_jwt_identity(): return abort(401, "You are not authorised to update this transaction.") if args['asset_id'] is not None: asset = Asset.get_by_id(args['asset_id']) if asset is None: return abort(400, "Invalid {asset_id} specified.") transaction.set_asset(asset) if args['quantity'] is not None: try: quantity = float(args['quantity']) except Exception: return abort(400, "Invalid {quantity} specified.") if quantity <= 0: return abort( 400, "The {quantity} cannot be less than or equal to 0.") transaction.set_quantity(quantity) if args['date_purchased'] is not None: try: date_purchased = parser.parse(args['date_purchased']) date_purchased = date_purchased.replace(tzinfo=None) except Exception: return abort(400, "Invalid {date_purchased} specified.") if date_purchased > datetime.utcnow(): return abort(400, "The {date_purchased} cannot be ahead of time.") purchase_candle = transaction.get_asset().get_daily_candle( date_purchased) if purchase_candle is None and (date_purchased.date() != datetime.utcnow().date()): return abort( 400, "The given {date_purchased} is prior to the platform's pricing history for the asset." ) transaction.set_buy_date(date_purchased) if args['price_purchased'] is not None: try: price_purchased = float(args['price_purchased']) except Exception: return abort(400, "Invalid {price_purchased} specified.") if price_purchased <= 0: return abort( 400, "The {price_purchased} cannot be less than or equal to 0.") transaction.set_buy_price(price_purchased) else: if args['date_purchased'] is not None: if purchase_candle is None: transaction.set_buy_price( transaction.get_asset().get_price()) else: transaction.set_buy_price(purchase_candle.get_close()) if args['date_sold'] is not None: if args['date_sold'] == "": transaction.set_sell_date(None) transaction.set_sell_price(None) else: try: date_sold = parser.parse(args['date_sold']) date_sold = date_sold.replace(tzinfo=None) except Exception: return abort(400, "Invalid {date_sold} specified.") if date_sold > datetime.utcnow(): return abort(400, "The {date_sold} cannot be ahead of time.") if date_sold <= transaction.get_buy_date(): return abort( 400, "The {date_sold} must be further ahead in time than the {date_purchased}." ) sell_candle = transaction.get_asset().get_daily_candle( date_sold) if sell_candle is None and date_sold.date() != datetime.utcnow( ).date(): return abort( 400, "The given {date_sold} is outside the platform's pricing history for the asset." ) transaction.set_sell_date(date_sold) if args['price_sold'] is not None: if transaction.get_sell_date() is None: return abort( 400, "The {price_sold} field cannot be set while {date_sold} hasn't been set." ) try: price_sold = float(args['price_sold']) except Exception: return abort(400, "Invalid {price_sold} specified.") if price_sold < 0: return abort(400, "The {price_sold} cannot be less than 0.") transaction.set_sell_price(price_sold) else: if transaction.get_sell_date() is not None: if date_sold.date() == datetime.utcnow().date(): transaction.set_sell_price( transaction.get_asset().get_price()) else: sell_candle = transaction.get_asset().get_daily_candle( date_sold) if sell_candle is None: return abort( 400, "The given {date_sold} has no data for the asset in the platform's pricing history." ) transaction.set_sell_price(sell_candle.get_close()) transaction.save() user = transaction.user.fetch() user.set_portfolio_historical(None) user.save() return make_response( jsonify({"msg": "The transaction was successfully updated."}), 200)
def set_asset(self, guid, description, type, uri, duration_secs=None, pin=None, how_many=None, shuffle=None): self.kv.set_asset(guid, Asset(uri, guid, description, type, duration_secs, pin, how_many, shuffle))
async def load_location(sid: str, location: Location, *, complete=False): pr: PlayerRoom = game_state.get(sid) if pr.active_location != location: pr.active_location = location pr.save() # 1. Load client options client_options = pr.player.as_dict() client_options["location_user_options"] = LocationUserOption.get( user=pr.player, location=location).as_dict() client_options["default_user_options"] = pr.player.default_options.as_dict( ) if pr.user_options: client_options["room_user_options"] = pr.user_options.as_dict() await sio.emit("Client.Options.Set", client_options, room=sid, namespace=GAME_NS) # 2. Load room info if complete: await sio.emit( "Room.Info.Set", { "name": pr.room.name, "creator": pr.room.creator.name, "invitationCode": str(pr.room.invitation_code), "isLocked": pr.room.is_locked, "default_options": pr.room.default_options.as_dict(), "players": [{ "id": rp.player.id, "name": rp.player.name, "location": rp.active_location.id, "role": rp.role, } for rp in pr.room.players], "publicName": config.get("General", "public_name", fallback=""), }, room=sid, namespace=GAME_NS, ) # 3. Load location await sio.emit("Location.Set", location.as_dict(), room=sid, namespace=GAME_NS) # 4. Load all location settings (DM) if complete and pr.role == Role.DM: await sio.emit( "Locations.Settings.Set", { l.id: {} if l.options is None else l.options.as_dict() for l in pr.room.locations }, room=sid, namespace=GAME_NS, ) # 5. Load Board locations = [{ "id": l.id, "name": l.name, "archived": l.archived } for l in pr.room.locations.order_by(Location.index)] await sio.emit("Board.Locations.Set", locations, room=sid, namespace=GAME_NS) floors = [floor for floor in location.floors.order_by(Floor.index)] if "active_floor" in client_options["location_user_options"]: index = next(i for i, f in enumerate(floors) if f.name == client_options["location_user_options"]["active_floor"]) lower_floors = floors[index - 1::-1] if index > 0 else [] higher_floors = floors[index + 1:] if index < len(floors) else [] floors = [floors[index], *lower_floors, *higher_floors] for floor in floors: await sio.emit( "Board.Floor.Set", floor.as_dict(pr.player, pr.role == Role.DM), room=sid, namespace=GAME_NS, ) # 6. Load Initiative location_data = Initiative.get_or_none(location=location) if location_data: await sio.emit("Initiative.Set", location_data.as_dict(), room=sid, namespace=GAME_NS) # 7. Load labels if complete: labels = Label.select().where((Label.user == pr.player) | (Label.visible == True)) label_filters = LabelSelection.select().where( (LabelSelection.user == pr.player) & (LabelSelection.room == pr.room)) await sio.emit( "Labels.Set", [l.as_dict() for l in labels], room=sid, namespace=GAME_NS, ) await sio.emit( "Labels.Filters.Set", [l.label.uuid for l in label_filters], room=sid, namespace=GAME_NS, ) # 8. Load Notes await sio.emit( "Notes.Set", [ note.as_dict() for note in Note.select().where((Note.user == pr.player) & (Note.room == pr.room)) ], room=sid, namespace=GAME_NS, ) # 9. Load Markers await sio.emit( "Markers.Set", [ marker.as_string() for marker in Marker.select(Marker.shape_id).where( (Marker.user == pr.player) & (Marker.location == location)) ], room=sid, namespace=GAME_NS, ) # 10. Load Assets if complete: await sio.emit( "Asset.List.Set", Asset.get_user_structure(pr.player), room=sid, namespace=GAME_NS, )
def update(self, id, dto): reg = Asset() reg.map(dto) reg.calculate() return AssetDb().update(id, reg)