1
0
Fork 0
mirror of https://github.com/Findus23/RPGnotes.git synced 2024-09-19 15:43:45 +02:00

initial version

This commit is contained in:
Lukas Winkler 2021-08-22 20:10:29 +02:00
commit 71b0d1cac8
Signed by: lukas
GPG key ID: 54DE4D798D244853
64 changed files with 2210 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
.idea/
secrets.py
media/
__pycache__/
static/css
node_modules

22
manage.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rpg_notes.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

0
notes/__init__.py Normal file
View file

10
notes/admin.py Normal file
View file

@ -0,0 +1,10 @@
from django.contrib import admin
# Register your models here.
from notes.models import Character, Campaign, Faction, Location, Loot
admin.site.register(Campaign)
admin.site.register(Character)
admin.site.register(Faction)
admin.site.register(Location)
admin.site.register(Loot)

6
notes/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class NotesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'notes'

21
notes/forms.py Normal file
View file

@ -0,0 +1,21 @@
from django.forms import ModelForm
from notes.models import Campaign, Loot, Character
class CampaignForm(ModelForm):
class Meta:
model = Campaign
fields = "__all__"
class LootForm(ModelForm):
class Meta:
model = Loot
fields = ["name", "description_md", "quantity", "value_gold", "owner", "magic_item"]
class CharacterForm(ModelForm):
class Meta:
model = Character
fields = ["name", "description_md", "subtitle", "player", "faction", "location", "color", "image"]

View file

@ -0,0 +1,83 @@
# Generated by Django 3.2.6 on 2021-08-22 11:02
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Campaign',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(unique=True)),
('notes', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('dm', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Loot',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('description', models.TextField()),
('quantity', models.PositiveSmallIntegerField()),
('value_gold', models.DecimalField(decimal_places=2, max_digits=7)),
('magic_item', models.BooleanField(default=False)),
('created', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('campaign', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='notes.campaign')),
('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Location',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(unique=True)),
('notes', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('campaign', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='notes.campaign')),
],
),
migrations.CreateModel(
name='Faction',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(unique=True)),
('notes', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('campaign', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='notes.campaign')),
],
),
migrations.CreateModel(
name='Character',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(unique=True)),
('notes', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('campaign', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='notes.campaign')),
('faction', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='notes.faction')),
('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='notes.location')),
('player', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
],
),
]

View file

@ -0,0 +1,33 @@
# Generated by Django 3.2.6 on 2021-08-22 11:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notes', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='campaign',
name='slug',
field=models.SlugField(editable=False, unique=True),
),
migrations.AlterField(
model_name='character',
name='slug',
field=models.SlugField(editable=False, unique=True),
),
migrations.AlterField(
model_name='faction',
name='slug',
field=models.SlugField(editable=False, unique=True),
),
migrations.AlterField(
model_name='location',
name='slug',
field=models.SlugField(editable=False, unique=True),
),
]

View file

@ -0,0 +1,38 @@
# Generated by Django 3.2.6 on 2021-08-22 11:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notes', '0002_auto_20210822_1109'),
]
operations = [
migrations.AlterField(
model_name='campaign',
name='notes',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='character',
name='notes',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='faction',
name='notes',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='location',
name='notes',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='loot',
name='description',
field=models.TextField(blank=True),
),
]

View file

