|
|
|
@ -1,12 +1,10 @@
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
from cachalot.api import invalidate
|
|
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
|
|
|
from django.http import HttpResponse
|
|
|
|
|
from django.shortcuts import render
|
|
|
|
|
from django.views import View
|
|
|
|
|
from mixins.views import (
|
|
|
|
|
AbortSave,
|
|
|
|
|
ObjectCreate,
|
|
|
|
|
ObjectDelete,
|
|
|
|
|
ObjectList,
|
|
|
|
@ -17,8 +15,9 @@ from rest_framework import status
|
|
|
|
|
from rest_framework.parsers import JSONParser
|
|
|
|
|
from rest_framework.views import APIView
|
|
|
|
|
|
|
|
|
|
from core.forms import AssetGroupForm, AssetRestrictionForm
|
|
|
|
|
from core.models import AssetGroup, AssetRestriction
|
|
|
|
|
from core.forms import AssetGroupForm # , AssetRestrictionForm
|
|
|
|
|
from core.models import AssetGroup # , AssetRestriction
|
|
|
|
|
from core.trading import assetfilter
|
|
|
|
|
from core.util import logs
|
|
|
|
|
|
|
|
|
|
log = logs.get_logger(__name__)
|
|
|
|
@ -59,73 +58,73 @@ class AssetGroupDelete(LoginRequiredMixin, ObjectDelete):
|
|
|
|
|
# Asset Restrictions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AssetRestrictionsPermissionMixin:
|
|
|
|
|
# Check the user has permission to view the asset group
|
|
|
|
|
# We have a user check on the AssetRestriction, but we need to check the
|
|
|
|
|
# AssetGroup as well
|
|
|
|
|
def set_extra_args(self, user):
|
|
|
|
|
self.extra_permission_args = {
|
|
|
|
|
"group__user": user,
|
|
|
|
|
"group__pk": self.kwargs["group"],
|
|
|
|
|
}
|
|
|
|
|
# class AssetRestrictionsPermissionMixin:
|
|
|
|
|
# # Check the user has permission to view the asset group
|
|
|
|
|
# # We have a user check on the AssetRestriction, but we need to check the
|
|
|
|
|
# # AssetGroup as well
|
|
|
|
|
# def set_extra_args(self, user):
|
|
|
|
|
# self.extra_permission_args = {
|
|
|
|
|
# "group__user": user,
|
|
|
|
|
# "group__pk": self.kwargs["group"],
|
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AssetRestrictionList(
|
|
|
|
|
LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectList
|
|
|
|
|
):
|
|
|
|
|
list_template = "partials/assetrestriction-list.html"
|
|
|
|
|
model = AssetRestriction
|
|
|
|
|
page_title = "List of asset restrictions. Linked to asset groups."
|
|
|
|
|
page_subtitle = (
|
|
|
|
|
"Allows API calls to permit or prohibit trading on defined currency pairs."
|
|
|
|
|
)
|
|
|
|
|
# class AssetRestrictionList(
|
|
|
|
|
# LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectList
|
|
|
|
|
# ):
|
|
|
|
|
# list_template = "partials/assetrestriction-list.html"
|
|
|
|
|
# model = AssetRestriction
|
|
|
|
|
# page_title = "List of asset restrictions. Linked to asset groups."
|
|
|
|
|
# page_subtitle = (
|
|
|
|
|
# "Allows API calls to permit or prohibit trading on defined currency pairs."
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
|
|
list_url_name = "assetrestrictions"
|
|
|
|
|
list_url_args = ["type", "group"]
|
|
|
|
|
# list_url_name = "assetrestrictions"
|
|
|
|
|
# list_url_args = ["type", "group"]
|
|
|
|
|
|
|
|
|
|
submit_url_name = "assetrestriction_create"
|
|
|
|
|
submit_url_args = ["type", "group"]
|
|
|
|
|
# submit_url_name = "assetrestriction_create"
|
|
|
|
|
# submit_url_args = ["type", "group"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AssetRestrictionCreate(
|
|
|
|
|
LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectCreate
|
|
|
|
|
):
|
|
|
|
|
model = AssetRestriction
|
|
|
|
|
form_class = AssetRestrictionForm
|
|
|
|
|
# class AssetRestrictionCreate(
|
|
|
|
|
# LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectCreate
|
|
|
|
|
# ):
|
|
|
|
|
# model = AssetRestriction
|
|
|
|
|
# form_class = AssetRestrictionForm
|
|
|
|
|
|
|
|
|
|
submit_url_name = "assetrestriction_create"
|
|
|
|
|
submit_url_args = ["type", "group"]
|
|
|
|
|
# submit_url_name = "assetrestriction_create"
|
|
|
|
|
# submit_url_args = ["type", "group"]
|
|
|
|
|
|
|
|
|
|
def form_invalid(self, form):
|
|
|
|
|
"""If the form is invalid, render the invalid form."""
|
|
|
|
|
return self.get(self.request, **self.kwargs, form=form)
|
|
|
|
|
# def form_invalid(self, form):
|
|
|
|
|
# """If the form is invalid, render the invalid form."""
|
|
|
|
|
# return self.get(self.request, **self.kwargs, form=form)
|
|
|
|
|
|
|
|
|
|
def pre_save_mutate(self, user, obj):
|
|
|
|
|
try:
|
|
|
|
|
assetgroup = AssetGroup.objects.get(pk=self.kwargs["group"], user=user)
|
|
|
|
|
obj.group = assetgroup
|
|
|
|
|
except AssetGroup.DoesNotExist:
|
|
|
|
|
log.error(f"Asset Group {self.kwargs['group']} does not exist")
|
|
|
|
|
raise AbortSave("asset group does not exist or you don't have access")
|
|
|
|
|
# def pre_save_mutate(self, user, obj):
|
|
|
|
|
# try:
|
|
|
|
|
# assetgroup = AssetGroup.objects.get(pk=self.kwargs["group"], user=user)
|
|
|
|
|
# obj.group = assetgroup
|
|
|
|
|
# except AssetGroup.DoesNotExist:
|
|
|
|
|
# log.error(f"Asset Group {self.kwargs['group']} does not exist")
|
|
|
|
|
# raise AbortSave("asset group does not exist or you don't have access")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AssetRestrictionUpdate(
|
|
|
|
|
LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectUpdate
|
|
|
|
|
):
|
|
|
|
|
model = AssetRestriction
|
|
|
|
|
form_class = AssetRestrictionForm
|
|
|
|
|
# class AssetRestrictionUpdate(
|
|
|
|
|
# LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectUpdate
|
|
|
|
|
# ):
|
|
|
|
|
# model = AssetRestriction
|
|
|
|
|
# form_class = AssetRestrictionForm
|
|
|
|
|
|
|
|
|
|
submit_url_name = "assetrestriction_update"
|
|
|
|
|
submit_url_args = ["type", "pk", "group"]
|
|
|
|
|
# submit_url_name = "assetrestriction_update"
|
|
|
|
|
# submit_url_args = ["type", "pk", "group"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AssetRestrictionDelete(
|
|
|
|
|
LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectDelete
|
|
|
|
|
):
|
|
|
|
|
model = AssetRestriction
|
|
|
|
|
# class AssetRestrictionDelete(
|
|
|
|
|
# LoginRequiredMixin, AssetRestrictionsPermissionMixin, ObjectDelete
|
|
|
|
|
# ):
|
|
|
|
|
# model = AssetRestriction
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AssetRestrictionAPI(APIView):
|
|
|
|
|
class AssetGroupAPI(APIView):
|
|
|
|
|
parser_classes = [JSONParser]
|
|
|
|
|
|
|
|
|
|
def post(self, request, webhook_id):
|
|
|
|
@ -133,16 +132,16 @@ class AssetRestrictionAPI(APIView):
|
|
|
|
|
print(json.dumps(request.data, indent=2))
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
restriction = AssetRestriction.objects.get(webhook_id=webhook_id)
|
|
|
|
|
except AssetRestriction.DoesNotExist:
|
|
|
|
|
log.error(f"Asset restriction {webhook_id} does not exist")
|
|
|
|
|
group = AssetGroup.objects.get(webhook_id=webhook_id)
|
|
|
|
|
except AssetGroup.DoesNotExist:
|
|
|
|
|
log.error(f"Asset group {webhook_id} does not exist")
|
|
|
|
|
return HttpResponse(status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
|
|
|
|
if restriction.group is not None:
|
|
|
|
|
group = restriction.group
|
|
|
|
|
else:
|
|
|
|
|
log.error(f"Asset restriction {restriction} has no group")
|
|
|
|
|
return HttpResponse(status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
# if restriction.group is not None:
|
|
|
|
|
# group = restriction.group
|
|
|
|
|
# else:
|
|
|
|
|
# log.error(f"Asset restriction {restriction} has no group")
|
|
|
|
|
# return HttpResponse(status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
|
|
|
|
# if group.strategy_set.exists() is not None:
|
|
|
|
|
# strategies = group.strategy_set.all()
|
|
|
|
@ -151,18 +150,52 @@ class AssetRestrictionAPI(APIView):
|
|
|
|
|
# return HttpResponse(status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
# log.debug(f"Asset API {webhook_id} matched to strategies {strategies}")
|
|
|
|
|
|
|
|
|
|
if "meta" in request.data:
|
|
|
|
|
if "is_match" in request.data["meta"]:
|
|
|
|
|
is_match = request.data["meta"]["is_match"]
|
|
|
|
|
if isinstance(restriction.pairs_parsed, list):
|
|
|
|
|
for pair in restriction.pairs_parsed:
|
|
|
|
|
group.allowed[pair] = is_match
|
|
|
|
|
group.save()
|
|
|
|
|
invalidate(restriction)
|
|
|
|
|
invalidate(group)
|
|
|
|
|
|
|
|
|
|
return HttpResponse(status=status.HTTP_200_OK)
|
|
|
|
|
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
if "meta" not in request.data:
|
|
|
|
|
log.error(f"Asset API {webhook_id} has no meta")
|
|
|
|
|
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
if "is_match" not in request.data["meta"]:
|
|
|
|
|
log.error(f"Asset API {webhook_id} has no is_match")
|
|
|
|
|
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
is_match = request.data["meta"]["is_match"]
|
|
|
|
|
if "topic" not in request.data:
|
|
|
|
|
log.error(f"Asset API {webhook_id} has no topic")
|
|
|
|
|
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
|
|
|
|
topic = request.data["topic"]
|
|
|
|
|
print("YES TOPIC", topic)
|
|
|
|
|
new_pairs = []
|
|
|
|
|
pair_split = topic.split(",")
|
|
|
|
|
if not pair_split:
|
|
|
|
|
log.error(f"Asset API {webhook_id} topic {topic} is not a pair")
|
|
|
|
|
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
for pair in pair_split:
|
|
|
|
|
if pair:
|
|
|
|
|
new_pairs.append(pair.strip())
|
|
|
|
|
else:
|
|
|
|
|
log.error(f"Asset API {webhook_id} pair {pair} is not a pair")
|
|
|
|
|
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
print("YES PAIRS", new_pairs)
|
|
|
|
|
|
|
|
|
|
# Check if we have lower/upper bounds
|
|
|
|
|
if group.aggregation != "none":
|
|
|
|
|
if "aggs" in request.data["meta"]:
|
|
|
|
|
aggs = request.data["meta"]["aggs"]
|
|
|
|
|
if group.aggregation in aggs:
|
|
|
|
|
if "value" in aggs[group.aggregation]:
|
|
|
|
|
value = aggs[group.aggregation]["value"]
|
|
|
|
|
print("YES AVG", value)
|
|
|
|
|
is_match = assetfilter.check_asset_aggregation(
|
|
|
|
|
value, group.trigger_above, group.trigger_below
|
|
|
|
|
)
|
|
|
|
|
print("YES AVG IS MATCH", is_match)
|
|
|
|
|
|
|
|
|
|
for pair in new_pairs:
|
|
|
|
|
group.allowed[pair] = is_match is True or None
|
|
|
|
|
group.save()
|
|
|
|
|
|
|
|
|
|
return HttpResponse(status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Asset group allowed field
|
|
|
|
|