Show trades
This commit is contained in:
parent
1e7d8f6c8d
commit
fa7ea66c65
|
@ -143,4 +143,10 @@ urlpatterns = [
|
||||||
platforms.PlatformDelete.as_view(),
|
platforms.PlatformDelete.as_view(),
|
||||||
name="platform_delete",
|
name="platform_delete",
|
||||||
),
|
),
|
||||||
|
# Trades
|
||||||
|
path(
|
||||||
|
"trades/<str:type>/",
|
||||||
|
platforms.PlatformTrades.as_view(),
|
||||||
|
name="trades",
|
||||||
|
),
|
||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
|
|
|
@ -28,6 +28,15 @@ class LocalPlatformClient(ABC):
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
self.api = AgoraDesk(self.instance.token)
|
self.api = AgoraDesk(self.instance.token)
|
||||||
|
|
||||||
|
async def call_method(self, method, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Call a method using the self.api object.
|
||||||
|
"""
|
||||||
|
if hasattr(self.api, method):
|
||||||
|
return await getattr(self.api, method)(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Method {method} not found in {self.name} API.")
|
||||||
|
|
||||||
# TODO: do in schedules
|
# TODO: do in schedules
|
||||||
# def setup_loop(self):
|
# def setup_loop(self):
|
||||||
# """
|
# """
|
||||||
|
@ -62,19 +71,18 @@ class LocalPlatformClient(ABC):
|
||||||
|
|
||||||
async def wrap_dashboard(self, dash=None): # backwards compatibility with TX
|
async def wrap_dashboard(self, dash=None): # backwards compatibility with TX
|
||||||
if not dash:
|
if not dash:
|
||||||
dash = await self.api.dashboard()
|
# dash = await self.api.dashboard()
|
||||||
|
dash = await self.call("dashboard")
|
||||||
|
|
||||||
|
print("DASH22", dash)
|
||||||
# if dash["response"] is None:
|
# if dash["response"] is None:
|
||||||
# return False
|
# return False
|
||||||
dash_tmp = {}
|
dash_tmp = {}
|
||||||
if not dash:
|
if not dash:
|
||||||
return False
|
return False
|
||||||
if not dash["response"]:
|
|
||||||
return False
|
if dash["contact_count"] > 0:
|
||||||
if "data" not in dash["response"]:
|
for contact in dash["contact_list"]:
|
||||||
# log.error(f"Data not in dashboard response: {dash}")
|
|
||||||
return dash_tmp
|
|
||||||
if dash["response"]["data"]["contact_count"] > 0:
|
|
||||||
for contact in dash["response"]["data"]["contact_list"]:
|
|
||||||
contact_id = contact["data"]["contact_id"]
|
contact_id = contact["data"]["contact_id"]
|
||||||
dash_tmp[contact_id] = contact
|
dash_tmp[contact_id] = contact
|
||||||
return dash_tmp
|
return dash_tmp
|
||||||
|
|
|
@ -6,7 +6,7 @@ from core.clients.platform import LocalPlatformClient
|
||||||
from core.lib.money import Money
|
from core.lib.money import Money
|
||||||
|
|
||||||
|
|
||||||
class AgoraClient(BaseClient, LocalPlatformClient):
|
class AgoraClient(LocalPlatformClient, BaseClient):
|
||||||
"""
|
"""
|
||||||
AgoraDesk API handler.
|
AgoraDesk API handler.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -87,6 +87,7 @@ class AgoraDesk:
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.post(api_call_url, **cast) as response_raw:
|
async with session.post(api_call_url, **cast) as response_raw:
|
||||||
response = await response_raw.json()
|
response = await response_raw.json()
|
||||||
|
status_code = response_raw.status
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# response = httpx.get(url=api_call_url, headers=headers, params=query_values)
|
# response = httpx.get(url=api_call_url, headers=headers, params=query_values)
|
||||||
|
@ -95,12 +96,15 @@ class AgoraDesk:
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get(api_call_url, **cast) as response_raw:
|
async with session.get(api_call_url, **cast) as response_raw:
|
||||||
response = await response_raw.json()
|
response = await response_raw.json()
|
||||||
|
status_code = response_raw.status
|
||||||
if response:
|
if response:
|
||||||
|
print("YES RESPONSE", response)
|
||||||
logger.debug(response)
|
logger.debug(response)
|
||||||
result["status"] = response.code
|
result["status"] = status_code
|
||||||
if response.code == 200:
|
if status_code == 200:
|
||||||
result["success"] = True
|
result["success"] = True
|
||||||
result["message"] = "OK"
|
result["message"] = "OK"
|
||||||
|
result["response"] = response
|
||||||
else:
|
else:
|
||||||
result["message"] = "API ERROR"
|
result["message"] = "API ERROR"
|
||||||
|
|
||||||
|
|
|
@ -107,5 +107,4 @@ class AntiFraud(object):
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
antifraud = AntiFraud()
|
antifraud = AntiFraud()
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
from core.lib.schemas import agora_s # noqa
|
||||||
from core.lib.schemas import nordigen_s # noqa
|
from core.lib.schemas import nordigen_s # noqa
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class ContactDataBuyerSeller(BaseModel):
|
||||||
|
username: str
|
||||||
|
name: str
|
||||||
|
feedback_score: int
|
||||||
|
trade_count: str
|
||||||
|
last_online: str
|
||||||
|
|
||||||
|
|
||||||
|
class ContactDataAd(BaseModel):
|
||||||
|
payment_method: str
|
||||||
|
trade_type: str
|
||||||
|
advertiser: ContactDataBuyerSeller
|
||||||
|
asset: str
|
||||||
|
id: str
|
||||||
|
|
||||||
|
|
||||||
|
class ContactData(BaseModel):
|
||||||
|
buyer: ContactDataBuyerSeller
|
||||||
|
seller: ContactDataBuyerSeller
|
||||||
|
amount: str
|
||||||
|
amount_xmr: str
|
||||||
|
fee_xmr: str
|
||||||
|
advertisement: ContactDataAd
|
||||||
|
contact_id: str
|
||||||
|
currency: str
|
||||||
|
country: str
|
||||||
|
account_info: str
|
||||||
|
price_equation: str
|
||||||
|
is_buying: bool
|
||||||
|
is_selling: bool
|
||||||
|
created_at: str
|
||||||
|
escrowed_at: str
|
||||||
|
funded_at: str
|
||||||
|
canceled_at: str | None
|
||||||
|
closed_at: str | None
|
||||||
|
msg: str
|
||||||
|
released_at: str | None
|
||||||
|
payment_completed_at: str | None
|
||||||
|
disputed_at: str | None
|
||||||
|
arbitrated: bool
|
||||||
|
transfer_to_seller_non_custodial_wallet_transaction_confirmations: str | None
|
||||||
|
transfer_to_buyer_settlement_wallet_transaction_id: str | None
|
||||||
|
transfer_to_buyer_settlement_wallet_transaction_key: str | None
|
||||||
|
buyer_settlement_address: str | None
|
||||||
|
buyer_settlement_fee_level: str | None
|
||||||
|
seller_non_custodial_wallet_mnemonic: str | None
|
||||||
|
transfer_to_seller_non_custodial_wallet_transaction_id: str | None
|
||||||
|
|
||||||
|
|
||||||
|
class ContactActions(BaseModel):
|
||||||
|
advertisement_public_view: str
|
||||||
|
advertisement_url: str
|
||||||
|
message_post_url: str
|
||||||
|
messages_url: str
|
||||||
|
release_url: str
|
||||||
|
|
||||||
|
|
||||||
|
class Contact(BaseModel):
|
||||||
|
data: ContactData
|
||||||
|
actions: ContactActions
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseData(BaseModel):
|
||||||
|
contact_count: int
|
||||||
|
contact_list: list[Contact]
|
||||||
|
|
||||||
|
|
||||||
|
class Response(BaseModel):
|
||||||
|
data: ResponseData
|
||||||
|
|
||||||
|
|
||||||
|
class Dashboard(BaseModel):
|
||||||
|
success: bool
|
||||||
|
message: str
|
||||||
|
response: Response
|
||||||
|
|
||||||
|
|
||||||
|
DashboardSchema = {
|
||||||
|
"success": "success",
|
||||||
|
"message": "message",
|
||||||
|
"contact_count": "response.data.contact_count",
|
||||||
|
"contact_list": "response.data.contact_list",
|
||||||
|
}
|
|
@ -122,6 +122,10 @@ class Platform(models.Model):
|
||||||
|
|
||||||
enabled = models.BooleanField(default=True)
|
enabled = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_for_user(cls, user):
|
||||||
|
return cls.objects.filter(user=user, enabled=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def currencies(self):
|
def currencies(self):
|
||||||
return Aggregator.get_currencies_for_platform(self)
|
return Aggregator.get_currencies_for_platform(self)
|
||||||
|
|
|
@ -242,6 +242,12 @@
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="navbar-dropdown">
|
<div class="navbar-dropdown">
|
||||||
|
<a class="navbar-item" href="{% url 'trades' type='page' %}">
|
||||||
|
Trades
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="#">
|
||||||
|
Wallets
|
||||||
|
</a>
|
||||||
<a class="navbar-item" href="#">
|
<a class="navbar-item" href="#">
|
||||||
Advert Configuration
|
Advert Configuration
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
{% load cache %}
|
||||||
|
{% load cachalot cache %}
|
||||||
|
{% get_last_invalidation 'core.Platform' as last %}
|
||||||
|
{% include 'mixins/partials/notify.html' %}
|
||||||
|
{# cache 600 objects_platform_trades request.user.id object_list type last #}
|
||||||
|
{% for platform_name, trade_map in object_list.items %}
|
||||||
|
<h2 class="title is-4">{{ platform_name }}</h2>
|
||||||
|
<table
|
||||||
|
class="table is-fullwidth is-hoverable"
|
||||||
|
hx-target="#{{ context_object_name }}-table"
|
||||||
|
id="{{ context_object_name }}-table"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-trigger="{{ context_object_name_singular }}Event from:body"
|
||||||
|
hx-get="{{ list_url }}">
|
||||||
|
<thead>
|
||||||
|
<th>id</th>
|
||||||
|
<th>buyer</th>
|
||||||
|
<th>seller</th>
|
||||||
|
<th>amount</th>
|
||||||
|
<th>crypto</th>
|
||||||
|
<th>provider</th>
|
||||||
|
<th>type</th>
|
||||||
|
<th>actions</th>
|
||||||
|
</thead>
|
||||||
|
{% for item in trade_map.values %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
class="has-text-grey"
|
||||||
|
onclick="window.prompt('Copy to clipboard: Ctrl+C, Enter', '{{ item.data.contact_id }}/');">
|
||||||
|
<span class="icon" data-tooltip="Copy to clipboard">
|
||||||
|
<i class="fa-solid fa-copy" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td data-tooltip="{{ item.data.buyer.name }}
|
||||||
|
Trades: {{ item.data.buyer.trade_count }}
|
||||||
|
Last online: {{ item.data.buyer.last_online }}">{{ item.data.buyer.username }}</td>
|
||||||
|
<td data-tooltip="{{ item.data.seller.name }}
|
||||||
|
Trades: {{ item.data.seller.trade_count }}
|
||||||
|
Last online: {{ item.data.seller.last_online }}">{{ item.data.seller.username }}</td>
|
||||||
|
<td>{{ item.data.amount }} {{ item.data.currency }}</td>
|
||||||
|
<td>{{ item.data.amount_xmr }} XMR</td>
|
||||||
|
<td>{{ item.data.advertisement.payment_method }}</td>
|
||||||
|
<td>{{ item.data.advertisement.trade_type }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="buttons">
|
||||||
|
<button
|
||||||
|
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||||
|
hx-get="{# url 'platform_update' type=type pk=item.id #}"
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-target="#{{ type }}s-here"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
class="button">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fa-solid fa-pencil"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||||
|
hx-delete="{# url 'platform_delete' type=type pk=item.id #}"
|
||||||
|
hx-trigger="click"
|
||||||
|
hx-target="#modals-here"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
hx-confirm="Are you sure you wish to delete {{ item.name }}?"
|
||||||
|
class="button">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fa-solid fa-xmark"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</table>
|
||||||
|
{% endfor %}
|
||||||
|
{# endcache #}
|
|
@ -11,16 +11,37 @@ from mixins.views import ( # ObjectRead,
|
||||||
)
|
)
|
||||||
from two_factor.views.mixins import OTPRequiredMixin
|
from two_factor.views.mixins import OTPRequiredMixin
|
||||||
|
|
||||||
# from core.clients.platforms.agora import AgoraClient
|
from core.clients.platforms.agora import AgoraClient
|
||||||
from core.forms import PlatformForm
|
from core.forms import PlatformForm
|
||||||
from core.models import Platform
|
from core.models import Platform
|
||||||
from core.util import logs
|
from core.util import logs
|
||||||
|
from core.views.helpers import synchronize_async_helper
|
||||||
# from core.views.helpers import synchronize_async_helper
|
|
||||||
|
|
||||||
log = logs.get_logger(__name__)
|
log = logs.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformTrades(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
|
||||||
|
list_template = "partials/platform-trades.html"
|
||||||
|
page_title = "List of trades"
|
||||||
|
|
||||||
|
list_url_name = "trades"
|
||||||
|
list_url_args = ["type"]
|
||||||
|
|
||||||
|
context_object_name_singular = "trade"
|
||||||
|
context_object_name = "trades"
|
||||||
|
|
||||||
|
def get_queryset(self, **kwargs):
|
||||||
|
platforms = Platform.get_for_user(self.request.user)
|
||||||
|
total_trades = {}
|
||||||
|
for platform in platforms:
|
||||||
|
run = synchronize_async_helper(AgoraClient(platform))
|
||||||
|
dash = synchronize_async_helper(run.wrap_dashboard())
|
||||||
|
print("DASH", dash)
|
||||||
|
total_trades[platform.name] = dash
|
||||||
|
|
||||||
|
return total_trades
|
||||||
|
|
||||||
|
|
||||||
class PlatformList(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
|
class PlatformList(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
|
||||||
list_template = "partials/platform-list.html"
|
list_template = "partials/platform-list.html"
|
||||||
model = Platform
|
model = Platform
|
||||||
|
|
|
@ -108,3 +108,6 @@ class AntiFraud(util.Base):
|
||||||
trade_id,
|
trade_id,
|
||||||
f"Hi! To continue the trade, please complete the verification form: {auth_url}",
|
f"Hi! To continue the trade, please complete the verification form: {auth_url}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
antifraud = AntiFraud()
|
||||||
|
|
Loading…
Reference in New Issue