@ -0,0 +1,138 @@
# Generated by Django 3.2.6 on 2021-08-22 11:38
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('notes', '0003_auto_20210822_1110'),
]
operations = [
migrations.CreateModel(
name='HistoricalLoot',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('description', models.TextField(blank=True)),
('quantity', models.PositiveSmallIntegerField()),
('value_gold', models.DecimalField(decimal_places=2, max_digits=7)),
('magic_item', models.BooleanField(default=False)),
('created', models.DateTimeField(blank=True, editable=False)),
('last_modified', models.DateTimeField(blank=True, editable=False)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('campaign', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='notes.campaign')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('owner', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical loot',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalLocation',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(editable=False)),
('notes', models.TextField(blank=True)),
('created', models.DateTimeField(blank=True, editable=False)),
('last_modified', models.DateTimeField(blank=True, editable=False)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('campaign', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='notes.campaign')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical location',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalFaction',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(editable=False)),
('notes', models.TextField(blank=True)),
('created', models.DateTimeField(blank=True, editable=False)),
('last_modified', models.DateTimeField(blank=True, editable=False)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('campaign', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='notes.campaign')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical faction',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalCharacter',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(editable=False)),
('notes', models.TextField(blank=True)),
('created', models.DateTimeField(blank=True, editable=False)),
('last_modified', models.DateTimeField(blank=True, editable=False)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('campaign', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='notes.campaign')),
('faction', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='notes.faction')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('location', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='notes.location')),
('player', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical character',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalCampaign',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.CharField(max_length=1000)),
('slug', models.SlugField(editable=False)),
('notes', models.TextField(blank=True)),
('created', models.DateTimeField(blank=True, editable=False)),
('last_modified', models.DateTimeField(blank=True, editable=False)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('dm', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical campaign',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]

View file

@ -0,0 +1,40 @@
# Generated by Django 3.2.6 on 2021-08-22 12:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notes', '0004_historicalcampaign_historicalcharacter_historicalfaction_historicallocation_historicalloot'),
]
operations = [
migrations.AlterField(
model_name='character',
name='slug',
field=models.SlugField(editable=False),
),
migrations.AlterField(
model_name='faction',
name='slug',
field=models.SlugField(editable=False),
),
migrations.AlterField(
model_name='location',
name='slug',
field=models.SlugField(editable=False),
),
migrations.AlterUniqueTogether(
name='character',
unique_together={('campaign', 'slug')},
),
migrations.AlterUniqueTogether(
name='faction',
unique_together={('campaign', 'slug')},
),
migrations.AlterUniqueTogether(
name='location',
unique_together={('campaign', 'slug')},
),
]

View file

@ -0,0 +1,123 @@
# Generated by Django 3.2.6 on 2021-08-22 14:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notes', '0005_auto_20210822_1259'),
]
operations = [
migrations.RenameField(
model_name='campaign',
old_name='notes',
new_name='description_md',
),
migrations.RenameField(
model_name='character',
old_name='notes',
new_name='description_md',
),
migrations.RenameField(
model_name='faction',
old_name='notes',
new_name='description_md',
),
migrations.RenameField(
model_name='historicalcampaign',
old_name='notes',
new_name='description_md',
),
migrations.RenameField(
model_name='historicalcharacter',
old_name='notes',
new_name='description_md',
),
migrations.RenameField(
model_name='historicalfaction',
old_name='notes',
new_name='description_md',
),
migrations.RenameField(
model_name='historicalloot',
old_name='description',
new_name='description_md',
),
migrations.RenameField(
model_name='loot',
old_name='description',
new_name='description_md',
),
migrations.AddField(
model_name='campaign',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='character',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='faction',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='historicalcampaign',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='historicalcharacter',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='historicalfaction',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='historicallocation',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='historicallocation',
name='description_md',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='historicalloot',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='location',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AddField(
model_name='location',
name='description_md',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='loot',
name='description_html',
field=models.TextField(blank=True, editable=False),
),
migrations.AlterField(
model_name='historicalloot',
name='value_gold',
field=models.DecimalField(decimal_places=2, max_digits=7, verbose_name='Value (Gold)'),
),
migrations.AlterField(
model_name='loot',
name='value_gold',
field=models.DecimalField(decimal_places=2, max_digits=7, verbose_name='Value (Gold)'),
),
]

View file

@ -0,0 +1,31 @@
# Generated by Django 3.2.6 on 2021-08-22 15:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notes', '0006_auto_20210822_1421'),
]
operations = [
migrations.AlterModelOptions(
name='character',
options={'ordering': ['name']},
),
migrations.AddField(
model_name='character',
name='subtitle',
field=models.CharField(blank=True, max_length=100),
),
migrations.AddField(
model_name='historicalcharacter',
name='subtitle',
field=models.CharField(blank=True, max_length=100),
),
migrations.AlterUniqueTogether(
name='character',
unique_together=set(),
),
]

View file

@ -0,0 +1,24 @@
# Generated by Django 3.2.6 on 2021-08-22 16:10
from django.db import migrations, models
import notes.utils.colors
class Migration(migrations.Migration):
dependencies = [
('notes', '0007_auto_20210822_1551'),
]
operations = [
migrations.AddField(
model_name='character',
name='color',
field=models.CharField(default=notes.utils.colors.get_random_color, max_length=6),
),
migrations.AddField(
model_name='historicalcharacter',
name='color',
field=models.CharField(default=notes.utils.colors.get_random_color, max_length=6),
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 3.2.6 on 2021-08-22 17:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('notes', '0008_auto_20210822_1610'),
]
operations = [
migrations.AddField(
model_name='character',
name='image',
field=models.ImageField(blank=True, null=True, upload_to='character_images'),
),
migrations.AddField(
model_name='historicalcharacter',
name='image',
field=models.TextField(blank=True, max_length=100, null=True),
),
]

View file

@ -0,0 +1,19 @@
# Generated by Django 3.2.6 on 2021-08-22 17:09
from django.db import migrations
import sorl.thumbnail.fields
class Migration(migrations.Migration):
dependencies = [
('notes', '0009_auto_20210822_1702'),
]
operations = [
migrations.AlterField(
model_name='character',
name='image',
field=sorl.thumbnail.fields.ImageField(blank=True, null=True, upload_to='character_images'),
),
]

View file

7
notes/models/__init__.py Normal file
View file

@ -0,0 +1,7 @@
from .descriptionmodel import DescriptionModel
from .campaign import Campaign
from .basemodel import BaseModel
from .faction import Faction
from .location import Location
from .character import Character
from .loot import Loot

24
notes/models/basemodel.py Normal file
View file

@ -0,0 +1,24 @@
from django.db import models
from django.utils.text import slugify
from notes.models import Campaign
class BaseModel(models.Model):
campaign = models.ForeignKey(Campaign, on_delete=models.PROTECT)
name = models.CharField(max_length=1000)
slug = models.SlugField(editable=False)
class Meta:
abstract = True
unique_together = ["campaign", "slug"]
def save(self, *args, **kwargs):
if not self.id:
# Newly created object, so set slug
self.slug = slugify(self.name)
super(BaseModel, self).save(*args, **kwargs)
def __str__(self):
return self.name

21
notes/models/campaign.py Normal file
View file

@ -0,0 +1,21 @@
from django.conf import settings
from django.db import models
from django.urls import reverse
from simple_history.models import HistoricalRecords
from notes.models import DescriptionModel
class Campaign(DescriptionModel):
name = models.CharField(max_length=1000)
slug = models.SlugField(unique=True, editable=False)
dm = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
created = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
history = HistoricalRecords()
def get_absolute_url(self):
return reverse('campaigndetail', args=[str(self.slug)])
def __str__(self):
return self.name

33
notes/models/character.py Normal file
View file

@ -0,0 +1,33 @@
from django.conf import settings
from django.db import models
from django.urls import reverse
from simple_history.models import HistoricalRecords
from sorl.thumbnail import ImageField
from notes.models import Faction, Location, BaseModel, DescriptionModel
from notes.utils.colors import get_random_color, is_bright_color
class Character(BaseModel, DescriptionModel):
subtitle = models.CharField(max_length=100, blank=True)
player = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, null=True)
faction = models.ForeignKey(Faction, on_delete=models.PROTECT, blank=True, null=True)
location = models.ForeignKey(Location, on_delete=models.PROTECT, blank=True, null=True)
color = models.CharField(max_length=6, default=get_random_color)
image = ImageField(upload_to="character_images", blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
history = HistoricalRecords()
class Meta:
ordering = ["name"]
def get_absolute_url(self):
return reverse('characterdetail', args=[self.campaign.slug, self.slug])
def initials(self):
return "".join([word[0] for word in self.name.split()][:2]).upper()
def text_color(self):
return "black" if is_bright_color(self.color) else "white"

View file

@ -0,0 +1,16 @@
from django.db import models
from notes.utils.markdown import md_to_html
class DescriptionModel(models.Model):
description_md = models.TextField(blank=True)
description_html = models.TextField(blank=True, editable=False)
class Meta:
abstract = True
def save(self, *args, **kwargs):
self.description_html = md_to_html(self.description_md)
super(DescriptionModel, self).save(*args, **kwargs)

10
notes/models/faction.py Normal file
View file

@ -0,0 +1,10 @@
from django.db import models
from simple_history.models import HistoricalRecords
from notes.models import BaseModel, DescriptionModel
class Faction(BaseModel, DescriptionModel):
created = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
history = HistoricalRecords()

11
notes/models/location.py Normal file
View file

@ -0,0 +1,11 @@
from django.db import models
from simple_history.models import HistoricalRecords
from notes.models import BaseModel, DescriptionModel
class Location(BaseModel, DescriptionModel):
notes = models.TextField(blank=True)
created = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
history = HistoricalRecords()

25
notes/models/loot.py Normal file
View file

@ -0,0 +1,25 @@
from django.conf import settings
from django.db import models
from simple_history.models import HistoricalRecords
from notes.models import Campaign, DescriptionModel
class Loot(DescriptionModel):
campaign = models.ForeignKey(Campaign, on_delete=models.PROTECT)
name = models.CharField(max_length=1000)
quantity = models.PositiveSmallIntegerField()
value_gold = models.DecimalField("Value (Gold)", max_digits=7, decimal_places=2)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, null=True)
magic_item = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
history = HistoricalRecords()
@property
def value_per_unit(self):
return self.value_gold / self.quantity
def __str__(self):
return self.name

26
notes/templates/base.html Normal file
View file

@ -0,0 +1,26 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<!-- Bootstrap -->
{% if debug %}
<link rel="stylesheet" href="{% url "css" %}">
{% else %}
<link rel="stylesheet" href="{% static "css/main.css" %}">
{% endif %}
</head>
<body>
<div class="container">
{% block mainpage %}{% endblock %}
</div>
<script src="{% static "libs/bootstrap.min.js" %}"></script>
{% block extra_js %}{% endblock %}
</body>
</html>

View file

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block mainpage %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" href="{% url "campaigndetail" view.kwargs.campslug %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url "characterlist" view.kwargs.campslug %}">Characters</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url "lootlist" view.kwargs.campslug %}">Loot</a>
</li>
</ul>
</div>
</div>
</nav>
{% block heading %}{% endblock %}
{% block content %}
{% endblock %}
{% endblock %}

View file

@ -0,0 +1,14 @@
{% extends 'navbarbase.html' %}
{% load django_bootstrap5 %}
{% load static %}
{% block heading %}
<h1>Add new Loot</h1>
{% endblock %}
{% block content %}
<form method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input class="btn btn-primary" type="submit" value="Confirm">
</form>{% endblock %}

View file

@ -0,0 +1,5 @@
{% extends "navbarbase.html" %}
{% block content %}
{{ object }}
{% endblock %}

View file

@ -0,0 +1,20 @@
{% extends 'base.html' %}
{% load django_bootstrap5 %}
{% load static %}
{% block mainpage %}
<h1>Add new campaign</h1>
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-primary" value="Update">
</form>
{% endblock %}
{#{% block extra_head %}#}
{# <script src="{% static "libs/codemirror.js" %}"></script>#}
{# <script src="{% static "libs/markdown.js" %}"></script>#}
{# <script src="{% static "libs/tagify.min.js" %}"></script>#}
{#{% endblock %}#}

View file

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block mainpage %}
{% for campaign in campaigns %}
<h2><a href="{% url "campaigndetail" campaign.slug %}">{{ campaign.name }}</a></h2>
{% endfor %}
<a href="{% url "campaigncreate" %}" class="btn btn-secondary">create Campaign</a>
{% endblock %}

View file

@ -0,0 +1,37 @@
{% extends "navbarbase.html" %}
{% block content %}
<div class="row">
<div class="col-4">
<ul class="nav nav-pills flex-column">
{% for c in player_characters %}
{% include "notes/macros/character-pillar.html" with character=c %}
{% endfor %}
</ul>
<ul class="nav nav-pills flex-column">
{% for c in npcs %}
{% include "notes/macros/character-pillar.html" with character=c %}
{% endfor %}
</ul>
<a class="btn btn-primary" href="{% url "characteradd" character.campaign.slug %}">Add Character</a>
</div>
<div class="col-8">
<div class="character-heading" style="border-bottom-color: #{{ character.color }}">
<h1>
{{ character.name }}
<a href="{% url "characteredit" character.campaign.slug character.slug %}">
edit
</a>
</h1>
<p>{{ character.subtitle }}</p>
</div>
<dl>
{% if character.player %}
<dt>Player:</dt>
<dd>{{ character.player }}</dd>
{% endif %}
</dl>
{{ character.description_html|safe }}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,26 @@
{% extends 'navbarbase.html' %}
{% load django_bootstrap5 %}
{% load static %}
{% block heading %}
{% if edit %}
<h1>Edit "{{ object.name }}"</h1>
{% else %}
<h1>Add new</h1>
{% endif %}
{% endblock %}
{% block content %}
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-primary" value="Update">
</form>
{% endblock %}
{#{% block extra_head %}#}
{# <script src="{% static "libs/codemirror.js" %}"></script>#}
{# <script src="{% static "libs/markdown.js" %}"></script>#}
{# <script src="{% static "libs/tagify.min.js" %}"></script>#}
{#{% endblock %}#}

View file

@ -0,0 +1,49 @@
{% extends "navbarbase.html" %}
{% block heading %}
<h1>Loot</h1>
{% endblock %}
{% block content %}
<table class="table">
<thead>
<tr>
<td>Item</td>
<td>Quantity</td>
<td>Total Value</td>
<td>Owner</td>
<td></td>
</tr>
</thead>
<tbody>
{% for l in loot %}
<tr data-bs-toggle="collapse" class="collapse-button collapsed"
data-bs-target="#row-{{ l.id }}"
aria-expanded="false"
aria-controls="row-{{ l.id }}">
<td>{{ l.name }}</td>
<td>{{ l.quantity }}</td>
<td>{{ l.value_gold }}</td>
<td>{{ l.owner.first_name }}</td>
<td>
<svg class="chev" viewBox="0 0 640 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 320L320 512 128 320 0 448l320 320 320-320L512 320z"/>
</svg>
</td>
</tr>
<tr>
<td colspan="5" class="collapse-cell">
<div class="collapse" id="row-{{ l.id }}">
<h3>{{ l.name }} <a href="{% url "lootedit" l.campaign.slug l.id %}">edit</a></h3>
{{ l.description_html|safe }}
<p>Value each: {{ l.value_per_unit|floatformat:-2 }} Gold</p>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{% url "lootadd" loot.0.campaign.slug %}" class="btn btn-primary">Add Loot</a>
{% endblock %}

View file

@ -0,0 +1,25 @@
{% load thumbutils %}
{% load thumbnail %}
<li class="nav-item">
<div class="side-card">
<div class="image-col">
{% if character.image %}
{% thumbnail character.image "48x48" crop="center" as im %}
<img class="rounded-circle" src="{{ im.url }}" width="{{ im.width }}"
height="{{ im.height }}"
srcset="{{ im.url|srcset }}">
{% endthumbnail %}
{% else %}
<div class="avatar"
style="background: #{{ character.color }};color:{{ character.text_color }}">{{ character.initials }}</div>
{% endif %}
</div>
<div class="text-col">
<a class="stretched-link"
href="{{ character.get_absolute_url }}">
{{ character.name }}
</a>
<div>{{ character.subtitle }}</div>
</div>
</div>
</li>

View file

View file

@ -0,0 +1,18 @@
from django import template
from sorl.thumbnail.templatetags.thumbnail import resolution
from rpg_notes import settings
register = template.Library()
@register.filter()
def srcset(filename):
""" Automatically generate the srcset value based on
THUMBNAIL_ALTERNATIVE_RESOLUTIONS settings
"""
lines = [filename]
for res in settings.THUMBNAIL_ALTERNATIVE_RESOLUTIONS:
res_string = "{}x".format(res)
lines.append("{} {}".format(resolution(filename, res_string), res_string))
return ','.join(lines)

3
notes/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

20
notes/urls.py Normal file
View file

@ -0,0 +1,20 @@
from django.urls import path
from notes import views
urlpatterns = [
path("", views.CampaignListView.as_view(), name="campaignlist"),
path("c/add", views.CampaignCreateView.as_view(), name="campaigncreate"),
path("c/<str:campslug>", views.CampaignDetailView.as_view(), name="campaigndetail"),
path("c/<str:campslug>/edit", views.CampaignEditView.as_view(), name="campaignedit"),
path("c/<str:campslug>/delete", views.CampaignDeleteView.as_view(), name="campaigndelete"),
path("c/<str:campslug>/loot", views.LootListView.as_view(), name="lootlist"),
path("c/<str:campslug>/loot/<int:pk>/edit", views.LootEditView.as_view(), name="lootedit"),
path("c/<str:campslug>/loot/<int:pk>/delete", views.LootDeleteView.as_view(), name="lootdelete"),
path("c/<str:campslug>/loot/add", views.LootCreateView.as_view(), name="lootadd"),
path("c/<str:campslug>/character/", views.list_character_redirect, name="characterlist"),
path("c/<str:campslug>/character/add", views.CharacterCreateView.as_view(), name="characteradd"),
path("c/<str:campslug>/character/<str:charslug>", views.CharacterDetailView.as_view(), name="characterdetail"),
path("c/<str:campslug>/character/<str:charslug>/edit", views.CharacterEditView.as_view(), name="characteredit"),
path("c/<str:campslug>/character/<str:charslug>/delete", views.CharacterDeleteView.as_view(), name="characterdelete"),
]

0
notes/utils/__init__.py Normal file
View file

30
notes/utils/assets.py Normal file
View file

@ -0,0 +1,30 @@
from pathlib import Path
import sass
basedir = Path(__file__).resolve().parent.parent.parent
inputdir = basedir / "static/scss/"
inputfile = inputdir / "main.scss"
outputfile = basedir / "static/css/main.css"
sourcemap = outputfile.with_suffix(".css.map")
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
def save_css():
css, sourcemap_text = get_css()
with outputfile.open("w") as f:
f.write(css)
with sourcemap.open("w") as f:
f.write(sourcemap_text)

301
notes/utils/colors.py Normal file
View file

@ -0,0 +1,301 @@
"""
colors from https://stackoverflow.com/a/33295456/4398037
"""
import random
from typing import Tuple
color_string = """#B88183
#922329
#5A0007
#D7BFC2
#D86A78
#FF8A9A
#3B000A
#E20027
#943A4D
#5B4E51
#B05B6F
#FEB2C6
#D83D66
#895563
#FF1A59
#FFDBE5
#CC0744
#CB7E98
#997D87
#6A3A4C
#FF2F80
#6B002C
#A74571
#C6005A
#FF5DA7
#300018
#B894A6
#FF90C9
#7C6571
#A30059
#DA007C
#5B113C
#402334
#D157A0
#DDB6D0
#885578
#962B75
#A97399
#D20096
#E773CE
#AA5199
#E704C4
#6B3A64
#FFA0F2
#6F0062
#B903AA
#C895C5
#FF34FF
#320033
#DBD5DD
#EEC3FF
#BC23FF
#671190
#201625
#F5E1FF
#BC65E9
#D790FF
#72418F
#4A3B53
#9556BD
#B4A8BD
#7900D7
#A079BF
#958A9F
#837393
#64547B
#3A2465
#353339
#BCB1E5
#9F94F0
#9695C5
#0000A6
#000035
#636375
#00005F
#97979E
#7A7BFF
#3C3E6E
#6367A9
#494B5A
#3B5DFF
#C8D0F6
#6D80BA
#8FB0FF
#0045D2
#7A87A1
#324E72
#00489C
#0060CD
#789EC9
#012C58
#99ADC0
#001325
#DDEFFF
#59738A
#0086ED
#75797C
#BDC9D2
#3E89BE
#8CD0FF
#0AA3F7
#6B94AA
#29607C
#404E55
#006FA6
#013349
#0AA6D8
#658188
#5EBCD1
#456D75
#0089A3
#B5F4FF
#02525F
#1CE6FF
#001C1E
#203B3C
#A3C8C9
#00A6AA
#00C6C8
#006A66
#518A87
#E4FFFC
#66E1D3
#004D43
#809693
#15A08A
#00846F
#00C2A0
#00FECF
#78AFA1
#02684E
#C2FFED
#47675D
#00D891
#004B28
#8ADBB4
#0CBD66
#549E79
#1A3A2A
#6C8F7D
#008941
#63FFAC
#1BE177
#006C31
#B5D6C3
#3D4F44
#4B8160
#66796D
#71BB8C
#04F757
#001E09
#D2DCD5
#00B433
#9FB2A4
#003109
#A3F3AB
#456648
#51A058
#83A485
#7ED379
#D1F7CE
#A1C299
#061203
#1E6E00
#5EFF03
#55813B
#3B9700
#4FC601
#1B4400
#C2FF99
#788D66
#868E7E
#83AB58
#374527
#98D058
#C6DC99
#A4E804
#76912F
#8BB400
#34362D
#4C6001
#DFFB71
#6A714A
#222800
#6B7900
#3A3F00
#BEC459
#FEFFE6
#A3A489
#9FA064
#FFFF00
#61615A
#FFFFFE
#9B9700
#CFCDAC
#797868
#575329
#FFF69F
#8D8546
#F4D749
#7E6405
#1D1702
#CCAA35
#CCB87C
#453C23
#513A01
#FFB500
#A77500
#D68E01
#B79762
#7A4900
#372101
#886F4C
#A45B02
#E7AB63
#FAD09F
#C0B9B2
#938A81
#A38469
#D16100
#A76F42
#5B4534
#5B3213
#CA834E
#FF913F
#953F00
#D0AC94
#7D5A44
#BE4700
#FDE8DC
#772600
#A05837
#EA8B66
#391406
#FF6832
#C86240
#29201D
#B77B68
#806C66
#FFAA92
#89412E
#E83000
#A88C85
#F7C9BF
#643127
#E98176
#7B4F4B
#1E0200
#9C6966
#BF5650
#BA0900
#FF4A46
#F4ABAA
#000000
#452C2C
#C8A1A1"""
def get_all_colors():
colors = []
for c in color_string.split("\n"):
colors.append(c.strip()[1:])
return colors
def get_random_color() -> str:
return random.choice(get_all_colors())
## color math from
## https://stackoverflow.com/a/56678483/4398037
def gamma_correction(value: float) -> float:
if value < 0.04045:
return value / 12.92
else:
return ((value + 0.055) / 1.055) ** 2.4
def get_luminance(rgb: Tuple[int, ...]) -> float:
r, g, b = list(map(gamma_correction, rgb))
return 0.2126 * r + 0.7152 * g + 0.0722 * b
def get_percieved_lightness(rgb: Tuple[int, ...]) -> float:
Y = get_luminance(rgb)
if Y <= (216 / 24389):
return Y * (24389 / 27)
else:
return Y ** (1 / 3) * 116 - 16
def is_bright_color(bg_color: str) -> bool:
rgb = tuple(int(bg_color[i:i + 2], 16) for i in (0, 2, 4))
return get_percieved_lightness(rgb) > 50

19
notes/utils/markdown.py Normal file
View file

@ -0,0 +1,19 @@
import bleach
import markdown
from bleach_allowlist import markdown_tags, markdown_attrs
def md_to_html(md: str) -> str:
html = markdown.markdown(
md,
output_format="html",
extensions=[
"nl2br",
]
)
html = bleach.clean(
html,
tags=markdown_tags,
attributes=markdown_attrs
)
return html

4
notes/views/__init__.py Normal file
View file

@ -0,0 +1,4 @@
from .campaign_views import *
from .loot_views import *
from .character_views import *
from .debugviews import *

View file

@ -0,0 +1,38 @@
from django.urls import reverse_lazy
from django.views import generic
from notes.forms import CampaignForm
from notes.models import Campaign
class CampaignListView(generic.ListView):
template_name = "notes/campaign_overview.html"
model = Campaign
context_object_name = "campaigns"
class CampaignDetailView(generic.DetailView):
template_name = "notes/campaign_detail.html"
model = Campaign
slug_url_kwarg = "campslug"
class CampaignCreateView(generic.CreateView):
template_name = "notes/campaign_edit.html"
model = Campaign
form_class = CampaignForm
slug_url_kwarg = "campslug"
class CampaignEditView(generic.UpdateView):
template_name = "notes/campaign_edit.html"
model = Campaign
form_class = CampaignForm
slug_url_kwarg = "campslug"
class CampaignDeleteView(generic.DeleteView):
template_name = "notes/campaign_confirm_delete.html"
model = Campaign
slug_url_kwarg = "campslug"
success_url = reverse_lazy('campaignlist')

View file

@ -0,0 +1,69 @@
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.views import generic
from notes.forms import CharacterForm
from notes.models import Character, Campaign
# class CharacterListView(generic.ListView):
# template_name = "notes/character_overview.html"
# model = Character
# context_object_name = "character"
#
#
#
def list_character_redirect(request, *args, **kwargs):
first_character:Character=Character.objects.first()
return redirect(first_character)
class CharacterDetailView(generic.DetailView):
template_name = "notes/character_detail.html"
model = Character
context_object_name = "character"
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data["player_characters"] = Character.objects.filter(
campaign__slug=self.kwargs['campslug'],
player__isnull=False
)
data["npcs"] = Character.objects.filter(campaign__slug=self.kwargs['campslug'], player__isnull=True)
return data
def get_object(self, queryset=None):
return Character.objects.get(campaign__slug=self.kwargs['campslug'], slug=self.kwargs['charslug'])
class CharacterCreateView(generic.CreateView):
template_name = "notes/loot_edit.html"
model = Character
form_class = CharacterForm
context_object_name = "object"
def form_valid(self, form):
form.instance.campaign = Campaign.objects.get(slug=self.kwargs['campslug'])
return super().form_valid(form)
class CharacterEditView(generic.UpdateView):
template_name = "notes/loot_edit.html"
model = Character
form_class = CharacterForm
def get_object(self, queryset=None):
return Character.objects.get(campaign__slug=self.kwargs['campslug'], slug=self.kwargs['charslug'])
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['edit'] = True
return data
class CharacterDeleteView(generic.DeleteView):
template_name = "notes/campaign_confirm_delete.html"
model = Character
success_url = reverse_lazy('characterlist')

13
notes/views/debugviews.py Normal file
View file

@ -0,0 +1,13 @@
from django.http import HttpResponse
from notes.utils.assets import get_css
def debug_css(request):
css, source_map = get_css(debug=True)
return HttpResponse(css, content_type="text/css")
def debug_css_sourcemap(request):
css, source_map = get_css(debug=True)
return HttpResponse(source_map, content_type="application/json")

51
notes/views/loot_views.py Normal file
View file

@ -0,0 +1,51 @@
from django.urls import reverse_lazy, reverse
from django.views import generic
from notes.forms import LootForm
from notes.models import Loot, Campaign
class LootListView(generic.ListView):
template_name = "notes/loot_overview.html"
model = Loot
context_object_name = "loot"
def get_queryset(self):
return Loot.objects.filter(campaign__slug=self.kwargs['campslug'])
class LootDetailView(generic.DetailView):
template_name = "notes/loot_detail.html"
model = Loot
class LootCreateView(generic.CreateView):
template_name = "notes/loot_edit.html"
model = Loot
form_class = LootForm
def form_valid(self, form):
form.instance.campaign = Campaign.objects.get(slug=self.kwargs['campslug'])
return super().form_valid(form)
success_url = reverse_lazy('lootlist')
class LootEditView(generic.UpdateView):
template_name = "notes/loot_edit.html"
model = Loot
form_class = LootForm
context_object_name = "object"
def get_success_url(self):
return reverse("lootlist", kwargs={"campslug": self.kwargs.get("campslug")})
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['edit'] = True
return data
class LootDeleteView(generic.DeleteView):
template_name = "notes/loot_confirm_delete.html"
model = Loot
success_url = reverse_lazy('lootlist')

48
package-lock.json generated Normal file
View file

@ -0,0 +1,48 @@
{
"name": "RPGnotes",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"bootstrap": "^5.1.0"
}
},
"node_modules/@popperjs/core": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.3.tgz",
"integrity": "sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ==",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/bootstrap": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.0.tgz",
"integrity": "sha512-bs74WNI9BgBo3cEovmdMHikSKoXnDgA6VQjJ7TyTotU6L7d41ZyCEEelPwkYEzsG/Zjv3ie9IE3EMAje0W9Xew==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
},
"peerDependencies": {
"@popperjs/core": "^2.9.3"
}
}
},
"dependencies": {
"@popperjs/core": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.3.tgz",
"integrity": "sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ==",
"peer": true
},
"bootstrap": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.0.tgz",
"integrity": "sha512-bs74WNI9BgBo3cEovmdMHikSKoXnDgA6VQjJ7TyTotU6L7d41ZyCEEelPwkYEzsG/Zjv3ie9IE3EMAje0W9Xew==",
"requires": {}
}
}
}

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"dependencies": {
"bootstrap": "^5.1.0"
}
}

323
poetry.lock generated Normal file
View file

@ -0,0 +1,323 @@
[[package]]
name = "asgiref"
version = "3.4.1"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"]
[[package]]
name = "beautifulsoup4"
version = "4.9.3"
description = "Screen-scraping library"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
soupsieve = {version = ">1.2", markers = "python_version >= \"3.0\""}
[package.extras]
html5lib = ["html5lib"]
lxml = ["lxml"]
[[package]]
name = "bleach"
version = "4.0.0"
description = "An easy safelist-based HTML-sanitizing tool."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
packaging = "*"
six = ">=1.9.0"
webencodings = "*"
[[package]]
name = "bleach-allowlist"
version = "1.0.3"
description = "Curated lists of tags and attributes for sanitizing html"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "django"
version = "3.2.6"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
asgiref = ">=3.3.2,<4"
pytz = "*"
sqlparse = ">=0.2.2"
[package.extras]
argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
name = "django-bootstrap5"
version = "2.1.2"
description = "Bootstrap 5 for Django"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
beautifulsoup4 = ">=4.8.0"
Django = ">=2.2"
[[package]]
name = "django-simple-history"
version = "3.0.0"
description = "Store model history and view/revert changes from admin site."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "libsass"
version = "0.21.0"
description = "Sass for Python: A straightforward binding of libsass for Python."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
six = "*"
[[package]]
name = "markdown"
version = "3.3.4"
description = "Python implementation of Markdown."
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
testing = ["coverage", "pyyaml"]
[[package]]
name = "packaging"
version = "21.0"
description = "Core utilities for Python packages"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
pyparsing = ">=2.0.2"
[[package]]
name = "pillow"
version = "8.3.1"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "psycopg2"
version = "2.9.1"
description = "psycopg2 - Python-PostgreSQL Database Adapter"
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "pyparsing"
version = "2.4.7"
description = "Python parsing module"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "pytz"
version = "2021.1"
description = "World timezone definitions, modern and historical"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "sorl-thumbnail"
version = "12.7.0"
description = "Thumbnails for Django"
category = "main"
optional = false
python-versions = ">=3.4"
[[package]]
name = "soupsieve"
version = "2.2.1"
description = "A modern CSS selector implementation for Beautiful Soup."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "sqlparse"
version = "0.4.1"
description = "A non-validating SQL parser."
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "webencodings"
version = "0.5.1"
description = "Character encoding aliases for legacy web content"
category = "main"
optional = false
python-versions = "*"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "245e8ddb9d285feb2d4ab950fa117b8422d0634fece9a59938b663cbeb4f45ae"
[metadata.files]
asgiref = [
{file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"},
{file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"},
]
beautifulsoup4 = [
{file = "beautifulsoup4-4.9.3-py2-none-any.whl", hash = "sha256:4c98143716ef1cb40bf7f39a8e3eec8f8b009509e74904ba3a7b315431577e35"},
{file = "beautifulsoup4-4.9.3-py3-none-any.whl", hash = "sha256:fff47e031e34ec82bf17e00da8f592fe7de69aeea38be00523c04623c04fb666"},
{file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"},
]
bleach = [
{file = "bleach-4.0.0-py2.py3-none-any.whl", hash = "sha256:c1685a132e6a9a38bf93752e5faab33a9517a6c0bb2f37b785e47bf253bdb51d"},
{file = "bleach-4.0.0.tar.gz", hash = "sha256:ffa9221c6ac29399cc50fcc33473366edd0cf8d5e2cbbbb63296dc327fb67cc8"},
]
bleach-allowlist = [
{file = "bleach-allowlist-1.0.3.tar.gz", hash = "sha256:56e22086079a0e6a3100ae99e4dbaf20eb2585486598eb0e994008a11428da9b"},
{file = "bleach_allowlist-1.0.3-py2.py3-none-any.whl", hash = "sha256:6427a3ac0baddf549703f1003ea53f411f3d7888524c94c00eb6ef1deb378899"},
]
django = [
{file = "Django-3.2.6-py3-none-any.whl", hash = "sha256:7f92413529aa0e291f3be78ab19be31aefb1e1c9a52cd59e130f505f27a51f13"},
{file = "Django-3.2.6.tar.gz", hash = "sha256:f27f8544c9d4c383bbe007c57e3235918e258364577373d4920e9162837be022"},
]
django-bootstrap5 = [
{file = "django-bootstrap5-2.1.2.tar.gz", hash = "sha256:ac05ca69b990e62657c0bf40db14946c22fd64c7fb9dfe094a9f22ecc58f86c5"},
{file = "django_bootstrap5-2.1.2-py3-none-any.whl", hash = "sha256:0021355df9212c511876e3f5336ba470416a6dd52f61bf5acec5bb783ab41ff5"},
]
django-simple-history = [
{file = "django-simple-history-3.0.0.tar.gz", hash = "sha256:66fe76c560054be393c52b1799661e104fbe372918d37d151e5d41c676158118"},
{file = "django_simple_history-3.0.0-py2.py3-none-any.whl", hash = "sha256:a312adfe8fbec4c450b08e641b11249a8a589a7e7d1ba2404764b8b5bed53552"},
]
libsass = [
{file = "libsass-0.21.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:06c8776417fe930714bdc930a3d7e795ae3d72be6ac883ff72a1b8f7c49e5ffb"},
{file = "libsass-0.21.0-cp27-cp27m-win32.whl", hash = "sha256:a005f298f64624f313a3ac618ab03f844c71d84ae4f4a4aec4b68d2a4ffe75eb"},
{file = "libsass-0.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:6b984510ed94993708c0d697b4fef2d118929bbfffc3b90037be0f5ccadf55e7"},
{file = "libsass-0.21.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e25dd9047a9392d3c59a0b869e0404f2b325a03871ee45285ee33b3664f5613"},
{file = "libsass-0.21.0-cp36-abi3-macosx_10_14_x86_64.whl", hash = "sha256:12f39712de38689a8b785b7db41d3ba2ea1d46f9379d81ea4595802d91fa6529"},
{file = "libsass-0.21.0-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e2b1a7d093f2e76dc694c17c0c285e846d0b0deb0e8b21dc852ba1a3a4e2f1d6"},
{file = "libsass-0.21.0-cp36-abi3-win32.whl", hash = "sha256:abc29357ee540849faf1383e1746d40d69ed5cb6d4c346df276b258f5aa8977a"},
{file = "libsass-0.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:659ae41af8708681fa3ec73f47b9735a6725e71c3b66ff570bfce78952f2314e"},
{file = "libsass-0.21.0.tar.gz", hash = "sha256:d5ba529d9ce668be9380563279f3ffe988f27bc5b299c5a28453df2e0b0fbaf2"},
]
markdown = [
{file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"},
{file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"},
]
packaging = [
{file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
{file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
]
pillow = [
{file = "Pillow-8.3.1-1-cp36-cp36m-win_amd64.whl", hash = "sha256:fd7eef578f5b2200d066db1b50c4aa66410786201669fb76d5238b007918fb24"},
{file = "Pillow-8.3.1-1-cp37-cp37m-win_amd64.whl", hash = "sha256:75e09042a3b39e0ea61ce37e941221313d51a9c26b8e54e12b3ececccb71718a"},
{file = "Pillow-8.3.1-1-cp38-cp38-win_amd64.whl", hash = "sha256:c0e0550a404c69aab1e04ae89cca3e2a042b56ab043f7f729d984bf73ed2a093"},
{file = "Pillow-8.3.1-1-cp39-cp39-win_amd64.whl", hash = "sha256:479ab11cbd69612acefa8286481f65c5dece2002ffaa4f9db62682379ca3bb77"},
{file = "Pillow-8.3.1-1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f156d6ecfc747ee111c167f8faf5f4953761b5e66e91a4e6767e548d0f80129c"},
{file = "Pillow-8.3.1-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:196560dba4da7a72c5e7085fccc5938ab4075fd37fe8b5468869724109812edd"},
{file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c9569049d04aaacd690573a0398dbd8e0bf0255684fee512b413c2142ab723"},
{file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c088a000dfdd88c184cc7271bfac8c5b82d9efa8637cd2b68183771e3cf56f04"},
{file = "Pillow-8.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fc214a6b75d2e0ea7745488da7da3c381f41790812988c7a92345978414fad37"},
{file = "Pillow-8.3.1-cp36-cp36m-win32.whl", hash = "sha256:a17ca41f45cf78c2216ebfab03add7cc350c305c38ff34ef4eef66b7d76c5229"},
{file = "Pillow-8.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:67b3666b544b953a2777cb3f5a922e991be73ab32635666ee72e05876b8a92de"},
{file = "Pillow-8.3.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:ff04c373477723430dce2e9d024c708a047d44cf17166bf16e604b379bf0ca14"},
{file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9364c81b252d8348e9cc0cb63e856b8f7c1b340caba6ee7a7a65c968312f7dab"},
{file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a2f381932dca2cf775811a008aa3027671ace723b7a38838045b1aee8669fdcf"},
{file = "Pillow-8.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d0da39795049a9afcaadec532e7b669b5ebbb2a9134576ebcc15dd5bdae33cc0"},
{file = "Pillow-8.3.1-cp37-cp37m-win32.whl", hash = "sha256:2b6dfa068a8b6137da34a4936f5a816aba0ecc967af2feeb32c4393ddd671cba"},
{file = "Pillow-8.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a4eef1ff2d62676deabf076f963eda4da34b51bc0517c70239fafed1d5b51500"},
{file = "Pillow-8.3.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:660a87085925c61a0dcc80efb967512ac34dbb256ff7dd2b9b4ee8dbdab58cf4"},
{file = "Pillow-8.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:15a2808e269a1cf2131930183dcc0419bc77bb73eb54285dde2706ac9939fa8e"},
{file = "Pillow-8.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:969cc558cca859cadf24f890fc009e1bce7d7d0386ba7c0478641a60199adf79"},
{file = "Pillow-8.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ee77c14a0299d0541d26f3d8500bb57e081233e3fa915fa35abd02c51fa7fae"},
{file = "Pillow-8.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c11003197f908878164f0e6da15fce22373ac3fc320cda8c9d16e6bba105b844"},
{file = "Pillow-8.3.1-cp38-cp38-win32.whl", hash = "sha256:3f08bd8d785204149b5b33e3b5f0ebbfe2190ea58d1a051c578e29e39bfd2367"},
{file = "Pillow-8.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:70af7d222df0ff81a2da601fab42decb009dc721545ed78549cb96e3a1c5f0c8"},
{file = "Pillow-8.3.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:37730f6e68bdc6a3f02d2079c34c532330d206429f3cee651aab6b66839a9f0e"},
{file = "Pillow-8.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bc3c7ef940eeb200ca65bd83005eb3aae8083d47e8fcbf5f0943baa50726856"},
{file = "Pillow-8.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c35d09db702f4185ba22bb33ef1751ad49c266534339a5cebeb5159d364f6f82"},
{file = "Pillow-8.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b2efa07f69dc395d95bb9ef3299f4ca29bcb2157dc615bae0b42c3c20668ffc"},
{file = "Pillow-8.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cc866706d56bd3a7dbf8bac8660c6f6462f2f2b8a49add2ba617bc0c54473d83"},
{file = "Pillow-8.3.1-cp39-cp39-win32.whl", hash = "sha256:9a211b663cf2314edbdb4cf897beeb5c9ee3810d1d53f0e423f06d6ebbf9cd5d"},
{file = "Pillow-8.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:c2a5ff58751670292b406b9f06e07ed1446a4b13ffced6b6cab75b857485cbc8"},
{file = "Pillow-8.3.1-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c379425c2707078dfb6bfad2430728831d399dc95a7deeb92015eb4c92345eaf"},
{file = "Pillow-8.3.1-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:114f816e4f73f9ec06997b2fde81a92cbf0777c9e8f462005550eed6bae57e63"},
{file = "Pillow-8.3.1-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8960a8a9f4598974e4c2aeb1bff9bdd5db03ee65fd1fce8adf3223721aa2a636"},
{file = "Pillow-8.3.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:147bd9e71fb9dcf08357b4d530b5167941e222a6fd21f869c7911bac40b9994d"},
{file = "Pillow-8.3.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1fd5066cd343b5db88c048d971994e56b296868766e461b82fa4e22498f34d77"},
{file = "Pillow-8.3.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f4ebde71785f8bceb39dcd1e7f06bcc5d5c3cf48b9f69ab52636309387b097c8"},
{file = "Pillow-8.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c03e24be975e2afe70dfc5da6f187eea0b49a68bb2b69db0f30a61b7031cee4"},
{file = "Pillow-8.3.1.tar.gz", hash = "sha256:2cac53839bfc5cece8fdbe7f084d5e3ee61e1303cccc86511d351adcb9e2c792"},
]
psycopg2 = [
{file = "psycopg2-2.9.1-cp36-cp36m-win32.whl", hash = "sha256:7f91312f065df517187134cce8e395ab37f5b601a42446bdc0f0d51773621854"},
{file = "psycopg2-2.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:830c8e8dddab6b6716a4bf73a09910c7954a92f40cf1d1e702fb93c8a919cc56"},
{file = "psycopg2-2.9.1-cp37-cp37m-win32.whl", hash = "sha256:89409d369f4882c47f7ea20c42c5046879ce22c1e4ea20ef3b00a4dfc0a7f188"},
{file = "psycopg2-2.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7640e1e4d72444ef012e275e7b53204d7fab341fb22bc76057ede22fe6860b25"},
{file = "psycopg2-2.9.1-cp38-cp38-win32.whl", hash = "sha256:079d97fc22de90da1d370c90583659a9f9a6ee4007355f5825e5f1c70dffc1fa"},
{file = "psycopg2-2.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:2c992196719fadda59f72d44603ee1a2fdcc67de097eea38d41c7ad9ad246e62"},
{file = "psycopg2-2.9.1-cp39-cp39-win32.whl", hash = "sha256:2087013c159a73e09713294a44d0c8008204d06326006b7f652bef5ace66eebb"},
{file = "psycopg2-2.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:bf35a25f1aaa8a3781195595577fcbb59934856ee46b4f252f56ad12b8043bcf"},
{file = "psycopg2-2.9.1.tar.gz", hash = "sha256:de5303a6f1d0a7a34b9d40e4d3bef684ccc44a49bbe3eb85e3c0bffb4a131b7c"},
]
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pytz = [
{file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
{file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
sorl-thumbnail = [
{file = "sorl-thumbnail-12.7.0.tar.gz", hash = "sha256:fbe6dfd66a1aceb7e0203895ff5622775e50266f8d8cfd841fe1500bd3e19018"},
{file = "sorl_thumbnail-12.7.0-py3-none-any.whl", hash = "sha256:c56cd651feab3bdc415d5301600198e2e70c08234dad48b8f6cfa4746cc102c7"},
]
soupsieve = [
{file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"},
{file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"},
]
sqlparse = [
{file = "sqlparse-0.4.1-py3-none-any.whl", hash = "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0"},
{file = "sqlparse-0.4.1.tar.gz", hash = "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"},
]
webencodings = [
{file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
{file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
]

24
pyproject.toml Normal file
View file

@ -0,0 +1,24 @@
[tool.poetry]
name = "rpgnotes"
version = "0.1.0"
description = ""
authors = ["Lukas Winkler <git@lw1.at>"]
[tool.poetry.dependencies]
python = "^3.9"
Django = "^3.2.6"
psycopg2 = "^2.9.1"
django-simple-history = "^3.0.0"
django-bootstrap5 = "^2.1.2"
Markdown = "^3.3.4"
bleach = "^4.0.0"
bleach-allowlist = "^1.0.3"
Pillow = "^8.3.1"
sorl-thumbnail = "^12.7.0"
libsass = "^0.21.0"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

0
rpg_notes/__init__.py Normal file
View file

16
rpg_notes/asgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
ASGI config for rpg_notes project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rpg_notes.settings')
application = get_asgi_application()

115
rpg_notes/settings.py Normal file
View file

@ -0,0 +1,115 @@
"""
Django settings for rpg_notes project.
Generated by 'django-admin startproject' using Django 3.2.6.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
from .secrets import *
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'notes.apps.NotesConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'simple_history',
'django_bootstrap5',
'sorl.thumbnail'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware'
]
ROOT_URLCONF = 'rpg_notes.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'rpg_notes.wsgi.application'
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
THUMBNAIL_ALTERNATIVE_RESOLUTIONS = [2, 3]

31
rpg_notes/urls.py Normal file
View file

@ -0,0 +1,31 @@
"""rpg_notes URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
from notes import views
from rpg_notes import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("notes.urls"))
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns.append(path("css", views.debug_css, name="css"))
urlpatterns.append(path("css_sourcemap", views.debug_css_sourcemap, name="css_sourcemap"))

16
rpg_notes/wsgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
WSGI config for rpg_notes project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rpg_notes.settings')
application = get_wsgi_application()

1
static/libs/bootstrap.min.css vendored Symbolic link
View file

@ -0,0 +1 @@
../../node_modules/bootstrap/dist/css/bootstrap.min.css

View file

@ -0,0 +1 @@
../../node_modules/bootstrap/dist/css/bootstrap.min.css.map

1
static/libs/bootstrap.min.js vendored Symbolic link
View file

@ -0,0 +1 @@
../../node_modules/bootstrap/dist/js/bootstrap.min.js

View file

@ -0,0 +1 @@
../../node_modules/bootstrap/dist/js/bootstrap.min.js.map

54
static/scss/_misc.scss Normal file
View file

@ -0,0 +1,54 @@
.collapse-cell {
padding: 0 !important;
border: none !important;
}
.chev {
transition: transform .2s;
width: 13px;
height: auto;
}
tr.collapsed .chev {
transform: rotate(90deg);
}
tr.collapse-button:not(.collapsed) {
background: darkgray;
}
.avatar {
display: block;
font-size: 1em;
width: 48px;
height: 48px;
line-height: 48px;
text-align: center;
border-radius: 50%;
vertical-align: middle;
color: white;
font-family: sans-serif;
}
.side-card {
display: flex;
position: relative;
> div {
padding: 0.5rem;
}
.text-col {
a {
text-decoration: none;
&:focus,&:active,&:hover{
text-decoration: underline;
}
}
}
}
.character-heading {
border-bottom: solid 2px;
}

View file

5
static/scss/main.scss Normal file
View file

@ -0,0 +1,5 @@
@import "variables";
@import "node_modules/bootstrap/scss/bootstrap";
@import "misc";