mirror of
https://github.com/Findus23/RPGnotes.git
synced 2024-09-18 14:33:44 +02:00
initial version
This commit is contained in:
commit
71b0d1cac8
64 changed files with 2210 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
.idea/
|
||||
secrets.py
|
||||
media/
|
||||
__pycache__/
|
||||
static/css
|
||||
node_modules
|
22
manage.py
Executable file
22
manage.py
Executable 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
0
notes/__init__.py
Normal file
10
notes/admin.py
Normal file
10
notes/admin.py
Normal 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
6
notes/apps.py
Normal 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
21
notes/forms.py
Normal 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"]
|
83
notes/migrations/0001_initial.py
Normal file
83
notes/migrations/0001_initial.py
Normal 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)),
|
||||
],
|
||||
),
|
||||
]
|
33
notes/migrations/0002_auto_20210822_1109.py
Normal file
33
notes/migrations/0002_auto_20210822_1109.py
Normal 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),
|
||||
),
|
||||
]
|
38
notes/migrations/0003_auto_20210822_1110.py
Normal file
38
notes/migrations/0003_auto_20210822_1110.py
Normal 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),
|
||||
),
|
||||
]
|
|
@ -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),
|
||||
),
|
||||
]
|
40
notes/migrations/0005_auto_20210822_1259.py
Normal file
40
notes/migrations/0005_auto_20210822_1259.py
Normal 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')},
|
||||
),
|
||||
]
|
123
notes/migrations/0006_auto_20210822_1421.py
Normal file
123
notes/migrations/0006_auto_20210822_1421.py
Normal 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)'),
|
||||
),
|
||||
]
|
31
notes/migrations/0007_auto_20210822_1551.py
Normal file
31
notes/migrations/0007_auto_20210822_1551.py
Normal 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(),
|
||||
),
|
||||
]
|
24
notes/migrations/0008_auto_20210822_1610.py
Normal file
24
notes/migrations/0008_auto_20210822_1610.py
Normal 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),
|
||||
),
|
||||
]
|
23
notes/migrations/0009_auto_20210822_1702.py
Normal file
23
notes/migrations/0009_auto_20210822_1702.py
Normal 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),
|
||||
),
|
||||
]
|
19
notes/migrations/0010_alter_character_image.py
Normal file
19
notes/migrations/0010_alter_character_image.py
Normal 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'),
|
||||
),
|
||||
]
|
0
notes/migrations/__init__.py
Normal file
0
notes/migrations/__init__.py
Normal file
7
notes/models/__init__.py
Normal file
7
notes/models/__init__.py
Normal 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
24
notes/models/basemodel.py
Normal 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
21
notes/models/campaign.py
Normal 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
33
notes/models/character.py
Normal 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"
|
16
notes/models/descriptionmodel.py
Normal file
16
notes/models/descriptionmodel.py
Normal 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
10
notes/models/faction.py
Normal 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
11
notes/models/location.py
Normal 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
25
notes/models/loot.py
Normal 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
26
notes/templates/base.html
Normal 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>
|
29
notes/templates/navbarbase.html
Normal file
29
notes/templates/navbarbase.html
Normal 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 %}
|
14
notes/templates/notes/campaign_confirm_delete.html
Normal file
14
notes/templates/notes/campaign_confirm_delete.html
Normal 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 %}
|
5
notes/templates/notes/campaign_detail.html
Normal file
5
notes/templates/notes/campaign_detail.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
{% extends "navbarbase.html" %}
|
||||
|
||||
{% block content %}
|
||||
{{ object }}
|
||||
{% endblock %}
|
20
notes/templates/notes/campaign_edit.html
Normal file
20
notes/templates/notes/campaign_edit.html
Normal 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 %}#}
|
8
notes/templates/notes/campaign_overview.html
Normal file
8
notes/templates/notes/campaign_overview.html
Normal 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 %}
|
37
notes/templates/notes/character_detail.html
Normal file
37
notes/templates/notes/character_detail.html
Normal 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 %}
|
26
notes/templates/notes/loot_edit.html
Normal file
26
notes/templates/notes/loot_edit.html
Normal 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 %}#}
|
49
notes/templates/notes/loot_overview.html
Normal file
49
notes/templates/notes/loot_overview.html
Normal 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 %}
|
||||
|
25
notes/templates/notes/macros/character-pillar.html
Normal file
25
notes/templates/notes/macros/character-pillar.html
Normal 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>
|
0
notes/templatetags/__init__.py
Normal file
0
notes/templatetags/__init__.py
Normal file
18
notes/templatetags/thumbutils.py
Normal file
18
notes/templatetags/thumbutils.py
Normal 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
3
notes/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
20
notes/urls.py
Normal file
20
notes/urls.py
Normal 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
0
notes/utils/__init__.py
Normal file
30
notes/utils/assets.py
Normal file
30
notes/utils/assets.py
Normal 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
301
notes/utils/colors.py
Normal 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
19
notes/utils/markdown.py
Normal 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
4
notes/views/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from .campaign_views import *
|
||||
from .loot_views import *
|
||||
from .character_views import *
|
||||
from .debugviews import *
|
38
notes/views/campaign_views.py
Normal file
38
notes/views/campaign_views.py
Normal 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')
|
69
notes/views/character_views.py
Normal file
69
notes/views/character_views.py
Normal 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
13
notes/views/debugviews.py
Normal 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
51
notes/views/loot_views.py
Normal 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
48
package-lock.json
generated
Normal 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
5
package.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.1.0"
|
||||
}
|
||||
}
|
323
poetry.lock
generated
Normal file
323
poetry.lock
generated
Normal 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
24
pyproject.toml
Normal 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
0
rpg_notes/__init__.py
Normal file
16
rpg_notes/asgi.py
Normal file
16
rpg_notes/asgi.py
Normal 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
115
rpg_notes/settings.py
Normal 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
31
rpg_notes/urls.py
Normal 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
16
rpg_notes/wsgi.py
Normal 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
1
static/libs/bootstrap.min.css
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../node_modules/bootstrap/dist/css/bootstrap.min.css
|
1
static/libs/bootstrap.min.css.map
Symbolic link
1
static/libs/bootstrap.min.css.map
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../node_modules/bootstrap/dist/css/bootstrap.min.css.map
|
1
static/libs/bootstrap.min.js
vendored
Symbolic link
1
static/libs/bootstrap.min.js
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../node_modules/bootstrap/dist/js/bootstrap.min.js
|
1
static/libs/bootstrap.min.js.map
Symbolic link
1
static/libs/bootstrap.min.js.map
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../node_modules/bootstrap/dist/js/bootstrap.min.js.map
|
54
static/scss/_misc.scss
Normal file
54
static/scss/_misc.scss
Normal 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;
|
||||
}
|
0
static/scss/_variables.scss
Normal file
0
static/scss/_variables.scss
Normal file
5
static/scss/main.scss
Normal file
5
static/scss/main.scss
Normal file
|
@ -0,0 +1,5 @@
|
|||
@import "variables";
|
||||
|
||||
@import "node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
@import "misc";
|
Loading…
Reference in a new issue