Upgrade Bulma and begin drug info screen and favourites
This commit is contained in:
parent
4c8411b863
commit
46b1858897
|
@ -61,4 +61,5 @@ DRUGS_DEFAULT_PARAMS = {
|
||||||
"size": "15",
|
"size": "15",
|
||||||
"sorting": "desc",
|
"sorting": "desc",
|
||||||
"source": "substances",
|
"source": "substances",
|
||||||
|
"index": "main",
|
||||||
}
|
}
|
||||||
|
|
31
app/urls.py
31
app/urls.py
|
@ -20,7 +20,7 @@ from django.contrib.auth.views import LogoutView
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from two_factor.urls import urlpatterns as tf_urls
|
from two_factor.urls import urlpatterns as tf_urls
|
||||||
|
|
||||||
from core.views import base, demo, drugs, notifications, search
|
from core.views import base, demo, drugs, favourites, notifications, search
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("__debug__/", include("debug_toolbar.urls")),
|
path("__debug__/", include("debug_toolbar.urls")),
|
||||||
|
@ -57,6 +57,11 @@ urlpatterns = [
|
||||||
drugs.DrugDelete.as_view(),
|
drugs.DrugDelete.as_view(),
|
||||||
name="drug_delete",
|
name="drug_delete",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"drugs/<str:type>/detail/<str:pk>/",
|
||||||
|
drugs.DrugDetail.as_view(),
|
||||||
|
name="drug_detail",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"drugs/clear/all/",
|
"drugs/clear/all/",
|
||||||
drugs.DrugClear.as_view(),
|
drugs.DrugClear.as_view(),
|
||||||
|
@ -70,4 +75,28 @@ urlpatterns = [
|
||||||
# Drug search
|
# Drug search
|
||||||
path("search/", search.DrugsTableView.as_view(), name="search"),
|
path("search/", search.DrugsTableView.as_view(), name="search"),
|
||||||
path("search/partial/", search.DrugsTableView.as_view(), name="search_partial"),
|
path("search/partial/", search.DrugsTableView.as_view(), name="search_partial"),
|
||||||
|
# Favourites
|
||||||
|
path(
|
||||||
|
"favourites/<str:type>/", favourites.FavouriteList.as_view(), name="favourites"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"favourites/<str:type>/create/",
|
||||||
|
favourites.FavouriteCreate.as_view(),
|
||||||
|
name="favourite_create",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"favourites/<str:type>/update/<str:pk>/",
|
||||||
|
favourites.FavouriteUpdate.as_view(),
|
||||||
|
name="favourite_update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"favourites/<str:type>/delete/<str:pk>/",
|
||||||
|
favourites.FavouriteDelete.as_view(),
|
||||||
|
name="favourite_delete",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"favourites/<str:type>/detail/<str:pk>/",
|
||||||
|
favourites.FavouriteDetail.as_view(),
|
||||||
|
name="favourite_detail",
|
||||||
|
),
|
||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
|
|
|
@ -11,6 +11,7 @@ from .models import (
|
||||||
Entry,
|
Entry,
|
||||||
Experience,
|
Experience,
|
||||||
ExperienceDose,
|
ExperienceDose,
|
||||||
|
Favourite,
|
||||||
NotificationSettings,
|
NotificationSettings,
|
||||||
Source,
|
Source,
|
||||||
Timing,
|
Timing,
|
||||||
|
@ -57,3 +58,4 @@ admin.site.register(Experience)
|
||||||
admin.site.register(Source)
|
admin.site.register(Source)
|
||||||
admin.site.register(SEI)
|
admin.site.register(SEI)
|
||||||
admin.site.register(ExperienceDose)
|
admin.site.register(ExperienceDose)
|
||||||
|
admin.site.register(Favourite)
|
||||||
|
|
|
@ -21,6 +21,7 @@ class PsychWikiClient(GraphQLClient, BaseClient):
|
||||||
Store the data in the database.
|
Store the data in the database.
|
||||||
"""
|
"""
|
||||||
for drug in data["substances"]:
|
for drug in data["substances"]:
|
||||||
|
print("DRUG ITER", drug)
|
||||||
try:
|
try:
|
||||||
drug_obj = Drug.objects.get(name=drug["name"])
|
drug_obj = Drug.objects.get(name=drug["name"])
|
||||||
except Drug.DoesNotExist:
|
except Drug.DoesNotExist:
|
||||||
|
@ -89,6 +90,7 @@ class PsychWikiClient(GraphQLClient, BaseClient):
|
||||||
)
|
)
|
||||||
if created or dosage not in drug_obj.dosages.all():
|
if created or dosage not in drug_obj.dosages.all():
|
||||||
drug_obj.dosages.add(dosage)
|
drug_obj.dosages.add(dosage)
|
||||||
|
print("YES DOSAGE", drug_obj.dosages)
|
||||||
|
|
||||||
# Parsing timing information
|
# Parsing timing information
|
||||||
timing = roa["duration"]
|
timing = roa["duration"]
|
||||||
|
|
|
@ -89,6 +89,8 @@ def drug_query(request, query_params, size=None, tags=None):
|
||||||
|
|
||||||
# Q/T - Query/Tags
|
# Q/T - Query/Tags
|
||||||
result = run_query(query_params, tags, size, sources, ranges, sort)
|
result = run_query(query_params, tags, size, sources, ranges, sort)
|
||||||
|
for x in result:
|
||||||
|
print(x.dosages)
|
||||||
rtrn = {
|
rtrn = {
|
||||||
"object_list": result,
|
"object_list": result,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ from mixins.restrictions import RestrictedFormMixin
|
||||||
|
|
||||||
from mxs.restrictions import RestrictedFormMixinStaff
|
from mxs.restrictions import RestrictedFormMixinStaff
|
||||||
|
|
||||||
from .models import Drug, NotificationSettings, User
|
from .models import Drug, Favourite, NotificationSettings, User
|
||||||
|
|
||||||
# Create your forms here.
|
# Create your forms here.
|
||||||
|
|
||||||
|
@ -78,3 +78,20 @@ class DrugForm(RestrictedFormMixinStaff, ModelForm):
|
||||||
"actions": "Actions, what does it do on an objective level?",
|
"actions": "Actions, what does it do on an objective level?",
|
||||||
"experiences": "Experiences, what do people experience?",
|
"experiences": "Experiences, what do people experience?",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FavouriteForm(RestrictedFormMixin, ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Favourite
|
||||||
|
fields = (
|
||||||
|
"nickname",
|
||||||
|
"name",
|
||||||
|
"drug_class",
|
||||||
|
"common_name",
|
||||||
|
)
|
||||||
|
help_texts = {
|
||||||
|
"nickname": "Call it whatever you like.",
|
||||||
|
"name": "Lysergic acid diethylamide, Phenibut",
|
||||||
|
"drug_class": "Psychedelic, Sedative, Stimulant",
|
||||||
|
"common_name": "LSD",
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Generated by Django 5.0.3 on 2024-05-17 19:01
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0009_alter_drug_common_name_alter_drug_drug_class'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Price',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('amount_mg', models.IntegerField()),
|
||||||
|
('price_gbp', models.FloatField()),
|
||||||
|
('note', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FavouriteDrug',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('nickname', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('drug_class', models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
('common_name', models.CharField(blank=True, max_length=1024, null=True)),
|
||||||
|
('actions', models.ManyToManyField(blank=True, to='core.action')),
|
||||||
|
('dosages', models.ManyToManyField(blank=True, to='core.dosage')),
|
||||||
|
('effects', models.ManyToManyField(blank=True, to='core.effect')),
|
||||||
|
('experiences', models.ManyToManyField(blank=True, to='core.experience')),
|
||||||
|
('links', models.ManyToManyField(blank=True, to='core.entry')),
|
||||||
|
('original', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.drug')),
|
||||||
|
('timings', models.ManyToManyField(blank=True, to='core.timing')),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
('prices', models.ManyToManyField(blank=True, null=True, to='core.price')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 5.0.3 on 2024-05-17 19:02
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0010_price_favouritedrug'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='FavouriteDrug',
|
||||||
|
new_name='Favourite',
|
||||||
|
),
|
||||||
|
]
|
|
@ -188,7 +188,7 @@ class Dosage(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
text = (
|
text = (
|
||||||
f"{self.threshold_lower} {self.light_lower} {self.common_lower} "
|
f"{self.threshold_lower} {self.light_lower} {self.common_lower} "
|
||||||
"{self.strong_lower} {self.heavy_lower}"
|
f"{self.strong_lower} {self.heavy_lower}"
|
||||||
)
|
)
|
||||||
return f"{self.roa} {text} ({self.unit})"
|
return f"{self.roa} {text} ({self.unit})"
|
||||||
|
|
||||||
|
@ -409,6 +409,69 @@ class Drug(models.Model):
|
||||||
return f"{self.name} ({self.common_name})"
|
return f"{self.name} ({self.common_name})"
|
||||||
|
|
||||||
|
|
||||||
|
class Price(models.Model):
|
||||||
|
"""
|
||||||
|
Price of a drug.
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||||
|
amount_mg = models.IntegerField()
|
||||||
|
price_gbp = models.FloatField()
|
||||||
|
note = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
|
# class Stack: references, times
|
||||||
|
# class StackUnit: reference, times, dose_mg
|
||||||
|
|
||||||
|
|
||||||
|
class Favourite(models.Model):
|
||||||
|
"""
|
||||||
|
Model of a drug. Owned by a user and customisable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
# Nickname
|
||||||
|
nickname = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
|
# Prices, how much certain mass of this substance costs
|
||||||
|
prices = models.ManyToManyField(Price, blank=True, null=True)
|
||||||
|
|
||||||
|
# Internals
|
||||||
|
original = models.ForeignKey(Drug, on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
|
|
||||||
|
# Below duplicates Drug
|
||||||
|
# Lysergic acid diethylamide, Phenibut
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
# Psychedelic, Sedative, Stimulant
|
||||||
|
drug_class = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
|
# LSD
|
||||||
|
common_name = models.CharField(max_length=1024, blank=True, null=True)
|
||||||
|
|
||||||
|
# Factsheets, posts
|
||||||
|
links = models.ManyToManyField(Entry, blank=True)
|
||||||
|
|
||||||
|
# Dosages, how much to take to get a certain effect
|
||||||
|
dosages = models.ManyToManyField(Dosage, blank=True)
|
||||||
|
|
||||||
|
# Timings, how long to wait to reach maximum intensity (and others)
|
||||||
|
timings = models.ManyToManyField(Timing, blank=True)
|
||||||
|
|
||||||
|
# Effects, what does it do on a subjective level?
|
||||||
|
effects = models.ManyToManyField(Effect, blank=True)
|
||||||
|
|
||||||
|
# Actions, what does it do on an objective level?
|
||||||
|
actions = models.ManyToManyField(Action, blank=True)
|
||||||
|
|
||||||
|
# Experiences, what do people experience?
|
||||||
|
experiences = models.ManyToManyField(Experience, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.name} ({self.common_name})"
|
||||||
|
|
||||||
|
|
||||||
# class Perms(models.Model):
|
# class Perms(models.Model):
|
||||||
# class Meta:
|
# class Meta:
|
||||||
# permissions = (
|
# permissions = (
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -209,6 +209,12 @@
|
||||||
<a class="navbar-item" href="{% url 'home' %}">
|
<a class="navbar-item" href="{% url 'home' %}">
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
|
<a class="navbar-item" href="{% url 'home' %}">
|
||||||
|
Search
|
||||||
|
</a>
|
||||||
|
<a class="navbar-item" href="{% url 'favourites' type='page' %}">
|
||||||
|
Favourites
|
||||||
|
</a>
|
||||||
{% if user.is_superuser %}
|
{% if user.is_superuser %}
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
<a class="navbar-link">
|
<a class="navbar-link">
|
||||||
|
@ -225,9 +231,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="navbar-item" href="{% url 'home' %}">
|
|
||||||
Search
|
|
||||||
</a>
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
{% load pretty %}
|
||||||
|
|
||||||
|
{% load cache %}
|
||||||
|
|
||||||
|
{% cache 600 favourite_detail request.user.id object %}
|
||||||
|
{% include 'mixins/partials/notify.html' %}
|
||||||
|
|
||||||
|
{% if object is not None %}
|
||||||
|
<h1 class="title">{{ object.name }} - {{ object.nickname }} - {{ object.common_name }}</h1>
|
||||||
|
<p class="subtitle"><strong>{{ object.drug_class }}</strong></p>
|
||||||
|
<div class="block">
|
||||||
|
<a class="button is-info" href="#">Prices</a>
|
||||||
|
<a class="button is-info" href="#">More info</a>
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="cell">
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="subtitle">Dosage</h2>
|
||||||
|
<ul>
|
||||||
|
{% for dose in object.dosages.all %}
|
||||||
|
<li>{{ dose }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="subtitle">Timing</h2>
|
||||||
|
<ul>
|
||||||
|
{% for timing in object.timings.all %}
|
||||||
|
<li>{{ timing }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="subtitle">Links</h2>
|
||||||
|
<ul>
|
||||||
|
{% for link in object.links.all %}
|
||||||
|
<li>{{ link }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="cell">
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="subtitle">Actions</h2>
|
||||||
|
<ul>
|
||||||
|
{% for action in object.actions.all %}
|
||||||
|
<li>{{ action }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="subtitle">Effects</h2>
|
||||||
|
<ul>
|
||||||
|
{% for effect in object.effects.all %}
|
||||||
|
<li>{{ effect }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<h2 class="subtitle">Experiences</h2>
|
||||||
|
<ul>
|
||||||
|
{% for exp in object.experiences.all %}
|
||||||
|
<li>{{ exp }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endcache %}
|
|
@ -64,6 +64,15 @@
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
<a href="{% url 'drug_detail' type='page' pk=item.id %}"><button
|
||||||
|
class="button">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fa-solid fa-eye"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
{% load cache %}
|
||||||
|
{% load cachalot cache %}
|
||||||
|
{% get_last_invalidation 'core.Favourite' as last %}
|
||||||
|
{% include 'mixins/partials/notify.html' %}
|
||||||
|
{% cache 600 objects_favourittes 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>id</th>
|
||||||
|
<th>nickname</th>
|
||||||
|
<th>prices</th>
|
||||||
|
<th>name</th>
|
||||||
|
<th>drug class</th>
|
||||||
|
<th>common name</th>
|
||||||
|
<th>links</th>
|
||||||
|
<th>dosages</th>
|
||||||
|
<th>timings</th>
|
||||||
|
<th>effects</th>
|
||||||
|
<th>actions</th>
|
||||||
|
<th>experiences</th>
|
||||||
|
<th>actions</th>
|
||||||
|
</thead>
|
||||||
|
{% for item in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.id }}</td>
|
||||||
|
<td>{{ item.nickname }}</td>
|
||||||
|
<td>{{ item.prices.count }}</td>
|
||||||
|
<td>{{ item.name }}</td>
|
||||||
|
<td>{{ item.drug_class }}</td>
|
||||||
|
<td>{{ item.common_name }}</td>
|
||||||
|
<td>{{ item.links.count }}</td>
|
||||||
|
<td>{{ item.dosages.count }}</td>
|
||||||
|
<td>{{ item.timings.count }}</td>
|
||||||
|
<td>{{ item.effects.count }}</td>
|
||||||
|
<td>{{ item.actions.count }}</td>
|
||||||
|
<td>{{ item.experiences.count }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="buttons">
|
||||||
|
<button
|
||||||
|
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||||
|
hx-get="{% url 'favourite_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 'favourite_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>
|
||||||
|
<a href="{% url 'favourite_detail' type='page' pk=item.id %}"><button
|
||||||
|
class="button">
|
||||||
|
<span class="icon-text">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fa-solid fa-eye"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</table>
|
||||||
|
{% endcache %}
|
|
@ -5,7 +5,7 @@
|
||||||
{% load urlsafe %}
|
{% load urlsafe %}
|
||||||
{% load cache %}
|
{% load cache %}
|
||||||
|
|
||||||
{% cache 3600 results_table_full request.user.id table %}
|
{# cache 3600 results_table_full request.user.id table #}
|
||||||
{% block table-wrapper %}
|
{% block table-wrapper %}
|
||||||
<script src="{% static 'js/column-shifter.js' %}"></script>
|
<script src="{% static 'js/column-shifter.js' %}"></script>
|
||||||
<div id="drilldown-table" class="column-shifter-container" style="position:relative; z-index:1;">
|
<div id="drilldown-table" class="column-shifter-container" style="position:relative; z-index:1;">
|
||||||
|
@ -128,14 +128,7 @@
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr class="
|
<tr>
|
||||||
{% if row.cells.exemption == True %}has-background-grey-lighter
|
|
||||||
{% elif cell == 'join' %}has-background-success-light
|
|
||||||
{% elif cell == 'quit' %}has-background-danger-light
|
|
||||||
{% elif cell == 'kick' %}has-background-danger-light
|
|
||||||
{% elif cell == 'part' %}has-background-warning-light
|
|
||||||
{% elif cell == 'mode' %}has-background-info-light
|
|
||||||
{% endif %}">
|
|
||||||
{% for column, cell in row.items %}
|
{% for column, cell in row.items %}
|
||||||
{% if column.name in show %}
|
{% if column.name in show %}
|
||||||
{% block table.tbody.td %}
|
{% block table.tbody.td %}
|
||||||
|
@ -145,213 +138,6 @@
|
||||||
<i class="fa-solid fa-file-slash"></i>
|
<i class="fa-solid fa-file-slash"></i>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
{% elif column.name == 'src' %}
|
|
||||||
<td class="{{ column.name }}">
|
|
||||||
<a
|
|
||||||
class="has-text-grey"
|
|
||||||
onclick="populateSearch('src', '{{ cell|escapejs }}')">
|
|
||||||
{% if row.cells.src == 'irc' %}
|
|
||||||
<span class="icon" data-tooltip="IRC">
|
|
||||||
<i class="fa-solid fa-hashtag" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{% elif row.cells.src == 'dis' %}
|
|
||||||
<span class="icon" data-tooltip="Discord">
|
|
||||||
<i class="fa-brands fa-discord" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{% elif row.cells.src == '4ch' %}
|
|
||||||
<span class="icon" data-tooltip="4chan">
|
|
||||||
<i class="fa-solid fa-leaf" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
{% elif column.name == 'ts' %}
|
|
||||||
<td class="{{ column.name }}">
|
|
||||||
<p>{{ row.cells.date }}</p>
|
|
||||||
<p>{{ row.cells.time }}</p>
|
|
||||||
</td>
|
|
||||||
{% elif column.name == 'type' or column.name == 'mtype' %}
|
|
||||||
<td class="{{ column.name }}">
|
|
||||||
<a
|
|
||||||
class="has-text-grey"
|
|
||||||
onclick="populateSearch('{{ column.name }}', '{{ cell|escapejs }}')">
|
|
||||||
{% if cell == 'msg' %}
|
|
||||||
<span class="icon" data-tooltip="Message">
|
|
||||||
<i class="fa-solid fa-message"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'join' %}
|
|
||||||
<span class="icon" data-tooltip="Join">
|
|
||||||
<i class="fa-solid fa-person-to-portal"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'part' %}
|
|
||||||
<span class="icon" data-tooltip="Part">
|
|
||||||
<i class="fa-solid fa-person-from-portal"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'quit' %}
|
|
||||||
<span class="icon" data-tooltip="Quit">
|
|
||||||
<i class="fa-solid fa-circle-xmark"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'kick' %}
|
|
||||||
<span class="icon" data-tooltip="Kick">
|
|
||||||
<i class="fa-solid fa-user-slash"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'nick' %}
|
|
||||||
<span class="icon" data-tooltip="Nick">
|
|
||||||
<i class="fa-solid fa-signature"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'mode' %}
|
|
||||||
<span class="icon" data-tooltip="Mode">
|
|
||||||
<i class="fa-solid fa-gear"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'action' %}
|
|
||||||
<span class="icon" data-tooltip="Action">
|
|
||||||
<i class="fa-solid fa-exclamation"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'notice' %}
|
|
||||||
<span class="icon" data-tooltip="Notice">
|
|
||||||
<i class="fa-solid fa-message-code"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'conn' %}
|
|
||||||
<span class="icon" data-tooltip="Connection">
|
|
||||||
<i class="fa-solid fa-cloud-exclamation"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'znc' %}
|
|
||||||
<span class="icon" data-tooltip="ZNC">
|
|
||||||
<i class="fa-brands fa-unity"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'query' %}
|
|
||||||
<span class="icon" data-tooltip="Query">
|
|
||||||
<i class="fa-solid fa-message"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'highlight' %}
|
|
||||||
<span class="icon" data-tooltip="Highlight">
|
|
||||||
<i class="fa-solid fa-exclamation"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'who' %}
|
|
||||||
<span class="icon" data-tooltip="Who">
|
|
||||||
<i class="fa-solid fa-passport"></i>
|
|
||||||
</span>
|
|
||||||
{% elif cell == 'topic' %}
|
|
||||||
<span class="icon" data-tooltip="Topic">
|
|
||||||
<i class="fa-solid fa-sign"></i>
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
{{ cell }}
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
{% elif column.name == 'msg' %}
|
|
||||||
<td class="{{ column.name }} wrap">
|
|
||||||
<a
|
|
||||||
class="has-text-grey is-underlined"
|
|
||||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
|
||||||
hx-post="{% url 'modal_context' %}"
|
|
||||||
hx-vals='{"net": "{{ row.cells.net|escapejs }}",
|
|
||||||
"num": "{{ row.cells.num|escapejs }}",
|
|
||||||
"source": "{{ row.cells.src|escapejs }}",
|
|
||||||
"channel": "{{ row.cells.channel|escapejs }}",
|
|
||||||
"time": "{{ row.cells.time|escapejs }}",
|
|
||||||
"date": "{{ row.cells.date|escapejs }}",
|
|
||||||
"index": "{% if row.cells.index != '—' %}{{row.cells.index}}{% else %}{{ params.index }}{% endif %}",
|
|
||||||
"type": "{{ row.cells.type }}",
|
|
||||||
"mtype": "{{ row.cells.mtype }}",
|
|
||||||
"nick": "{{ row.cells.nick|escapejs }}",
|
|
||||||
"dedup": "{{ params.dedup }}"}'
|
|
||||||
hx-target="#modals-here"
|
|
||||||
hx-trigger="click"
|
|
||||||
href="/?modal=context&net={{row.cells.net|escapejs}}&num={{row.cells.num|escapejs}}&source={{row.cells.src|escapejs}}&channel={{row.cells.channel|urlsafe}}&time={{row.cells.time|escapejs}}&date={{row.cells.date|escapejs}}&index={{params.index}}&type={{row.cells.type}}&mtype={{row.cells.mtype}}&nick={{row.cells.mtype|escapejs}}">
|
|
||||||
{{ row.cells.msg }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
{% elif column.name == 'nick' %}
|
|
||||||
<td class="{{ column.name }}">
|
|
||||||
<div class="nowrap-parent">
|
|
||||||
<div class="nowrap-child">
|
|
||||||
{% if row.cells.online is True %}
|
|
||||||
<span class="icon has-text-success has-tooltip-success" data-tooltip="Online">
|
|
||||||
<i class="fa-solid fa-circle"></i>
|
|
||||||
</span>
|
|
||||||
{% elif row.cells.online is False %}
|
|
||||||
<span class="icon has-text-danger has-tooltip-danger" data-tooltip="Offline">
|
|
||||||
<i class="fa-solid fa-circle"></i>
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="icon has-text-warning has-tooltip-warning" data-tooltip="Unknown">
|
|
||||||
<i class="fa-solid fa-circle"></i>
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<a class="nowrap-child has-text-grey" onclick="populateSearch('nick', '{{ cell|escapejs }}')">
|
|
||||||
{{ cell }}
|
|
||||||
</a>
|
|
||||||
<div class="nowrap-child">
|
|
||||||
{% if row.cells.src == 'irc' %}
|
|
||||||
<a
|
|
||||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
|
||||||
hx-post="{% url 'modal_drilldown' %}"
|
|
||||||
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
|
|
||||||
hx-target="#modals-here"
|
|
||||||
hx-trigger="click"
|
|
||||||
class="has-text-black">
|
|
||||||
<span class="icon" data-tooltip="Open drilldown modal">
|
|
||||||
<i class="fa-solid fa-album"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
|
||||||
hx-post="{% url 'modal_drilldown' type='window' %}"
|
|
||||||
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
|
|
||||||
hx-target="#windows-here"
|
|
||||||
hx-swap="afterend"
|
|
||||||
hx-trigger="click"
|
|
||||||
class="has-text-black">
|
|
||||||
<span class="icon" data-tooltip="Open drilldown window">
|
|
||||||
<i class="fa-solid fa-album"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
|
||||||
hx-post="{% url 'modal_drilldown' type='widget' %}"
|
|
||||||
hx-vals='{"net": "{{ row.cells.net }}", "nick": "{{ row.cells.nick }}", "channel": "{{ row.cells.channel }}"}'
|
|
||||||
hx-target="#widgets-here"
|
|
||||||
hx-trigger="click"
|
|
||||||
class="has-text-black">
|
|
||||||
<span class="icon" data-tooltip="Open drilldown widget">
|
|
||||||
<i class="fa-solid fa-album"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if row.cells.num_chans != '—' %}
|
|
||||||
<div class="nowrap-child">
|
|
||||||
<span class="tag">
|
|
||||||
{{ row.cells.num_chans }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
{% elif column.name == 'channel' %}
|
|
||||||
<td class="{{ column.name }}">
|
|
||||||
{% if cell != '—' %}
|
|
||||||
<div class="nowrap-parent">
|
|
||||||
<a
|
|
||||||
class="nowrap-child has-text-grey"
|
|
||||||
onclick="populateSearch('channel', '{{ cell|escapejs }}')">
|
|
||||||
{{ cell }}
|
|
||||||
</a>
|
|
||||||
{% if row.cells.num_users != '—' %}
|
|
||||||
<div class="nowrap-child">
|
|
||||||
<span class="tag">
|
|
||||||
{{ row.cells.num_users }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
{{ cell }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% elif cell is True or cell is False %}
|
{% elif cell is True or cell is False %}
|
||||||
<td class="{{ column.name }}">
|
<td class="{{ column.name }}">
|
||||||
{% if cell is True %}
|
{% if cell is True %}
|
||||||
|
@ -364,44 +150,24 @@
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% elif column.name == "tokens" %}
|
{% elif column.name == "dosages" %}
|
||||||
<td class="{{ column.name }}">
|
<td class="{{ column.name }}">
|
||||||
<div class="tags">
|
{{ cell.entry }}
|
||||||
{% for word in cell %}
|
|
||||||
<a
|
|
||||||
class="tag"
|
|
||||||
onclick="populateSearch('{{ column.name }}', '{{ word }}')">
|
|
||||||
{{ word }}
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
{% elif column.name == "meta" %}
|
{% elif column.name == "name" %}
|
||||||
<td class="{{ column.name }}">
|
<td class="{{ column.name }}">
|
||||||
<pre class="small-field" style="cursor: pointer;">{{ cell }}</pre>
|
<a href="{% url 'drug_detail' type='page' pk=row.cells.id %}"><button
|
||||||
</td>
|
class="button">
|
||||||
{% elif 'id' in column.name and column.name != "ident" %}
|
<span class="icon-text">
|
||||||
<td class="{{ column.name }}">
|
<span class="icon">
|
||||||
<div class="buttons">
|
<i class="fa-solid fa-eye"></i>
|
||||||
<div class="nowrap-parent">
|
|
||||||
<!-- <input class="input" type="text" value="{{ cell }}" style="width: 50px;" readonly> -->
|
|
||||||
<a
|
|
||||||
class="has-text-grey button nowrap-child"
|
|
||||||
onclick="populateSearch('{{ column.name }}', '{{ cell|escapejs }}')">
|
|
||||||
<span class="icon" data-tooltip="Populate {{ cell }}">
|
|
||||||
<i class="fa-solid fa-arrow-left-long-to-line" aria-hidden="true"></i>
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="has-text-grey button nowrap-child"
|
|
||||||
onclick="window.prompt('Copy to clipboard: Ctrl+C, Enter', '{{ cell|escapejs }}');">
|
|
||||||
<span class="icon" data-tooltip="Copy to clipboard">
|
|
||||||
<i class="fa-solid fa-copy" aria-hidden="true"></i>
|
|
||||||
</span>
|
</span>
|
||||||
|
</button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
{{ cell }}
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<td class="{{ column.name }}">
|
<td class="{{ column.name }}">
|
||||||
<a
|
<a
|
||||||
|
@ -524,4 +290,4 @@
|
||||||
{% endblock pagination %}
|
{% endblock pagination %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock table-wrapper %}
|
{% endblock table-wrapper %}
|
||||||
{% endcache %}
|
{# endcache #}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import orjson
|
||||||
|
from django import template
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def pretty(data):
|
||||||
|
return orjson.dumps(data, option=orjson.OPT_INDENT_2).decode("utf-8")
|
|
@ -8,7 +8,9 @@ from core.forms import DrugForm
|
||||||
from core.models import Drug
|
from core.models import Drug
|
||||||
from core.views.helpers import synchronize_async_helper
|
from core.views.helpers import synchronize_async_helper
|
||||||
from mxs.restrictions import StaffMemberRequiredMixin
|
from mxs.restrictions import StaffMemberRequiredMixin
|
||||||
from mxs.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate
|
from mxs.views import ObjectCreate, ObjectDelete, ObjectList, ObjectRead, ObjectUpdate
|
||||||
|
|
||||||
|
# from mixins.views import ObjectRead
|
||||||
|
|
||||||
|
|
||||||
class DrugList(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectList):
|
class DrugList(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectList):
|
||||||
|
@ -54,6 +56,25 @@ class DrugDelete(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectDelete):
|
||||||
model = Drug
|
model = Drug
|
||||||
|
|
||||||
|
|
||||||
|
class DrugDetail(LoginRequiredMixin, StaffMemberRequiredMixin, ObjectRead):
|
||||||
|
model = Drug
|
||||||
|
form_class = DrugForm
|
||||||
|
detail_template = "partials/drug-detail.html"
|
||||||
|
|
||||||
|
detail_url_name = "drug_detail"
|
||||||
|
detail_url_args = ["type", "pk"]
|
||||||
|
|
||||||
|
def get_object(self, **kwargs):
|
||||||
|
print("GET")
|
||||||
|
pk = kwargs.get("pk")
|
||||||
|
info = Drug.objects.get(pk=pk)
|
||||||
|
|
||||||
|
# self.extra_context = {}
|
||||||
|
print("info", info)
|
||||||
|
# return dictionary
|
||||||
|
return info.__dict__
|
||||||
|
|
||||||
|
|
||||||
class DrugClear(LoginRequiredMixin, StaffMemberRequiredMixin, APIView):
|
class DrugClear(LoginRequiredMixin, StaffMemberRequiredMixin, APIView):
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
template_name = "mixins/partials/notify.html"
|
template_name = "mixins/partials/notify.html"
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
|
||||||
|
# from mixins.restrictions import StaffMemberRequiredMixin
|
||||||
|
from mixins.views import (
|
||||||
|
ObjectCreate,
|
||||||
|
ObjectDelete,
|
||||||
|
ObjectList,
|
||||||
|
ObjectRead,
|
||||||
|
ObjectUpdate,
|
||||||
|
)
|
||||||
|
|
||||||
|
from core.forms import FavouriteForm
|
||||||
|
from core.models import Favourite
|
||||||
|
|
||||||
|
|
||||||
|
class FavouriteList(LoginRequiredMixin, ObjectList):
|
||||||
|
list_template = "partials/favourite-list.html"
|
||||||
|
model = Favourite
|
||||||
|
page_title = "Global list of favourites"
|
||||||
|
|
||||||
|
list_url_name = "favourites"
|
||||||
|
list_url_args = ["type"]
|
||||||
|
|
||||||
|
submit_url_name = "favourite_create"
|
||||||
|
|
||||||
|
|
||||||
|
class FavouriteCreate(LoginRequiredMixin, ObjectCreate):
|
||||||
|
model = Favourite
|
||||||
|
form_class = FavouriteForm
|
||||||
|
|
||||||
|
submit_url_name = "favourite_create"
|
||||||
|
|
||||||
|
|
||||||
|
class FavouriteUpdate(LoginRequiredMixin, ObjectUpdate):
|
||||||
|
model = Favourite
|
||||||
|
form_class = FavouriteForm
|
||||||
|
|
||||||
|
submit_url_name = "favourite_update"
|
||||||
|
|
||||||
|
|
||||||
|
class FavouriteDelete(LoginRequiredMixin, ObjectDelete):
|
||||||
|
model = Favourite
|
||||||
|
|
||||||
|
|
||||||
|
class FavouriteDetail(LoginRequiredMixin, ObjectRead):
|
||||||
|
model = Favourite
|
||||||
|
form_class = FavouriteForm
|
||||||
|
detail_template = "partials/drug-detail.html"
|
||||||
|
|
||||||
|
detail_url_name = "favourite_detail"
|
||||||
|
detail_url_args = ["type", "pk"]
|
||||||
|
|
||||||
|
def get_object(self, **kwargs):
|
||||||
|
pk = kwargs.get("pk")
|
||||||
|
info = Favourite.objects.get(pk=pk, user=self.request.user)
|
||||||
|
return info.__dict__
|
||||||
|
|
||||||
|
|
||||||
|
# class FavouriteClear(LoginRequiredMixin, APIView):
|
||||||
|
# def delete(self, request):
|
||||||
|
# template_name = "mixins/partials/notify.html"
|
||||||
|
# favourites_all = Favourite.objects.all()
|
||||||
|
# favourites_all.delete()
|
||||||
|
# context = {
|
||||||
|
# "message": "Deleted all favourites",
|
||||||
|
# "class": "success",
|
||||||
|
# }
|
||||||
|
# response = render(request, template_name, context)
|
||||||
|
# response["HX-Trigger"] = "drugEvent"
|
||||||
|
# return response
|
||||||
|
|
||||||
|
|
||||||
|
# class FavouritePullMerge(LoginRequiredMixin, APIView):
|
||||||
|
# def post(self, request):
|
||||||
|
# template_name = "mixins/partials/notify.html"
|
||||||
|
# # Do something
|
||||||
|
# run = synchronize_async_helper(PsychWikiClient())
|
||||||
|
# result = synchronize_async_helper(run.update_favourites())
|
||||||
|
# context = {
|
||||||
|
# "message": f"Favourites fetched: {result}",
|
||||||
|
# "class": "success",
|
||||||
|
# }
|
||||||
|
# response = render(request, template_name, context)
|
||||||
|
# response["HX-Trigger"] = "drugEvent"
|
||||||
|
# return response
|
Loading…
Reference in New Issue