mirror of
https://github.com/Findus23/RPGnotes.git
synced 2024-09-19 15:43:45 +02:00
store linked pages in DB and show in graph
This commit is contained in:
parent
19aa3e0722
commit
1d7d713243
12 changed files with 177 additions and 15 deletions
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.3 on 2022-11-25 18:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("characters", "0016_remove_character_nickname_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="character",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="historicalcharacter",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
]
|
|
@ -36,9 +36,10 @@ class Command(BaseCommand):
|
|||
objects.extend(list(Note.objects.all()))
|
||||
objects.extend(list(IngameDay.objects.all()))
|
||||
for object in objects:
|
||||
fresh_html = md_to_html(object.description_md, replacements=replacements)
|
||||
fresh_html, linked_objects = md_to_html(object.description_md, replacements=replacements)
|
||||
if object.description_html != fresh_html:
|
||||
print_diff_call(object.description_html, fresh_html, str(object))
|
||||
if store:
|
||||
object.description_html = fresh_html
|
||||
object.linked_objects = ",".join(linked_objects)
|
||||
object.save()
|
||||
|
|
|
@ -7,11 +7,13 @@ from utils.markdown import md_to_html
|
|||
class DescriptionModel(models.Model):
|
||||
description_md = models.TextField(_("Description"), blank=True)
|
||||
description_html = models.TextField(_("Description (HTML)"), blank=True, editable=False)
|
||||
linked_objects = models.TextField(max_length=1000, blank=True, default="")
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.description_html = md_to_html(self.description_md)
|
||||
self.description_html, linked_objects = md_to_html(self.description_md)
|
||||
self.linked_objects = ",".join(linked_objects)
|
||||
|
||||
super(DescriptionModel, self).save(*args, **kwargs)
|
||||
|
|
|
@ -28,20 +28,20 @@ class ColorsTests(SimpleTestCase):
|
|||
class MarkdownTests(SimpleTestCase):
|
||||
def test_basic_markdown(self):
|
||||
self.assertHTMLEqual(
|
||||
md_to_html("**test** *it*", replacements={}),
|
||||
md_to_html("**test** *it*", replacements={})[0],
|
||||
"<p><strong>test</strong> <em>it</em></p>"
|
||||
)
|
||||
|
||||
def test_nb_md(self):
|
||||
self.assertHTMLEqual(
|
||||
md_to_html("This\nis\nTest", replacements={}),
|
||||
md_to_html("This\nis\nTest", replacements={})[0],
|
||||
"<p>This<br>is<br>Test</p>"
|
||||
)
|
||||
|
||||
def test_bleach(self):
|
||||
self.assertEqual(
|
||||
md_to_html(
|
||||
"<script>console.log()</script> <a onclick='console.log()'>Hi</button>", replacements={}),
|
||||
"<script>console.log()</script> <a onclick='console.log()'>Hi</button>", replacements={})[0],
|
||||
"<script>console.log()</script>\n<p><a>Hi</button></a></p>"
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.3 on 2022-11-25 18:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("days", "0006_alter_historicalsession_date_alter_session_date"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="historicalingameday",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ingameday",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
]
|
23
factions/migrations/0005_faction_linked_objects_and_more.py
Normal file
23
factions/migrations/0005_faction_linked_objects_and_more.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.3 on 2022-11-25 18:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("factions", "0004_faction_aliases_historicalfaction_aliases"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="faction",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="historicalfaction",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
]
|
|
@ -37,6 +37,12 @@ class Graph:
|
|||
"target": target.graphkey
|
||||
})
|
||||
|
||||
def add_edge_str(self, source: str, target: str):
|
||||
self.edges.append({
|
||||
"source": source,
|
||||
"target": target
|
||||
})
|
||||
|
||||
def prune(self) -> None:
|
||||
connected_nodes = set()
|
||||
for e in self.edges:
|
||||
|
@ -62,14 +68,22 @@ class GraphView(TemplateView):
|
|||
template_name = "graph/graph.jinja"
|
||||
|
||||
|
||||
def get_description_links(el: GraphModelEl, g: Graph):
|
||||
if el.linked_objects:
|
||||
for lo in el.linked_objects.split(","):
|
||||
g.add_edge_str(el.graphkey, lo)
|
||||
|
||||
|
||||
def get_graph(request: HttpRequest) -> HttpResponse:
|
||||
g = Graph()
|
||||
for loc in list(Location.objects.all()) + list(Note.objects.all()):
|
||||
g.add_node(loc)
|
||||
if loc.parent:
|
||||
g.add_edge(loc, loc.parent)
|
||||
get_description_links(loc, g)
|
||||
for faction in Faction.objects.all():
|
||||
g.add_node(faction, faction.name)
|
||||
get_description_links(faction, g)
|
||||
for user in TenantUser.objects \
|
||||
.filter(tenants=connection.get_tenant()) \
|
||||
.exclude(pk__in=[1, 2]):
|
||||
|
@ -82,6 +96,7 @@ def get_graph(request: HttpRequest) -> HttpResponse:
|
|||
g.add_edge(char, char.faction)
|
||||
if char.player:
|
||||
g.add_edge(char, char.player)
|
||||
get_description_links(char, g)
|
||||
|
||||
for loottype in LootType.objects.all():
|
||||
g.add_node(loottype)
|
||||
|
@ -94,6 +109,8 @@ def get_graph(request: HttpRequest) -> HttpResponse:
|
|||
g.add_edge(loot, loot.owner)
|
||||
if loot.type:
|
||||
g.add_edge(loot, loot.type)
|
||||
get_description_links(loot, g)
|
||||
|
||||
g.prune()
|
||||
|
||||
return JsonResponse(g.export())
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.3 on 2022-11-25 18:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("locations", "0010_historicallocation_aliases_location_aliases"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="historicallocation",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="location",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.3 on 2022-11-25 18:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("loot", "0015_loottype_slug"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="historicalloot",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="loot",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 4.1.3 on 2022-11-25 18:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("notes", "0005_historicalnote_aliases_note_aliases"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="historicalnote",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="note",
|
||||
name="linked_objects",
|
||||
field=models.TextField(blank=True, default="", max_length=1000),
|
||||
),
|
||||
]
|
|
@ -1,5 +1,6 @@
|
|||
import re
|
||||
from html.parser import HTMLParser
|
||||
from typing import Tuple, Set
|
||||
|
||||
import bleach
|
||||
import markdown
|
||||
|
@ -8,8 +9,8 @@ from bleach_allowlist import markdown_tags, markdown_attrs
|
|||
custom_allowed_tags = ["del", "ins"]
|
||||
|
||||
|
||||
def md_to_html(md: str, replacements=None) -> str:
|
||||
md = autolink(md, replacements=replacements)
|
||||
def md_to_html(md: str, replacements=None) -> Tuple[str, Set[str]]:
|
||||
md, linked_objects = autolink(md, replacements=replacements)
|
||||
html = markdown.markdown(
|
||||
md,
|
||||
output_format="html",
|
||||
|
@ -22,25 +23,28 @@ def md_to_html(md: str, replacements=None) -> str:
|
|||
tags=markdown_tags + custom_allowed_tags,
|
||||
attributes=markdown_attrs
|
||||
)
|
||||
return html
|
||||
return html, linked_objects
|
||||
|
||||
|
||||
def autolink(md: str, replacements=None) -> str:
|
||||
def autolink(md: str, replacements=None) -> Tuple[str, Set[str]]:
|
||||
if replacements is None:
|
||||
from utils.urls import name2url
|
||||
replacements = name2url()
|
||||
links = {}
|
||||
linked_objects = set()
|
||||
i = 0
|
||||
for name, url in replacements.items():
|
||||
for name, (url, obj) in replacements.items():
|
||||
regex = r"\bWORD\b".replace("WORD", name)
|
||||
placeholder = f"SOME{i}LINK"
|
||||
md = re.sub(regex, placeholder, md)
|
||||
md, n_replacements = re.subn(regex, placeholder, md)
|
||||
if n_replacements > 0:
|
||||
linked_objects.add(obj.graphkey)
|
||||
links[placeholder] = f"[{name}]({url})"
|
||||
i += 1
|
||||
|
||||
for placeholder, value in links.items():
|
||||
md = md.replace(placeholder, value)
|
||||
return md
|
||||
return md, linked_objects
|
||||
|
||||
|
||||
class HTMLFilter(HTMLParser):
|
||||
|
|
|
@ -16,10 +16,10 @@ def name2url() -> Dict[str, str]:
|
|||
objects.extend(Faction.objects.all())
|
||||
objects.extend(Note.objects.all())
|
||||
for object in objects:
|
||||
data[object.name] = object.get_absolute_url()
|
||||
data[object.name] = (object.get_absolute_url(), object)
|
||||
if object.aliases:
|
||||
for alias in object.aliases:
|
||||
data[alias] = object.get_absolute_url()
|
||||
data[alias] = (object.get_absolute_url(), object)
|
||||
|
||||
# longer replacements first
|
||||
data = {k: v for k, v in sorted(data.items(), key=lambda item: -len(item[0]))}
|
||||
|
|
Loading…
Reference in a new issue