Upgrade Bulma and begin drug info screen and favourites

This commit is contained in:
Mark Veidemanis 2024-05-17 22:47:16 +01:00
parent 4c8411b863
commit 46b1858897
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
20 changed files with 745 additions and 517 deletions

View File

@ -61,4 +61,5 @@ DRUGS_DEFAULT_PARAMS = {
"size": "15", "size": "15",
"sorting": "desc", "sorting": "desc",
"source": "substances", "source": "substances",
"index": "main",
} }

View File

@ -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)

View File

@ -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)

View File

@ -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"]

View File

@ -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,
} }

View File

@ -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",
}

View File

@ -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')),
],
),
]

View File

@ -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',
),
]

View File

@ -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

View File

@ -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">

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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 #}

View File

@ -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")

View File

@ -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"

85
core/views/favourites.py Normal file
View File

@ -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