Compare commits

...

10 Commits

Author SHA1 Message Date
5efcee12a9 frontend: sort by title 2023-08-03 20:18:43 +02:00
b838c79cdb CSRF $#%?@!!. Also konami to django admin 2023-08-03 20:11:45 +02:00
e8abfaf51b Add example system config files 2023-08-03 18:00:27 +02:00
55711d68c1 backend: allow all hosts 2023-08-03 17:59:59 +02:00
2b539a45d2 Set subs per product category 2023-07-03 20:52:43 +02:00
2895d295e4 Update README 2023-07-03 20:02:09 +02:00
74d7564bdc frontend: avoid double slash in data urls 2023-07-03 19:57:14 +02:00
0d164a1f31 Now deployable 2023-07-03 19:56:32 +02:00
2395bc215d Backend LGTM 2023-07-03 16:56:58 +02:00
9a7ce60913 manage.py makemigrations 2023-07-03 16:38:35 +02:00
9 changed files with 131 additions and 23 deletions

View File

@@ -1,6 +1,7 @@
FROM alpine FROM alpine
RUN apk --no-cache add python3 inkscape bash imagemagick ttf-opensans RUN apk --no-cache add python3 inkscape bash imagemagick ttf-opensans
RUN apk --no-cache add py3-pip && pip3 install django tzdata gunicorn
ADD backend /root/zetikettes ADD backend /root/zetikettes
@@ -8,6 +9,7 @@ RUN mkdir -p /usr/share/fonts/TTF \
&& cp /root/zetikettes/fonts/*.ttf /usr/share/fonts/TTF/ \ && cp /root/zetikettes/fonts/*.ttf /usr/share/fonts/TTF/ \
&& fc-cache -fv && fc-cache -fv
# the script will look for templates in /data # the script will look for templates in /data
WORKDIR /root/zetikettes WORKDIR /root/zetikettes/zetikettes
CMD /usr/bin/python3 web.py CMD /usr/bin/gunicorn zetikettes.wsgi -b 0.0.0.0:8000 --timeout 600

View File

@@ -21,7 +21,7 @@ Test
---- ----
``` ```
docker run --rm -it -v $PWD/templates:/data zetikettes /bin/bash /root/zetikettes/mkjam.sh docker run --rm -it -v $PWD/templates:/data zetikettes /bin/bash /root/zetikettes/old/mkjam.sh
``` ```
This should produce a .pdf in `templates/`. Open it to check that This should produce a .pdf in `templates/`. Open it to check that
@@ -34,10 +34,28 @@ Run
docker run -d --rm -p 127.0.0.1:8000:8000 -v /var/lib/zetikettes/templates:/data zetikettes docker run -d --rm -p 127.0.0.1:8000:8000 -v /var/lib/zetikettes/templates:/data zetikettes
``` ```
Notes for deploying
-------------------
.h3 Initialize empty database
```
python manage.py migrate
```
.h3 Prepare static files
```
python manage.py collectstatic
```
The files will be in `www_static/` and need to be moved to `/var/lib/zetikettes/www_static`
.h3 Change host settings
If not deploying on `aerith.ponteilla.net`, you'll need to edit `backend/zetikettes/zetikettes/settings.py` to change a couple things in there.
Change available templates Change available templates
-------------------------- --------------------------
1. go to /zetikettes/newtikette.html or konami code from main app 1. go to /zetikettes/admin
1. add the newtikette 1. add the newtikette
1. still no need to restart the container (magic!) 1. still no need to restart the container (magic!)
2. profit. 2. profit.

View File

@@ -0,0 +1,51 @@
# Generated by Django 4.2.2 on 2023-07-03 14:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Tikategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
('landscape', models.BooleanField()),
],
options={
'verbose_name_plural': 'tikategoriez',
},
),
migrations.CreateModel(
name='Tisub',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
('descritpion', models.TextField()),
('default', models.TextField()),
],
options={
'verbose_name_plural': 'tisubz',
},
),
migrations.CreateModel(
name='Tikette',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100)),
('svg', models.FileField(upload_to='')),
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tikette.tikategory')),
('subs', models.ManyToManyField(to='tikette.tisub')),
],
options={
'verbose_name_plural': 'tikettz',
},
),
]

View File

@@ -1,16 +1,5 @@
from django.db import models from django.db import models
class Tikategory(models.Model):
name = models.CharField(max_length=50)
landscape = models.BooleanField()
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "tikategoriez"
class Tisub(models.Model): class Tisub(models.Model):
name = models.CharField(max_length=50) name = models.CharField(max_length=50)
descritpion = models.TextField() descritpion = models.TextField()
@@ -23,11 +12,22 @@ class Tisub(models.Model):
verbose_name_plural = "tisubz" verbose_name_plural = "tisubz"
class Tikategory(models.Model):
name = models.CharField(max_length=50)
landscape = models.BooleanField()
subs = models.ManyToManyField(Tisub)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "tikategoriez"
class Tikette(models.Model): class Tikette(models.Model):
title = models.CharField(max_length=100) title = models.CharField(max_length=100)
category = models.ForeignKey(Tikategory, on_delete=models.CASCADE) category = models.ForeignKey(Tikategory, on_delete=models.CASCADE)
svg = models.FileField() svg = models.FileField()
subs = models.ManyToManyField(Tisub)
def __str__(self): def __str__(self):
return self.title return self.title

View File

@@ -16,7 +16,7 @@ def index(request):
'category': x.category.name, 'category': x.category.name,
'sticker': x.svg.name, 'sticker': x.svg.name,
'landscape': x.category.landscape, 'landscape': x.category.landscape,
'subs': {x.name: x.default for x in x.subs.all()}, 'subs': {x.name: x.default for x in x.category.subs.all()},
} for x in Tikette.objects.all()] } for x in Tikette.objects.all()]
return JsonResponse({'status': 'ok', 'tikettes': tikettes}, headers=CORS) return JsonResponse({'status': 'ok', 'tikettes': tikettes}, headers=CORS)

View File

@@ -18,7 +18,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
#TIKETTE_OUT_DIR = BASE_DIR / 'data' #TIKETTE_OUT_DIR = BASE_DIR / 'data'
TIKETTE_OUT_DIR = Path('/data') TIKETTE_OUT_DIR = Path('/data')
MEDIA_ROOT = TIKETTE_OUT_DIR MEDIA_ROOT = TIKETTE_OUT_DIR
MEDIA_URL = 'data/' MEDIA_URL = '/data/'
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
@@ -29,7 +29,8 @@ SECRET_KEY = 'django-insecure-64qxpe55#9wy=5@#dl0)3w7ywxh48m!f&!slp9e7v4lh@hjdct
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = ['*']
CSRF_TRUSTED_ORIGINS = ['https://*.ponteilla.net']
# Application definition # Application definition
@@ -81,7 +82,7 @@ WSGI_APPLICATION = 'zetikettes.wsgi.application'
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3', 'NAME': TIKETTE_OUT_DIR / 'db.sqlite3',
} }
} }
@@ -122,6 +123,8 @@ USE_TZ = True
STATIC_URL = 'static/' STATIC_URL = 'static/'
STATIC_ROOT = 'www_static'
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

View File

@@ -35,7 +35,7 @@ function loadAll(zetikettes) {
$.post(backend_api, JSON.stringify(req)) $.post(backend_api, JSON.stringify(req))
.then(data => { .then(data => {
console.log(data); console.log(data);
const pdfbtn = $(`<a class="btn" href="${backend_api}/data/${data.file}" target="_blank">open pdf</a>`); const pdfbtn = $(`<a class="btn" href="${backend_api}data/${data.file}" target="_blank">open pdf</a>`);
action.append(pdfbtn); action.append(pdfbtn);
}) })
.catch(err => { .catch(err => {
@@ -67,7 +67,7 @@ function konami() {
$(document).keydown(function (e) { $(document).keydown(function (e) {
if (e.keyCode === k[n++]) { if (e.keyCode === k[n++]) {
if (n === k.length) { if (n === k.length) {
document.location.href = 'newtikette.html'; document.location.href = backend_api + 'admin';
} }
} }
else { else {
@@ -82,7 +82,7 @@ $(document).ready(async () => {
url: backend_api + 'list', url: backend_api + 'list',
timeout: 1000, timeout: 1000,
}); });
loadAll(resp.tikettes); loadAll(resp.tikettes.sort((a, b) => (a.title < b.title) ? -1 : 1));
} catch(e) { } catch(e) {
const appbody = $("#appbody"); const appbody = $("#appbody");
appbody.append(`<li>Could not reach backend server`); appbody.append(`<li>Could not reach backend server`);

18
nginx_locations Normal file
View File

@@ -0,0 +1,18 @@
# prod site
location /zetikettes {
alias /var/lib/zetikettes/frontend;
}
location /zetikettes/srv/static {
alias /var/lib/zetikettes/www_static;
}
location ^~ /zetikettes/srv {
proxy_pass http://127.0.0.1:8000;
proxy_set_header SCRIPT_NAME /zetikettes/srv;
proxy_set_header Host $http_host;
# generating stuff takes time
proxy_read_timeout 10m;
client_max_body_size 10M;
}

16
zetikettes.service Normal file
View File

@@ -0,0 +1,16 @@
[Unit]
Description=Zetikettes backend service
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/bin/docker run --rm --name %n \
-p 127.0.0.1:8000:8000 \
-v /var/lib/zetikettes/data:/data \
zetikettes
Restart=on-failure
ExecStartPre=-/usr/bin/docker exec %n stop
ExecStartPre=-/usr/bin/docker rm %n
[Install]
WantedBy=multi-user.target