mirror of
https://github.com/Findus23/RPGnotes.git
synced 2024-09-19 15:43:45 +02:00
add search
This commit is contained in:
parent
5d4887a555
commit
b678ca004a
27 changed files with 351 additions and 50 deletions
19
campaigns/migrations/0005_campaign_language.py
Normal file
19
campaigns/migrations/0005_campaign_language.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 4.0.3 on 2022-04-11 16:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('campaigns', '0004_alter_campaign_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='campaign',
|
||||
name='language',
|
||||
field=models.CharField(default='english', max_length=100, verbose_name='Language'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -1,14 +1,16 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
# Create your models here.
|
||||
from django_tenants.models import DomainMixin
|
||||
from tenant_users.tenants.models import TenantBase
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from rpg_notes.secrets import DEBUG
|
||||
|
||||
|
||||
class Campaign(TenantBase):
|
||||
name = models.CharField(_("Name"), max_length=1000, unique=True)
|
||||
language = models.CharField(_("Language"), max_length=100)
|
||||
|
||||
auto_create_schema = True
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.0.3 on 2022-04-11 18:54
|
||||
|
||||
import django.contrib.postgres.indexes
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('characters', '0013_auto_20211125_1358'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='character',
|
||||
index=django.contrib.postgres.indexes.GinIndex(fields=['name'], name='character_name_gin_idx', opclasses=['gin_trgm_ops']),
|
||||
),
|
||||
]
|
|
@ -9,6 +9,7 @@ from common.models import NameSlugModel, DescriptionModel, HistoryModel
|
|||
from factions.models import Faction
|
||||
from locations.models import Location
|
||||
from rpg_notes.settings import AUTH_USER_MODEL
|
||||
from search.utils import NameSearchIndex
|
||||
from utils.colors import get_random_color, is_bright_color
|
||||
from utils.random_filename import get_file_path
|
||||
|
||||
|
@ -47,6 +48,9 @@ class Character(NameSlugModel, DescriptionModel, HistoryModel):
|
|||
ordering = ["archived", "name"]
|
||||
verbose_name = _("Character")
|
||||
verbose_name_plural = _("Characters")
|
||||
indexes = [
|
||||
NameSearchIndex
|
||||
]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('characterdetail', args=[self.slug])
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from django.contrib.postgres.indexes import GinIndex
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.http import condition
|
||||
from django.views.generic import TemplateView
|
||||
from django_jinja.views import ServerError
|
||||
from ipware import get_client_ip
|
||||
from sentry_sdk import last_event_id
|
||||
|
||||
from rpg_notes.secrets import SENTRY_DSN
|
||||
from utils.assets import get_css
|
||||
from utils.assets import get_css, get_file_hash
|
||||
|
||||
|
||||
class PublicHomepageView(TemplateView):
|
||||
|
@ -22,17 +22,22 @@ def print_ip(request):
|
|||
return HttpResponse(repr(client_ip), content_type="text/plain")
|
||||
|
||||
|
||||
# @cache_page(60 * 15)
|
||||
def calc_etag(*args, **kwargs):
|
||||
return get_file_hash()[:6]
|
||||
|
||||
|
||||
@condition(etag_func=calc_etag)
|
||||
def debug_css(request):
|
||||
css, source_map = get_css(debug=True)
|
||||
return HttpResponse(css, content_type="text/css")
|
||||
|
||||
|
||||
# @cache_page(60 * 15)
|
||||
@condition(etag_func=calc_etag)
|
||||
def debug_css_sourcemap(request):
|
||||
css, source_map = get_css(debug=True)
|
||||
return HttpResponse(source_map, content_type="application/json")
|
||||
|
||||
|
||||
def handler500(request, *args, **argv):
|
||||
return render(request, "500.jinja", {
|
||||
"sentry_event_id": last_event_id(),
|
||||
|
|
18
factions/migrations/0002_faction_faction_name_gin_idx.py
Normal file
18
factions/migrations/0002_faction_faction_name_gin_idx.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.0.3 on 2022-04-11 18:54
|
||||
|
||||
import django.contrib.postgres.indexes
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('factions', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='faction',
|
||||
index=django.contrib.postgres.indexes.GinIndex(fields=['name'], name='faction_name_gin_idx', opclasses=['gin_trgm_ops']),
|
||||
),
|
||||
]
|
|
@ -1,11 +1,13 @@
|
|||
from datetime import date
|
||||
|
||||
from django.contrib.humanize.templatetags.humanize import ordinal
|
||||
from django.contrib.postgres.indexes import GinIndex
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.models import DescriptionModel, HistoryModel, NameSlugModel
|
||||
from search.utils import NameSearchIndex
|
||||
|
||||
|
||||
class Faction(NameSlugModel, DescriptionModel, HistoryModel):
|
||||
|
@ -14,6 +16,9 @@ class Faction(NameSlugModel, DescriptionModel, HistoryModel):
|
|||
ordering = ["name"]
|
||||
verbose_name = _("Faction")
|
||||
verbose_name_plural = _("Factions")
|
||||
indexes = [
|
||||
NameSearchIndex
|
||||
]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('factiondetail', args=[self.slug])
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<dd>
|
||||
{% for char in faction.characters.all() %}
|
||||
<a href="{{ char.get_absolute_url() }}">{{ char.name }}</a>
|
||||
{%- if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
</dl>
|
||||
|
|
Binary file not shown.
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-25 13:56+0100\n"
|
||||
"POT-Creation-Date: 2022-04-11 22:42+0200\n"
|
||||
"PO-Revision-Date: 2021-10-03 17:19+0200\n"
|
||||
"Last-Translator: Lukas Winkler <translations@lw1.at>\n"
|
||||
"Language-Team: \n"
|
||||
|
@ -18,11 +18,17 @@ msgstr ""
|
|||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
|
||||
#: campaigns/models.py:11 common/models/nameslugmodel.py:7 loot/models.py:13
|
||||
#: campaigns/models.py:11 common/models/nameslugmodel.py:8 loot/models.py:14
|
||||
#: users/models.py:10
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: campaigns/models.py:12
|
||||
#, fuzzy
|
||||
#| msgid "Change Language"
|
||||
msgid "Language"
|
||||
msgstr "Sprache ändern"
|
||||
|
||||
#: campaigns/templates/campaigns/campaign_detail.jinja:7
|
||||
msgid "Players"
|
||||
msgstr "Spieler"
|
||||
|
@ -45,57 +51,57 @@ msgstr "Kampagnenübersicht"
|
|||
msgid "create Campaign"
|
||||
msgstr "Campaign erstellen"
|
||||
|
||||
#: characters/models.py:22
|
||||
#: characters/models.py:23
|
||||
msgid "Nickname"
|
||||
msgstr "Spitzname"
|
||||
|
||||
#: characters/models.py:23
|
||||
#: characters/models.py:24
|
||||
msgid "Subtitle"
|
||||
msgstr "Untertitel"
|
||||
|
||||
#: characters/models.py:26 characters/templates/characters/detail.jinja:45
|
||||
#: characters/models.py:27 characters/templates/characters/detail.jinja:45
|
||||
msgid "Player"
|
||||
msgstr "Spieler"
|
||||
|
||||
#: characters/models.py:27
|
||||
#: characters/models.py:28
|
||||
msgid "If no player is selected, this character is considered an NPC."
|
||||
msgstr "Wenn kein Spieler ausgewählt ist, ist dies ein NPC."
|
||||
|
||||
#: characters/models.py:32 characters/templates/characters/detail.jinja:49
|
||||
#: factions/models.py:15
|
||||
#: characters/models.py:33 characters/templates/characters/detail.jinja:49
|
||||
#: factions/models.py:17
|
||||
msgid "Faction"
|
||||
msgstr "Fraktion"
|
||||
|
||||
#: characters/models.py:36 locations/models.py:25 loot/models.py:27
|
||||
#: characters/models.py:37 locations/models.py:26 loot/models.py:28
|
||||
#: loot/templates/loot/overview.jinja:17
|
||||
msgid "Location"
|
||||
msgstr "Ort"
|
||||
|
||||
#: characters/models.py:38
|
||||
#: characters/models.py:39
|
||||
msgid "Archived"
|
||||
msgstr "Archiviert"
|
||||
|
||||
#: characters/models.py:39
|
||||
#: characters/models.py:40
|
||||
msgid "Color"
|
||||
msgstr "Farbe"
|
||||
|
||||
#: characters/models.py:43
|
||||
#: characters/models.py:44
|
||||
msgid "Token Image"
|
||||
msgstr "Token Bild"
|
||||
|
||||
#: characters/models.py:43
|
||||
#: characters/models.py:44
|
||||
msgid "round"
|
||||
msgstr "rund"
|
||||
|
||||
#: characters/models.py:44
|
||||
#: characters/models.py:45
|
||||
msgid "Large Image"
|
||||
msgstr "Großes Bild"
|
||||
|
||||
#: characters/models.py:48
|
||||
#: characters/models.py:49
|
||||
msgid "Character"
|
||||
msgstr "Charakter"
|
||||
|
||||
#: characters/models.py:49 templates/tenantbase.jinja:22
|
||||
#: characters/models.py:50 templates/tenantbase.jinja:22
|
||||
msgid "Characters"
|
||||
msgstr "Charaktere"
|
||||
|
||||
|
@ -155,7 +161,7 @@ msgstr "Tag"
|
|||
msgid "Add Day"
|
||||
msgstr "Tag hinzufügen"
|
||||
|
||||
#: factions/models.py:16 templates/tenantbase.jinja:34
|
||||
#: factions/models.py:18 templates/tenantbase.jinja:34
|
||||
msgid "Factions"
|
||||
msgstr "Fraktionen"
|
||||
|
||||
|
@ -167,18 +173,18 @@ msgstr "Fraktion hinzufügen"
|
|||
msgid "Members"
|
||||
msgstr "Mitglieder"
|
||||
|
||||
#: locations/models.py:18 locations/templates/locations/detail.jinja:41
|
||||
#: notes/models.py:18 notes/templates/notes/detail.jinja:41
|
||||
#: locations/models.py:19 locations/templates/locations/detail.jinja:41
|
||||
#: notes/models.py:20 notes/templates/notes/detail.jinja:41
|
||||
msgid "Part of"
|
||||
msgstr "Teil von"
|
||||
|
||||
#: locations/models.py:21 loot/models.py:17 notes/models.py:21
|
||||
#: locations/models.py:22 loot/models.py:18 notes/models.py:23
|
||||
#, fuzzy
|
||||
#| msgid "Token Image"
|
||||
msgid "Image"
|
||||
msgstr "Token Bild"
|
||||
|
||||
#: locations/models.py:26 templates/tenantbase.jinja:26
|
||||
#: locations/models.py:27 templates/tenantbase.jinja:26
|
||||
msgid "Locations"
|
||||
msgstr "Orte"
|
||||
|
||||
|
@ -190,27 +196,27 @@ msgstr "Ort hinzufügen"
|
|||
msgid "Contains"
|
||||
msgstr ""
|
||||
|
||||
#: loot/models.py:14 loot/templates/loot/overview.jinja:14
|
||||
#: loot/models.py:15 loot/templates/loot/overview.jinja:14
|
||||
msgid "Quantity"
|
||||
msgstr "Anzahl"
|
||||
|
||||
#: loot/models.py:15
|
||||
#: loot/models.py:16
|
||||
msgid "Value (Gold)"
|
||||
msgstr "Wert (Gold)"
|
||||
|
||||
#: loot/models.py:16
|
||||
#: loot/models.py:17
|
||||
msgid "Weight (lb)"
|
||||
msgstr "Gewicht (lb)"
|
||||
|
||||
#: loot/models.py:21 loot/templates/loot/overview.jinja:16
|
||||
#: loot/models.py:22 loot/templates/loot/overview.jinja:16
|
||||
msgid "Claimant"
|
||||
msgstr "Beansprucht von"
|
||||
|
||||
#: loot/models.py:30
|
||||
#: loot/models.py:31
|
||||
msgid "Magic Item"
|
||||
msgstr "Magisches Item"
|
||||
|
||||
#: loot/models.py:34 loot/models.py:35 loot/templates/loot/overview.jinja:3
|
||||
#: loot/models.py:35 loot/models.py:36 loot/templates/loot/overview.jinja:3
|
||||
#: loot/templates/loot/overview.jinja:6 templates/tenantbase.jinja:42
|
||||
msgid "Loot"
|
||||
msgstr "Loot"
|
||||
|
@ -259,11 +265,11 @@ msgstr "Gewicht (lb)"
|
|||
msgid "Add Loot"
|
||||
msgstr "Loot hinzufügen"
|
||||
|
||||
#: notes/models.py:25
|
||||
#: notes/models.py:27
|
||||
msgid "Note"
|
||||
msgstr "Notiz"
|
||||
|
||||
#: notes/models.py:26 templates/tenantbase.jinja:30
|
||||
#: notes/models.py:28 templates/tenantbase.jinja:30
|
||||
msgid "Notes"
|
||||
msgstr "Notizen"
|
||||
|
||||
|
@ -271,14 +277,27 @@ msgstr "Notizen"
|
|||
msgid "Add Note"
|
||||
msgstr "Notiz hinzufügen"
|
||||
|
||||
#: rpg_notes/settings.py:194
|
||||
#: rpg_notes/settings.py:196
|
||||
msgid "German"
|
||||
msgstr "Deutsch"
|
||||
|
||||
#: rpg_notes/settings.py:195
|
||||
#: rpg_notes/settings.py:197
|
||||
msgid "English"
|
||||
msgstr "Englisch"
|
||||
|
||||
#: search/templates/search/search_results.jinja:3
|
||||
msgid "Search Results"
|
||||
msgstr "Suchergebnisse"
|
||||
|
||||
#: search/templates/search/search_results.jinja:6
|
||||
#, python-format
|
||||
msgid "Search Results for %(query)s"
|
||||
msgstr "Suchergebnisse für %(query)s"
|
||||
|
||||
#: search/templates/search/search_results.jinja:11
|
||||
msgid "See also"
|
||||
msgstr "Siehe auch"
|
||||
|
||||
#: templates/403.jinja:8
|
||||
msgid "Permission Denied"
|
||||
msgstr "Zugriff verweigert"
|
||||
|
@ -289,7 +308,7 @@ msgid "You might want to go back to the <a href=\"%(url)s\">homepage</a>."
|
|||
msgstr ""
|
||||
"Du möchtest vielleicht zurück zur <a href=\"%(url)s\">Startseite</a> gehen."
|
||||
|
||||
#: templates/base.jinja:37 templates/tenantbase.jinja:63
|
||||
#: templates/base.jinja:37 templates/tenantbase.jinja:73
|
||||
msgid "Log out"
|
||||
msgstr "Abmelden"
|
||||
|
||||
|
@ -313,7 +332,7 @@ msgid "Sign up"
|
|||
msgstr "Registrieren"
|
||||
|
||||
#: templates/common/languageselect.jinja:3
|
||||
#: templates/common/languageselect.jinja:6 templates/tenantbase.jinja:53
|
||||
#: templates/common/languageselect.jinja:6 templates/tenantbase.jinja:63
|
||||
msgid "Change Language"
|
||||
msgstr "Sprache ändern"
|
||||
|
||||
|
@ -363,7 +382,15 @@ msgstr "Home"
|
|||
msgid "Timeline"
|
||||
msgstr "Timeline"
|
||||
|
||||
#: templates/tenantbase.jinja:59 users/templates/users/edit.jinja:5
|
||||
#: templates/tenantbase.jinja:49 templates/tenantbase.jinja:50
|
||||
msgid "Search"
|
||||
msgstr "Suchen"
|
||||
|
||||
#: templates/tenantbase.jinja:52
|
||||
msgid "Go!"
|
||||
msgstr "Los!"
|
||||
|
||||
#: templates/tenantbase.jinja:69 users/templates/users/edit.jinja:5
|
||||
msgid "Edit User Account"
|
||||
msgstr "Benutzerkonto bearbeiten"
|
||||
|
||||
|
@ -386,7 +413,7 @@ msgstr ""
|
|||
|
||||
#: users/views.py:61
|
||||
msgid "User account was updated successfully"
|
||||
msgstr ""
|
||||
msgstr "Benutzeraccount wurde erfolgreich bearbeitet"
|
||||
|
||||
#~ msgid "Nobody"
|
||||
#~ msgstr "Niemand"
|
||||
|
|
18
locations/migrations/0008_location_location_name_gin_idx.py
Normal file
18
locations/migrations/0008_location_location_name_gin_idx.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.0.3 on 2022-04-11 18:54
|
||||
|
||||
import django.contrib.postgres.indexes
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('locations', '0007_auto_20211007_2254'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='location',
|
||||
index=django.contrib.postgres.indexes.GinIndex(fields=['name'], name='location_name_gin_idx', opclasses=['gin_trgm_ops']),
|
||||
),
|
||||
]
|
|
@ -6,6 +6,7 @@ from tree_queries.fields import TreeNodeForeignKey
|
|||
from tree_queries.models import TreeNode
|
||||
|
||||
from common.models import NameSlugModel, DescriptionModel, HistoryModel
|
||||
from search.utils import NameSearchIndex
|
||||
from utils.random_filename import get_file_path
|
||||
|
||||
|
||||
|
@ -24,6 +25,9 @@ class Location(TreeNode, NameSlugModel, DescriptionModel, HistoryModel):
|
|||
ordering = ["name"]
|
||||
verbose_name = _("Location")
|
||||
verbose_name_plural = _("Locations")
|
||||
indexes = [
|
||||
NameSearchIndex
|
||||
]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('locationdetail', args=[self.slug])
|
||||
|
|
18
loot/migrations/0010_loot_loot_name_gin_idx.py
Normal file
18
loot/migrations/0010_loot_loot_name_gin_idx.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.0.3 on 2022-04-11 18:54
|
||||
|
||||
import django.contrib.postgres.indexes
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('loot', '0009_auto_20211017_1850'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='loot',
|
||||
index=django.contrib.postgres.indexes.GinIndex(fields=['name'], name='loot_name_gin_idx', opclasses=['gin_trgm_ops']),
|
||||
),
|
||||
]
|
|
@ -6,6 +6,7 @@ from sorl.thumbnail import ImageField
|
|||
from characters.models import Character
|
||||
from common.models import DescriptionModel, HistoryModel
|
||||
from locations.models import Location
|
||||
from search.utils import NameSearchIndex
|
||||
from utils.random_filename import get_file_path
|
||||
|
||||
|
||||
|
@ -33,7 +34,9 @@ class Loot(DescriptionModel, HistoryModel):
|
|||
ordering = ["name"]
|
||||
verbose_name = _("Loot")
|
||||
verbose_name_plural = _("Loot")
|
||||
|
||||
indexes = [
|
||||
NameSearchIndex
|
||||
]
|
||||
@property
|
||||
def value_per_unit(self):
|
||||
return self.value_gold / self.quantity
|
||||
|
|
18
notes/migrations/0003_note_note_name_gin_idx.py
Normal file
18
notes/migrations/0003_note_note_name_gin_idx.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.0.3 on 2022-04-11 18:54
|
||||
|
||||
import django.contrib.postgres.indexes
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notes', '0002_auto_20211007_2258'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddIndex(
|
||||
model_name='note',
|
||||
index=django.contrib.postgres.indexes.GinIndex(fields=['name'], name='note_name_gin_idx', opclasses=['gin_trgm_ops']),
|
||||
),
|
||||
]
|
|
@ -1,3 +1,4 @@
|
|||
from django.contrib.postgres.indexes import GinIndex
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -6,6 +7,7 @@ from tree_queries.fields import TreeNodeForeignKey
|
|||
from tree_queries.models import TreeNode
|
||||
|
||||
from common.models import NameSlugModel, DescriptionModel, HistoryModel
|
||||
from search.utils import NameSearchIndex
|
||||
from utils.random_filename import get_file_path
|
||||
|
||||
|
||||
|
@ -24,6 +26,9 @@ class Note(TreeNode, NameSlugModel, DescriptionModel, HistoryModel):
|
|||
ordering = ["name"]
|
||||
verbose_name = _("Note")
|
||||
verbose_name_plural = _("Notes")
|
||||
indexes = [
|
||||
NameSearchIndex
|
||||
]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('notedetail', args=[self.slug])
|
||||
|
|
|
@ -55,7 +55,8 @@ SHARED_APPS = (
|
|||
'sorl.thumbnail',
|
||||
'debug_toolbar',
|
||||
'axes',
|
||||
'django_extensions'
|
||||
'django_extensions',
|
||||
'django.contrib.postgres'
|
||||
)
|
||||
|
||||
TENANT_APPS = (
|
||||
|
@ -71,6 +72,7 @@ TENANT_APPS = (
|
|||
'days',
|
||||
'factions',
|
||||
'notes',
|
||||
'search',
|
||||
'common',
|
||||
'simple_history',
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ urlpatterns = [
|
|||
path('faction/', include("factions.urls")),
|
||||
path('note/', include("notes.urls")),
|
||||
path('loot/', include("loot.urls")),
|
||||
path('search/', include("search.urls")),
|
||||
path('', include("campaigns.urls"))
|
||||
]
|
||||
|
||||
|
|
0
search/__init__.py
Normal file
0
search/__init__.py
Normal file
6
search/apps.py
Normal file
6
search/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SearchConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'search'
|
24
search/templates/search/search_results.jinja
Normal file
24
search/templates/search/search_results.jinja
Normal file
|
@ -0,0 +1,24 @@
|
|||
{% extends "tenantbase.jinja" %}
|
||||
|
||||
{% block title %}{% trans %}Search Results{% endtrans %} {% endblock %}
|
||||
|
||||
{% block heading %}
|
||||
<h1>{% trans %}Search Results for {{ query }}{% endtrans %}</h1>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{% if similars %}
|
||||
<p>
|
||||
{% trans %}See also{% endtrans %}
|
||||
{% for s in similars %}
|
||||
<a data-distance="{{ s.distance }}" href="{{ url('search') }}?q={{ s }}"> {{ s }}</a>
|
||||
{%- if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% for r in results %}
|
||||
<h2 data-rank-value="{{ r.rank }}"><a href="{{ r.get_absolute_url() }}">{{ r.name }}</a></h2>
|
||||
<small class="text-muted">{{ r._meta.verbose_name }}</small>
|
||||
<p>{{ r.headline|safe }}</p>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
8
search/urls.py
Normal file
8
search/urls.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.urls import path
|
||||
|
||||
from search import views
|
||||
|
||||
urlpatterns=[
|
||||
path("", views.SearchResultsView.as_view(), name="search"),
|
||||
|
||||
]
|
7
search/utils.py
Normal file
7
search/utils.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from django.contrib.postgres.indexes import GinIndex
|
||||
|
||||
NameSearchIndex = GinIndex(
|
||||
name='%(class)s_name_gin_idx',
|
||||
fields=['name'],
|
||||
opclasses=['gin_trgm_ops'],
|
||||
)
|
60
search/views.py
Normal file
60
search/views.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Create your views here.
|
||||
from itertools import chain
|
||||
|
||||
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank, SearchHeadline, TrigramDistance
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from campaigns.models import Campaign
|
||||
from characters.models import Character
|
||||
from days.models import IngameDay
|
||||
from factions.models import Faction
|
||||
from locations.models import Location
|
||||
from loot.models import Loot
|
||||
from notes.models import Note
|
||||
|
||||
|
||||
class SearchResultsView(TemplateView):
|
||||
template_name = "search/search_results.jinja"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
print(self.request.GET)
|
||||
if "q" not in self.request.GET:
|
||||
return ""
|
||||
query_string = self.request.GET['q']
|
||||
context = super(SearchResultsView, self).get_context_data(**kwargs)
|
||||
campaign: Campaign = self.request.tenant
|
||||
config = campaign.language
|
||||
name_vector = SearchVector('name', weight="A", config=config)
|
||||
description_vector = SearchVector("description_html", weight="B", config=config)
|
||||
query = SearchQuery(query_string, search_type='websearch', config=config)
|
||||
models = [Location, Character, Faction, IngameDay, Note, Loot]
|
||||
all_results = []
|
||||
all_similar = []
|
||||
for m in models:
|
||||
if m == IngameDay:
|
||||
vector = description_vector
|
||||
else:
|
||||
vector = description_vector + name_vector
|
||||
similar = m.objects.annotate(
|
||||
# similarity=TrigramWordSimilarity(query_string, "name")
|
||||
distance=TrigramDistance("name", query_string)
|
||||
).filter(name__trigram_similar=query_string).order_by('distance')
|
||||
all_similar.extend(list(similar))
|
||||
results = m.objects.annotate(
|
||||
search=vector,
|
||||
rank=SearchRank(vector, query),
|
||||
headline=SearchHeadline(
|
||||
'description_html',
|
||||
query,
|
||||
start_sel='<strong>',
|
||||
stop_sel='</strong>',
|
||||
),
|
||||
).filter(search=query).order_by('-rank')
|
||||
all_results.append(results)
|
||||
|
||||
context["results"] = chain(*all_results)
|
||||
all_similar.sort(key=lambda s: s.distance)
|
||||
all_similar = [s for s in all_similar if s.distance != 0]
|
||||
context["similars"] = all_similar
|
||||
context["query"] = query_string
|
||||
return context
|
|
@ -43,6 +43,16 @@
|
|||
</li>
|
||||
{% endwith %}
|
||||
</ul>
|
||||
<form class="d-flex" action="{{ url("search") }}">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="q" type="search"
|
||||
placeholder="{% trans %}Search{% endtrans %}"
|
||||
aria-label="{% trans %}Search{% endtrans %}">
|
||||
<button class="btn btn-outline-secondary" type="submit">
|
||||
{% trans %}Go!{% endtrans %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="navbar-text nav-link dropdown-toggle" id="navbarDropdown" role="button"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
|
||||
import sass
|
||||
from django.core.cache import cache
|
||||
|
||||
basedir = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
@ -10,17 +12,32 @@ outputfile = basedir / "static/css/main.css"
|
|||
sourcemap = outputfile.with_suffix(".css.map")
|
||||
|
||||
|
||||
def get_file_hash():
|
||||
times = 0
|
||||
for file in inputdir.glob("*.scss"):
|
||||
times += int(file.stat().st_mtime)
|
||||
print(times)
|
||||
return sha256(times.to_bytes(16, 'little', signed=False)).hexdigest()
|
||||
|
||||
|
||||
def get_css(debug=False):
|
||||
sourcemap_name = "css_sourcemap" if debug else str(sourcemap)
|
||||
css, sourcemap_text = sass.compile(
|
||||
filename=str(inputfile),
|
||||
output_style="nested" if debug else "compressed",
|
||||
include_paths=[str(inputdir), str(basedir)],
|
||||
source_map_filename=sourcemap_name,
|
||||
source_map_contents=True
|
||||
)
|
||||
return css, sourcemap_text
|
||||
stored_file_hash = cache.get("scss_file_hash")
|
||||
real_file_hash = get_file_hash()
|
||||
if not stored_file_hash or stored_file_hash != real_file_hash:
|
||||
css, sourcemap_text = sass.compile(
|
||||
filename=str(inputfile),
|
||||
output_style="nested" if debug else "compressed",
|
||||
include_paths=[str(inputdir), str(basedir)],
|
||||
source_map_filename=sourcemap_name,
|
||||
source_map_contents=True
|
||||
)
|
||||
cache.set("scss_file_hash", real_file_hash)
|
||||
cache.set("scss_css", css)
|
||||
cache.set("scss_sourcemap", sourcemap_text)
|
||||
return css, sourcemap_text
|
||||
|
||||
return cache.get("scss_css"),cache.get("scss_sourcemap")
|
||||
|
||||
def save_css():
|
||||
css, sourcemap_text = get_css()
|
||||
|
|
Loading…
Reference in a new issue