Fix cheat

This commit is contained in:
Mark Veidemanis 2023-03-11 16:57:08 +00:00
parent 11f596708d
commit 436d069ae7
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
11 changed files with 401 additions and 156 deletions

View File

@ -185,6 +185,11 @@ urlpatterns = [
ads.AdRedist.as_view(),
name="ad_redist",
),
path(
"ops/ads/cheat/",
ads.Cheat.as_view(),
name="cheat",
),
path(
"profit/<str:type>/",
profit.Profit.as_view(),

View File

@ -300,7 +300,6 @@ class NordigenClient(BaseClient, AggregatorClient):
"""
path = f"accounts/{account_id}/transactions"
response = await self.call(path, schema="Transactions")
print("RESP", response["pending"])
parsed = response["booked"]
self.normalise_transactions(parsed, state="booked")

View File

@ -5,6 +5,7 @@ from datetime import datetime, timezone
from random import choices
from string import ascii_uppercase
from aiocoingecko import AsyncCoinGeckoAPISession
from django.conf import settings
from core.clients.platforms.api.agoradesk import AgoraDesk
@ -33,7 +34,37 @@ class LocalPlatformClient(ABC):
Call a method using the self.api object.
"""
if hasattr(self.api, method):
return await getattr(self.api, method)(*args, **kwargs)
returned_429 = True
iterations = 0
throttled = 0
while returned_429 or iterations == 100:
response = await getattr(self.api, method)(*args, **kwargs)
if "status" in response:
if response["status"] == 429: # Too many requests
throttled += 1
sleep_time = pow(throttled, 1.9)
log.info(
(
f"Throttled {throttled} times while calling "
f"{method}, "
f"sleeping for {sleep_time} seconds"
)
)
# We're running in a thread, so this is fine
await asyncio.sleep(sleep_time)
elif response["status"] == 400:
raise Exception(response)
else:
if throttled != 0:
log.info(
f"Finally successful after {throttled}",
f" attempts to call {method}",
)
returned_429 = False
throttled = 0
iterations += 1
return response
else:
raise Exception(f"Method {method} not found in {self.name} API.")
@ -249,62 +280,53 @@ class LocalPlatformClient(ABC):
async def enum_ad_ids(self, page=0):
if self.name == "lbtc" and page == 0:
page = 1
ads = await self.api.ads(page=page)
ads = await self.call("ads", page=page)
# ads = await self.api._api_call(api_method="ads", query_values={"page": page})
if ads is False:
return False
ads_total = []
if not ads["success"]:
return False
for ad in ads["response"]["data"]["ad_list"]:
for ad in ads["ad_list"]:
ads_total.append(ad["data"]["ad_id"])
if "pagination" in ads["response"]:
if "next" in ads["response"]["pagination"]:
page += 1
ads_iter = await self.enum_ad_ids(page)
if ads_iter is None:
return False
if ads_iter is False:
return False
for ad in ads_iter:
ads_total.append(ad)
if "pagination" in ads:
if ads["pagination"]:
if "next" in ads["pagination"]:
page += 1
ads_iter = await self.enum_ad_ids(page)
if ads_iter is None:
return False
if ads_iter is False:
return False
for ad in ads_iter:
ads_total.append(ad)
return ads_total
async def enum_ads(self, requested_asset=None, page=0):
if self.name == "lbtc" and page == 0:
page = 1
query_values = {"page": page}
if requested_asset:
query_values["asset"] = requested_asset
# ads = await self.api._api_call(api_method="ads", query_values=query_values)
ads = await self.api.ads(page=page)
if ads is False:
return False
ads = await self.call("ads", page=page)
ads_total = []
if not ads["success"]:
return False
if not ads["response"]:
return False
for ad in ads["response"]["data"]["ad_list"]:
if self.name == "agora":
asset = ad["data"]["asset"]
elif self.name == "lbtc":
asset = "BTC"
for ad in ads["ad_list"]:
asset = ad["data"]["asset"]
ad_id = ad["data"]["ad_id"]
country = ad["data"]["countrycode"]
currency = ad["data"]["currency"]
provider = ad["data"]["online_provider"]
ads_total.append([asset, ad_id, country, currency, provider])
if "pagination" in ads["response"]:
if "next" in ads["response"]["pagination"]:
page += 1
ads_iter = await self.enum_ads(requested_asset, page)
if ads_iter is None:
return False
if ads_iter is False:
return False
for ad in ads_iter:
ads_total.append([ad[0], ad[1], ad[2], ad[3], ad[4]])
if "pagination" in ads:
if ads["pagination"]:
if "next" in ads["pagination"]:
page += 1
ads_iter = await self.enum_ads(requested_asset, page)
if ads_iter is None:
return False
if ads_iter is False:
return False
for ad in ads_iter:
ads_total.append([ad[0], ad[1], ad[2], ad[3], ad[4]])
return ads_total
def last_online_recent(self, date):
@ -331,16 +353,8 @@ class LocalPlatformClient(ABC):
sec_ago_date = (now - date_parsed).total_seconds()
return sec_ago_date < 172800
async def enum_public_ads(self, asset, currency, providers=None, page=0):
if self.name == "lbtc" and page == 0:
page = 1
async def enum_public_ads(self, asset, currency, provider, page=0):
to_return = []
# if asset == "XMR":
# coin = "monero"
# elif asset == "BTC":
# coin = "bitcoins"
if not providers:
providers = ["NATIONAL_BANK"]
# buy-monero-online, buy-bitcoin-online
# Work around Agora weirdness calling it bitcoins
# ads = await self.api._api_call(
@ -348,28 +362,31 @@ class LocalPlatformClient(ABC):
# query_values={"page": page},
# )
if asset == "XMR":
ads = await self.api.buy_monero_online(currency_code=currency, page=page)
ads = await self.call(
"buy_monero_online",
currency_code=currency,
payment_method=provider,
page=page,
)
elif asset == "BTC":
ads = await self.api.buy_bitcoins_online(currency_code=currency, page=page)
# with open("pub.json", "a") as f:
# import json
# f.write(json.dumps([page, currency, asset, ads])+"\n")
# f.close()
if ads is None:
ads = await self.call(
"buy_bitcoins_online",
currency_code=currency,
payment_method=provider,
page=page,
)
else:
raise Exception("Unknown asset")
if not ads["success"]:
return False
if ads is False:
return False
if ads["response"] is None:
return False
if "data" not in ads["response"]:
return False
for ad in ads["response"]["data"]["ad_list"]:
provider = ad["data"]["online_provider"]
found_us = False
for ad in ads["ad_list"]:
provider_ad = ad["data"]["online_provider"]
if self.name == "lbtc":
provider_test = self.map_provider(provider)
provider_test = self.map_provider(provider_ad)
else:
provider_test = provider
if provider_test not in providers:
if provider_test != provider:
continue
date_last_seen = ad["data"]["profile"]["last_online"]
# Check if this person was seen recently
@ -377,48 +394,36 @@ class LocalPlatformClient(ABC):
continue
ad_id = str(ad["data"]["ad_id"])
username = ad["data"]["profile"]["username"]
if username == self.instance.username:
found_us = True
temp_price = ad["data"]["temp_price"]
if ad["data"]["currency"] != currency:
continue
to_append = [ad_id, username, temp_price, provider, asset, currency]
to_append = [ad_id, username, temp_price, provider_ad, asset, currency]
if to_append not in to_return:
to_return.append(to_append)
# await [ad_id, username, temp_price, provider, asset, currency]
if "pagination" in ads["response"]:
if "next" in ads["response"]["pagination"]:
page += 1
ads_iter = await self.enum_public_ads(asset, currency, providers, page)
if ads_iter is None:
return False
if ads_iter is False:
return False
for ad in ads_iter:
to_append = [ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]]
if to_append not in to_return:
to_return.append(to_append)
if found_us:
return to_return
if "pagination" in ads:
if ads["pagination"]:
if "next" in ads["pagination"]:
page += 1
ads_iter = await self.enum_public_ads(
asset, currency, provider, page
)
if ads_iter is None:
return False
if ads_iter is False:
return False
for ad in ads_iter:
to_append = [ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]]
if to_append not in to_return:
to_return.append(to_append)
return to_return
async def run_cheat_in_thread(self, assets=None):
"""
Update prices in another thread.
"""
if not assets:
all_assets = ["XMR"]
assets_not_run = set(all_assets) ^ set(self.cheat_run_on)
if not assets_not_run:
self.cheat_run_on = []
asset = list(all_assets).pop()
self.cheat_run_on.append(asset)
else:
asset = assets_not_run.pop()
self.cheat_run_on.append(asset)
await self.update_prices([asset])
return asset
else:
# deferToThread(self.update_prices, assets)
await self.update_prices(assets)
async def update_prices(self, assets=None):
async def cheat(self, assets=None):
# Get all public ads for the given assets
public_ads = await self.get_all_public_ads(assets)
if not public_ads:
@ -446,33 +451,35 @@ class LocalPlatformClient(ABC):
providers = providers or self.instance.ads_providers
currencies = currencies or self.instance.currencies
# We want to get the ads for each of these currencies and return the result
rates = await money.cg.get_price(
ids=["monero", "bitcoin"], vs_currencies=currencies
)
async with AsyncCoinGeckoAPISession() as cg:
rates = await cg.get_price(
ids="monero,bitcoin", vs_currencies=",".join(currencies)
)
for asset in assets:
for currency in currencies:
cg_asset_name = crypto_map[asset]
try:
rates[cg_asset_name][currency.lower()]
except KeyError:
log.debug(f"Error getting public ads for currency: {currency}")
continue
ads_list = await self.enum_public_ads(asset, currency, providers)
if not ads_list:
log.debug("Error getting ads list.")
continue
ads = await money.lookup_rates(self.name, ads_list, rates=rates)
if not ads:
log.debug("Error lookup up rates.")
continue
log.debug("Writing to ES.")
await self.write_to_es_ads("ads", ads)
if currency in public_ads:
for ad in list(ads):
if ad not in public_ads[currency]:
public_ads[currency].append(ad)
else:
public_ads[currency] = ads
for provider in providers:
cg_asset_name = crypto_map[asset]
try:
rates[cg_asset_name][currency.lower()]
except KeyError:
log.debug(f"Error getting public ads for currency: {currency}")
continue
ads_list = await self.enum_public_ads(asset, currency, provider)
if not ads_list:
log.debug("Error getting ads list.")
continue
ads = await money.lookup_rates(self.name, ads_list, rates=rates)
if not ads:
log.debug("Error lookup up rates.")
continue
log.debug("Writing to ES.")
# await self.write_to_es_ads("ads", ads)
if currency in public_ads:
for ad in list(ads):
if ad not in public_ads[currency]:
public_ads[currency].append(ad)
else:
public_ads[currency] = ads
return public_ads
@ -980,7 +987,7 @@ class LocalPlatformClient(ABC):
# (asset, currency, provider)
assets = self.instance.ads_assets
currencies = self.currencies
currencies = self.instance.currencies
providers = self.instance.ads_providers
# if platform == "lbtc":
# providers = [
@ -1161,7 +1168,7 @@ class LocalPlatformClient(ABC):
currency_account_info_map[currency]["recipient"] = account[
"ownerName"
]
return (currencies, currency_account_info_map)
return (list(currency_account_info_map.keys()), currency_account_info_map)
def get_matching_account_details(self, currency, ad):
(

View File

@ -652,7 +652,7 @@ class AgoraDesk:
)
@staticmethod
async def _generic_search_parameters(amount, page):
def _generic_search_parameters(amount, page):
params = None
if amount and page is not None:
params = {"amount": f"{amount}"}
@ -662,6 +662,7 @@ class AgoraDesk:
params = {"page": f"{page}"}
return params
#
async def buy_monero_online(
self,
currency_code: str,
@ -680,7 +681,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_online(
return await self._generic_online(
direction="buy",
main_currency="monero",
exchange_currency=currency_code,
@ -708,7 +709,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_online(
return await self._generic_online(
direction="buy",
main_currency="bitcoins",
exchange_currency=currency_code,
@ -736,7 +737,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_online(
return await self._generic_online(
direction="sell",
main_currency="monero",
exchange_currency=currency_code,
@ -764,7 +765,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_online(
return await self._generic_online(
direction="sell",
main_currency="bitcoins",
exchange_currency=currency_code,
@ -811,7 +812,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_cash(
return await self._generic_cash(
direction="buy",
main_currency="monero",
exchange_currency=currency_code,
@ -838,7 +839,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_cash(
return await self._generic_cash(
direction="buy",
main_currency="bitcoins",
exchange_currency=currency_code,
@ -865,7 +866,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_cash(
return await self._generic_cash(
direction="sell",
main_currency="monero",
exchange_currency=currency_code,
@ -892,7 +893,7 @@ class AgoraDesk:
# pylint: disable=too-many-arguments
return self._generic_cash(
return await self._generic_cash(
direction="sell",
main_currency="bitcoins",
exchange_currency=currency_code,

View File

@ -390,7 +390,6 @@ class Money(object):
cast_es["total_remaining"] = total_remaining
cast_es["total_profit"] = total_profit
# await self.write_to_es("get_total", cast_es)
print("CAST ES", cast_es)
return cast_es
async def open_trades_usd_parse_dash(self, dash, rates):

View File

@ -1,7 +1,12 @@
from pydantic import BaseModel
from pydantic import BaseModel, Extra
class ContactDataBuyerSeller(BaseModel):
class MyModel(BaseModel):
class Config:
extra = Extra.forbid
class ContactDataBuyerSeller(MyModel):
username: str
name: str
feedback_score: int
@ -9,7 +14,7 @@ class ContactDataBuyerSeller(BaseModel):
last_online: str
class ContactDataAd(BaseModel):
class ContactDataAd(MyModel):
payment_method: str
trade_type: str
advertiser: ContactDataBuyerSeller
@ -18,7 +23,7 @@ class ContactDataAd(BaseModel):
contact_id: str | None
class ContactData(BaseModel):
class ContactData(MyModel):
buyer: ContactDataBuyerSeller
seller: ContactDataBuyerSeller
amount: str
@ -53,32 +58,34 @@ class ContactData(BaseModel):
transfer_to_seller_non_custodial_wallet_transaction_id: str | None
class ContactActions(BaseModel):
class ContactActions(MyModel):
advertisement_public_view: str | None
advertisement_url: str | None
message_post_url: str
messages_url: str
release_url: str
cancel_url: str | None
class Contact(BaseModel):
class Contact(MyModel):
data: ContactData
actions: ContactActions
class ResponseData(BaseModel):
class DashboardResponseData(MyModel):
contact_count: int
contact_list: list[Contact]
class Response(BaseModel):
data: ResponseData
class DashboardResponse(MyModel):
data: DashboardResponseData
class Dashboard(BaseModel):
class Dashboard(MyModel):
success: bool
status: int | None
message: str
response: Response
response: DashboardResponse
DashboardSchema = {
@ -87,3 +94,202 @@ DashboardSchema = {
"contact_count": "response.data.contact_count",
"contact_list": "response.data.contact_list",
}
class Pagination(MyModel):
prev: str | None
next: str | None
total_elements: int
total_pages: int
current_page: int
class Profile(MyModel):
username: str
name: str
feedback_score: int
trade_count: str
last_online: str
localbitcoins_trade_count: int | None
paxful_trade_count: int | None
class BuyBitcoinsOnlineAd(MyModel):
ad_id: str
countrycode: str
created_at: str
currency: str
max_amount: float | None
max_amount_available: float
min_amount: float | None
msg: str
online_provider: str
require_trusted_by_advertiser: bool
verified_email_required: bool
temp_price: float
track_max_amount: bool
trade_type: str
trusted_required: bool
visible: bool
asset: str
payment_method_detail: str | None
profile: Profile
require_feedback_score: int | None
first_time_limit_btc: float | None
limit_to_fiat_amounts: str | None
class Actions(MyModel):
public_view: str
class BuyBitcoinsOnlineResponseDataAdList(MyModel):
data: BuyBitcoinsOnlineAd
actions: Actions
class BuyBitcoinsOnlineResponseData(MyModel):
ad_count: int
ad_list: list[BuyBitcoinsOnlineResponseDataAdList]
class BuyBitcoinsOnlineResponse(MyModel):
data: BuyBitcoinsOnlineResponseData
pagination: Pagination | None
class BuyBitcoinsOnline(MyModel):
success: bool
message: str
response: BuyBitcoinsOnlineResponse
status: int | None
class BuyMoneroOnlineAd(MyModel):
ad_id: str
countrycode: str
created_at: str
currency: str
max_amount: float | None
max_amount_available: float
min_amount: float | None
msg: str
online_provider: str
require_trusted_by_advertiser: bool
verified_email_required: bool
temp_price: float
track_max_amount: bool
trade_type: str
trusted_required: bool
visible: bool
asset: str
payment_method_detail: str | None
profile: Profile
require_feedback_score: int | None
first_time_limit_xmr: float | None
limit_to_fiat_amounts: str | None
class BuyMoneroOnlineAdList(MyModel):
data: BuyMoneroOnlineAd
actions: Actions
class BuyMoneroOnlineResponseData(MyModel):
ad_count: int
ad_list: list[BuyMoneroOnlineAdList]
class BuyMoneroOnlineResponse(MyModel):
data: BuyMoneroOnlineResponseData
pagination: Pagination | None
class BuyMoneroOnline(MyModel):
success: bool
message: str
response: BuyMoneroOnlineResponse
status: int | None
BuyBitcoinsOnlineSchema = {
"success": "success",
"message": "message",
"ad_count": "response.data.ad_count",
"ad_list": "response.data.ad_list",
"pagination": "response.pagination",
}
BuyMoneroOnlineSchema = {
"success": "success",
"message": "message",
"ad_count": "response.data.ad_count",
"ad_list": "response.data.ad_list",
"pagination": "response.pagination",
}
class AccountInfo(MyModel):
...
class AdsResponseDataAd(MyModel):
ad_id: str
countrycode: str
created_at: str
currency: str
max_amount: float | None
max_amount_available: float
min_amount: float | None
msg: str
online_provider: str
require_trusted_by_advertiser: bool
verified_email_required: bool
temp_price: float
track_max_amount: bool
trade_type: str
trusted_required: bool
visible: bool
asset: str
payment_method_detail: str | None
require_feedback_score: int | None
first_time_limit_xmr: float | None
first_time_limit_btc: float | None
limit_to_fiat_amounts: str | None
account_info: str
price_equation: str
class AdsActions(MyModel):
change_form: str | None
html_form: str | None
public_view: str | None
class AdsResponseDataAdList(MyModel):
data: AdsResponseDataAd
actions: AdsActions
class AdsResponseData(MyModel):
ad_count: int
ad_list: list[AdsResponseDataAdList]
class AdsResponse(MyModel):
data: AdsResponseData
class Ads(MyModel):
success: bool
message: str
response: AdsResponse
status: int | None
AdsSchema = {
"success": "success",
"message": "message",
"ad_count": "response.data.ad_count",
"ad_list": "response.data.ad_list",
}

View File

@ -1,4 +1,12 @@
from pydantic import BaseModel
from pydantic import BaseModel, Extra
class MyModel(BaseModel):
class Config:
extra = Extra.forbid
# TODO: inherit from MyModel
class TokenNew(BaseModel):

View File

@ -14,11 +14,10 @@ INTERVAL = 5
async def poll_aggregator(aggregator):
print("Polling aggregator", aggregator)
pass
async def poll_platform(platform):
print("Polling platform", platform)
client = await AgoraClient(platform)
await client.poll()

View File

@ -11,6 +11,20 @@ from core.models import Ad
from core.views.helpers import synchronize_async_helper
class Cheat(LoginRequiredMixin, OTPRequiredMixin, View):
template_name = "mixins/partials/notify.html"
def get(self, request):
ads = Ad.objects.filter(user=request.user, enabled=True)
for ad in ads:
for platform in ad.platforms.all():
run = synchronize_async_helper(AgoraClient(platform))
synchronize_async_helper(run.cheat())
context = {"class": "success", "message": "Cheat run"}
return render(request, self.template_name, context)
class AdNuke(LoginRequiredMixin, OTPRequiredMixin, View):
template_name = "mixins/partials/notify.html"
@ -21,7 +35,7 @@ class AdNuke(LoginRequiredMixin, OTPRequiredMixin, View):
run = synchronize_async_helper(AgoraClient(platform))
synchronize_async_helper(run.nuke_ads())
context = {"class": "success", "message": "Nuking ads"}
context = {"class": "success", "message": "Ads nuked"}
return render(request, self.template_name, context)
@ -35,7 +49,7 @@ class AdDist(LoginRequiredMixin, OTPRequiredMixin, View):
run = synchronize_async_helper(AgoraClient(platform))
synchronize_async_helper(run.dist_countries(ad))
context = {"class": "success", "message": "Distributing ads"}
context = {"class": "success", "message": "Ads distributed"}
return render(request, self.template_name, context)
@ -49,7 +63,7 @@ class AdRedist(LoginRequiredMixin, OTPRequiredMixin, View):
run = synchronize_async_helper(AgoraClient(platform))
synchronize_async_helper(run.redist_countries(ad))
context = {"class": "success", "message": "Updating ads"}
context = {"class": "success", "message": "Ads updated"}
return render(request, self.template_name, context)
@ -80,6 +94,13 @@ class AdList(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
"label": "Update ads",
"icon": "fa-solid fa-refresh",
},
{
"url": reverse("cheat"),
"action": "cheat",
"method": "get",
"label": "Run cheat",
"icon": "fa-solid fa-bolt",
},
{
"url": reverse("ad_nuke"),
"action": "nuke",

View File

@ -50,7 +50,7 @@ class RequestBankFetch(LoginRequiredMixin, OTPRequiredMixin, View):
class ReqsList(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
list_template = "partials/aggregator-info.html"
page_title = "Aggregator Info"
page_title = "Aggregator info"
context_object_name_singular = "requisition"
context_object_name = "requisitions"

View File

@ -17,7 +17,7 @@ class BanksCurrencies(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
"""
list_template = "partials/banks-currencies-list.html"
page_title = "Bank Currencies"
page_title = "Bank currencies"
context_object_name_singular = "currency"
context_object_name = "currencies"
@ -58,7 +58,7 @@ class BanksBalances(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
"""
list_template = "partials/banks-balances-list.html"
page_title = "Bank Balances"
page_title = "Bank balances"
context_object_name_singular = "balance"
context_object_name = "balances"
@ -100,7 +100,7 @@ class BanksTransactions(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
"""
list_template = "partials/banks-transactions-list.html"
page_title = "Bank Transactions"
page_title = "Bank transactions"
context_object_name_singular = "transaction"
context_object_name = "transactions"