link characters and npcs in texts
This commit is contained in:
parent
a7294f309a
commit
dbd7193c90
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 4.2.1 on 2023-08-25 20:42
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("guild", "0014_alter_playsession_npcs"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="character",
|
||||||
|
name="name",
|
||||||
|
field=models.CharField(max_length=255, unique=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="npc",
|
||||||
|
name="name",
|
||||||
|
field=models.CharField(max_length=255, unique=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -77,7 +77,7 @@ class Character(models.Model):
|
||||||
RETIRED = "RETIRED", _("Retired")
|
RETIRED = "RETIRED", _("Retired")
|
||||||
UNKNOWN = "UNKNOWN", _("Unknown")
|
UNKNOWN = "UNKNOWN", _("Unknown")
|
||||||
|
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255, unique=True)
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
max_length=16, choices=Status.choices, default=Status.ALIVE
|
max_length=16, choices=Status.choices, default=Status.ALIVE
|
||||||
|
@ -106,6 +106,10 @@ class Character(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_by_name(cls, name):
|
||||||
|
return cls.objects.filter(name=name).get()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("guild:character_detail", kwargs={"pk": self.pk})
|
return reverse("guild:character_detail", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
@ -203,7 +207,7 @@ class Reward(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class NPC(models.Model):
|
class NPC(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255, unique=True)
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
|
|
||||||
picture = models.ImageField(
|
picture = models.ImageField(
|
||||||
|
@ -222,3 +226,7 @@ class NPC(models.Model):
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("guild:npc_detail", kwargs={"pk": self.pk})
|
return reverse("guild:npc_detail", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_by_name(cls, name):
|
||||||
|
return cls.objects.filter(name=name).get()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import markdown
|
import markdown
|
||||||
from django import template
|
from django import template
|
||||||
from django.template.defaultfilters import stringfilter
|
from django.template.defaultfilters import stringfilter
|
||||||
|
from guild_md.entity_links import GuildLinkExtension
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -8,4 +9,4 @@ register = template.Library()
|
||||||
@register.filter(name="md")
|
@register.filter(name="md")
|
||||||
@stringfilter
|
@stringfilter
|
||||||
def md(value):
|
def md(value):
|
||||||
return markdown.markdown(value)
|
return markdown.markdown(value, extensions=[GuildLinkExtension()])
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
"""
|
||||||
|
Guild Journal Extension for Python-Markdown
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Converts [[NPC/Frankie]] to links.
|
||||||
|
|
||||||
|
Original code Copyright [Waylan Limberg](http://achinghead.com/).
|
||||||
|
|
||||||
|
All changes Copyright The Python Markdown Project
|
||||||
|
|
||||||
|
License: [BSD](https://opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from markdown.extensions import Extension
|
||||||
|
from markdown.inlinepatterns import InlineProcessor
|
||||||
|
from guild.models import NPC, Character
|
||||||
|
import xml.etree.ElementTree as etree
|
||||||
|
|
||||||
|
|
||||||
|
def build_url(category: str, name):
|
||||||
|
"""Build a URL from the label, a base, and an end."""
|
||||||
|
if category.lower() == "char":
|
||||||
|
try:
|
||||||
|
return Character.get_by_name(name).get_absolute_url()
|
||||||
|
except Character.DoesNotExist:
|
||||||
|
return ""
|
||||||
|
elif category.lower() == "npc":
|
||||||
|
try:
|
||||||
|
return NPC.get_by_name(name).get_absolute_url()
|
||||||
|
except NPC.DoesNotExist:
|
||||||
|
return ""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class GuildLinkExtension(Extension):
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
self.md = md
|
||||||
|
|
||||||
|
# append to end of inline patterns
|
||||||
|
GUILD_RE = r"\[\[([\w0-9_ -]+)\/([\w0-9_ -]+)\]\]"
|
||||||
|
wikilinkPattern = GuildLinksInlineProcessor(GUILD_RE, self.getConfigs())
|
||||||
|
wikilinkPattern.md = md
|
||||||
|
md.inlinePatterns.register(wikilinkPattern, "guildlinks", 75)
|
||||||
|
|
||||||
|
|
||||||
|
class GuildLinksInlineProcessor(InlineProcessor):
|
||||||
|
def __init__(self, pattern, config):
|
||||||
|
super().__init__(pattern)
|
||||||
|
self.config = config
|
||||||
|
|
||||||
|
def handleMatch(self, m, data):
|
||||||
|
if m.group(1).strip() and m.group(2).strip():
|
||||||
|
category = m.group(1).strip()
|
||||||
|
name = m.group(2).strip()
|
||||||
|
url = build_url(category, name)
|
||||||
|
a = etree.Element("a")
|
||||||
|
a.text = name
|
||||||
|
a.set("href", url)
|
||||||
|
if url == "":
|
||||||
|
a.set("class", "invalid-url")
|
||||||
|
else:
|
||||||
|
a = ""
|
||||||
|
return a, m.start(0), m.end(0)
|
||||||
|
|
||||||
|
|
||||||
|
def makeExtension(**kwargs): # pragma: no cover
|
||||||
|
return GuildLinkExtension(**kwargs)
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
[pytest]
|
||||||
|
DJANGO_SETTINGS_MODULE = guild_journal.settings
|
||||||
|
python_files = tests.py test_*.py *_tests.py
|
|
@ -0,0 +1,48 @@
|
||||||
|
import pytest
|
||||||
|
import markdown
|
||||||
|
from guild_md.entity_links import GuildLinkExtension
|
||||||
|
from guild.models import NPC, Character
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
["objs", "md", "html"],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
[],
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[Character(name="Blimm")],
|
||||||
|
"[[Char/Blimm]]",
|
||||||
|
'<p><a href="/characters/1/">Blimm</a></p>',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[Character(name="Blimm")],
|
||||||
|
"[[Char/Lun]]",
|
||||||
|
'<p><a class="invalid-url" href="">Lun</a></p>',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[Character(name="Blimm"), Character(name="Lun")],
|
||||||
|
"[[Char/Lun]] and [[Char/Blimm]]",
|
||||||
|
'<p><a href="/characters/2/">Lun</a> and <a href="/characters/1/">Blimm</a></p>',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[NPC(name="Frank")],
|
||||||
|
"[[NPC/Frank]]",
|
||||||
|
'<p><a href="/npcs/1/">Frank</a></p>',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[NPC(name="Frank"), Character(name="Blimm")],
|
||||||
|
"[[Char/Blimm]] and [[NPC/Frank]]",
|
||||||
|
'<p><a href="/characters/1/">Blimm</a> and <a href="/npcs/1/">Frank</a></p>',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_link_conversion(objs, md, html):
|
||||||
|
for obj in objs:
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
output = markdown.markdown(md, extensions=[GuildLinkExtension()])
|
||||||
|
assert output == html
|
Loading…
Reference in New Issue