Allow changing the asset filter list

This commit is contained in:
Mark Veidemanis 2023-02-11 18:46:26 +00:00
parent da9f32e882
commit 287facbab2
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
8 changed files with 178 additions and 12 deletions

View File

@ -284,4 +284,20 @@ urlpatterns = [
assets.AssetRestrictionDelete.as_view(),
name="assetrestriction_delete",
),
# Asset group filters
path(
"assetfilter/<str:group_id>/flip/<str:symbol>/",
assets.AssetFilterFlip.as_view(),
name="assetfilter_flip",
),
path(
"assetfilter/<str:group_id>/delete/<str:symbol>/",
assets.AssetFilterDelete.as_view(),
name="assetfilter_delete",
),
path(
"assetfilter/<str:type>/view/<str:group_id>/",
assets.AssetFilterList.as_view(),
name="assetfilters",
),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

View File

@ -94,7 +94,7 @@ class RiskModelAdmin(admin.ModelAdmin):
class AssetGroupAdmin(admin.ModelAdmin):
list_display = ("user", "name", "description", "account")
list_display = ("user", "name", "description")
class AssetRestrictionAdmin(admin.ModelAdmin):

View File

@ -309,12 +309,10 @@ class AssetGroupForm(RestrictedFormMixin, ModelForm):
fields = (
"name",
"description",
"account",
)
help_texts = {
"name": "Name of the asset group. Informational only.",
"description": "Description of the asset group. Informational only.",
"account": "Account to pull assets from.",
}

View File

@ -0,0 +1,17 @@
# Generated by Django 4.1.6 on 2023-02-11 18:46
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('core', '0057_alter_assetgroup_account_and_more'),
]
operations = [
migrations.RemoveField(
model_name='assetgroup',
name='account',
),
]

View File

@ -411,11 +411,6 @@ class AssetGroup(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
# Account for checking pairs on children if specified
account = models.ForeignKey(
Account, on_delete=models.PROTECT, null=True, blank=True
)
# Dict like {"RUB": True, "USD": False}
allowed = models.JSONField(null=True, blank=True, default=dict)

View File

@ -0,0 +1,59 @@
{% load cache %}
{% load cachalot cache %}
{% get_last_invalidation 'core.AssetGroup' as last %}
{% include 'mixins/partials/notify.html' %}
{% cache 600 objects_assetgroups_field request.user.id object_list last %}
<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>symbol</th>
<th>status</th>
<th>actions</th>
</thead>
{% for key, item in object_list.items %}
<tr class="
{% if item is True %}has-background-success-light
{% elif item is False %}has-background-danger-light
{% endif %}">
<td>{{ key }}</td>
<td>{{ item }}</td>
<td>
<div class="buttons">
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-get="{% url 'assetfilter_flip' group_id=group_id symbol=key %}"
hx-trigger="click"
hx-target="#modals-here"
hx-swap="innerHTML"
class="button">
<span class="icon-text">
<span class="icon" data-tooltip="Flip direction">
<i class="fa-solid fa-arrows-repeat"></i>
</span>
</span>
</button>
<button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-delete="{% url 'assetfilter_delete' group_id=group_id symbol=key %}"
hx-trigger="click"
hx-target="#modals-here"
hx-swap="innerHTML"
class="button">
<span class="icon-text">
<span class="icon">
<i class="fa-solid fa-xmark"></i>
</span>
</span>
</button>
</div>
</td>
</tr>
{% endfor %}
</table>
{% endcache %}

View File

@ -15,7 +15,6 @@
<th>user</th>
<th>name</th>
<th>description</th>
<th>account</th>
<th>status</th>
<th>restrictions</th>
<th>actions</th>
@ -26,8 +25,16 @@
<td>{{ item.user }}</td>
<td>{{ item.name }}</td>
<td>{{ item.description }}</td>
<td>{{ item.account }}</td>
<td>{{ item.matches }}</td>
<td>
<a
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-get="{% url 'assetfilters' type=type group_id=item.id %}"
hx-trigger="click"
hx-target="#{{ type }}s-here"
hx-swap="innerHTML">
{{ item.matches }}
</a>
</td>
<td>{{ item.restrictions }}</td>
<td>
<div class="buttons">

View File

@ -3,7 +3,16 @@ import json
from cachalot.api import invalidate
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse
from mixins.views import AbortSave, ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
from django.shortcuts import render
from django.views import View
from mixins.views import (
AbortSave,
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectNameMixin,
ObjectUpdate,
)
from rest_framework import status
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
@ -154,3 +163,68 @@ class AssetRestrictionAPI(APIView):
return HttpResponse(status=status.HTTP_200_OK)
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
# Asset group allowed field
class AssetFilterList(LoginRequiredMixin, ObjectList):
list_template = "partials/asset-filter-list.html"
page_title = "List of asset filters."
page_subtitle = None
context_object_name_singular = "asset filter"
context_object_name = "asset filters"
list_url_name = "assetfilters"
list_url_args = ["type", "group_id"]
def get_queryset(self, **kwargs):
group_id = kwargs.get("group_id", None)
self.extra_context = {"group_id": group_id}
try:
group = AssetGroup.objects.get(id=group_id, user=self.request.user)
except AssetGroup.DoesNotExist:
context = {"message": "Asset group does not exist", "class": "danger"}
return self.render_to_response(context)
return group.allowed
class AssetFilterFlip(LoginRequiredMixin, ObjectNameMixin, View):
template_name = "mixins/partials/notify.html"
model = AssetGroup
def get(self, request, group_id, symbol):
try:
group = AssetGroup.objects.get(id=group_id, user=request.user)
except AssetGroup.DoesNotExist:
context = {"message": "Asset group does not exist", "class": "danger"}
return render(request, self.template_name, context)
if symbol not in group.allowed:
context = {"message": "Asset filter does not exist", "class": "danger"}
return render(request, self.template_name, context)
group.allowed[symbol] = not group.allowed[symbol]
group.save()
context = {"message": "Asset filter updated", "class": "success"}
response = render(request, self.template_name, context)
response["HX-Trigger"] = "assetgroupEvent"
return response
class AssetFilterDelete(LoginRequiredMixin, ObjectNameMixin, View):
template_name = "mixins/partials/notify.html"
model = AssetGroup
def delete(self, request, group_id, symbol):
try:
group = AssetGroup.objects.get(id=group_id, user=request.user)
except AssetGroup.DoesNotExist:
context = {"message": "Asset group does not exist", "class": "danger"}
return render(request, self.template_name, context)
if symbol not in group.allowed:
context = {"message": "Asset filter does not exist", "class": "danger"}
return render(request, self.template_name, context)
del group.allowed[symbol]
group.save()
context = {"message": "Asset filter deleted", "class": "success"}
response = render(request, self.template_name, context)
response["HX-Trigger"] = "assetgroupEvent"
return response