diff --git a/backend/zetikettes/tikette/admin.py b/backend/zetikettes/tikette/admin.py index 8c38f3f..149dd87 100644 --- a/backend/zetikettes/tikette/admin.py +++ b/backend/zetikettes/tikette/admin.py @@ -1,3 +1,9 @@ from django.contrib import admin +from .models import Tikette, Tikategory, Tisub + +admin.site.register(Tikette) +admin.site.register(Tikategory) +admin.site.register(Tisub) + # Register your models here. diff --git a/backend/zetikettes/tikette/generate.py b/backend/zetikettes/tikette/generate.py new file mode 100644 index 0000000..2211b03 --- /dev/null +++ b/backend/zetikettes/tikette/generate.py @@ -0,0 +1,61 @@ +import os +import subprocess +import tempfile + +from .makesticker import makesticker +from .makeplanche import makeplanche + +OUT_DIR = tempfile.gettempdir() +DEFAULT_DPI = 300 + +def inkscapize(svg_in, pdf_out): + png_out = tempfile.mktemp(suffix='.png') + try: + cmd = ['inkscape', '--export-type=png', f'--export-filename={png_out}', + f'--export-dpi={DEFAULT_DPI}', svg_in] + subprocess.check_call(cmd) + + cmd = ['convert', png_out, pdf_out] + subprocess.check_call(cmd) + finally: + if os.path.exists(png_out): + os.unlink(png_out) + + +def generate(request, out_dir): + """ Generate a sticker sheet. + + request: dict-like with the following fields: + sticker: mandatory. filename for the sticker + subs: mandatory. dict-like with key-value template subtitution fields + landscape: optional. defaults to False + + out_dir: you get it + """ + + # fill in sticker details + sticker_out = tempfile.mktemp(suffix='.svg') + + try: + with open(sticker_out, 'w') as stickout: + landscape = request.get('landscape', False) + makesticker(os.path.join(out_dir, request['sticker']), stickout, + request['subs'], landscape=landscape) + + # make sticker sheet + planche_out = tempfile.mktemp(suffix='.svg') + with open(sticker_out, 'r') as stickin: + with open(planche_out, 'w') as planchout: + makeplanche(stickin, planchout) + + # process to printable pdf + pdf_out = tempfile.mktemp(dir=out_dir, suffix='.pdf') + inkscapize(planche_out, pdf_out) + + return os.path.basename(pdf_out) + + finally: + if os.path.exists(sticker_out): + os.unlink(sticker_out) + if 'planche_out' in locals() and os.path.exists(planche_out): + os.unlink(planche_out) diff --git a/backend/zetikettes/tikette/makeplanche.py b/backend/zetikettes/tikette/makeplanche.py new file mode 100755 index 0000000..c0639d9 --- /dev/null +++ b/backend/zetikettes/tikette/makeplanche.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +import argparse +from pathlib import Path +from string import Template +import sys + +DEFAULT_SHEET_TEMPLATE = Path(__file__).parent / 'planche.svg.in' + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Make a sheet with 12 stickers') + parser.add_argument('--template', + '-t', + default=DEFAULT_SHEET_TEMPLATE, + help='path to the sheet template') + parser.add_argument('--out', + '-o', + default=sys.stdout, + type=argparse.FileType('w'), + help='output path (default: stdout)') + parser.add_argument('sticker', + type=argparse.FileType('r'), + default=sys.stdin, + nargs='?', + help='path to the sticker SVG (default: stdin)') + + return parser.parse_args() + + +def makeplanche(sticker, out, template=DEFAULT_SHEET_TEMPLATE): + with open(template) as tpl: + tpl_data = tpl.read() + + lines = sticker.readlines() + if lines[0].startswith('{}".format(sticker_data) + + out.write(Template(sticker_data).substitute(subs)) + + +if __name__ == "__main__": + args = vars(parse_args()) + subs = { + 'dluo': args.pop('dluo'), + 'lot': args.pop('lot'), + 'teneur': args.pop('teneur'), + 'fruit': args.pop('fruit'), + 'qty': args.pop('quantite'), + 'size': args.pop('size'), + } + args['subs'] = subs + makesticker(**args) diff --git a/backend/zetikettes/tikette/models.py b/backend/zetikettes/tikette/models.py index 71a8362..9d7af6a 100644 --- a/backend/zetikettes/tikette/models.py +++ b/backend/zetikettes/tikette/models.py @@ -1,3 +1,38 @@ 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): + name = models.CharField(max_length=50) + descritpion = models.TextField() + default = models.TextField() + + def __str__(self): + return self.name + + class Meta: + verbose_name_plural = "tisubz" + + +class Tikette(models.Model): + title = models.CharField(max_length=100) + category = models.ForeignKey(Tikategory, on_delete=models.CASCADE) + svg = models.FileField() + subs = models.ManyToManyField(Tisub) + + def __str__(self): + return self.title + + class Meta: + verbose_name_plural = "tikettz" + # Create your models here. diff --git a/backend/zetikettes/tikette/planche.svg.in b/backend/zetikettes/tikette/planche.svg.in new file mode 100644 index 0000000..7fa6d85 --- /dev/null +++ b/backend/zetikettes/tikette/planche.svg.in @@ -0,0 +1,24 @@ + + + + + $right0 + $right1 + $right2 + $right3 + $right4 + $right5 + + + $left0 + $left1 + $left2 + $left3 + $left4 + $left5 + + + diff --git a/backend/zetikettes/tikette/views.py b/backend/zetikettes/tikette/views.py index 91ea44a..210944e 100644 --- a/backend/zetikettes/tikette/views.py +++ b/backend/zetikettes/tikette/views.py @@ -1,3 +1,31 @@ -from django.shortcuts import render +import json -# Create your views here. +from django.conf import settings +from django.http import JsonResponse +from django.shortcuts import render +from django.views.decorators.csrf import csrf_exempt + +from . import generate as stickersheet +from .models import Tikette, Tikategory + +CORS={'access-control-allow-origin': '*'} + +def index(request): + tikettes = [{ + 'title': x.title, + 'category': x.category.name, + 'sticker': x.svg.name, + 'landscape': x.category.landscape, + 'subs': {x.name: x.default for x in x.subs.all()}, + } for x in Tikette.objects.all()] + return JsonResponse({'status': 'ok', 'tikettes': tikettes}, headers=CORS) + +@csrf_exempt +def generate(request): + if request.method != "POST": + return JsonResponse({'status': 'notok', 'message': 'this isn\'t the way'}) + + payload = json.loads(request.body) + pdfpath = stickersheet.generate(payload, out_dir=settings.TIKETTE_OUT_DIR) + + return JsonResponse({'status': 'ok', 'file': pdfpath}, headers=CORS) diff --git a/backend/zetikettes/zetikettes/settings.py b/backend/zetikettes/zetikettes/settings.py index 23c7e3e..12fee74 100644 --- a/backend/zetikettes/zetikettes/settings.py +++ b/backend/zetikettes/zetikettes/settings.py @@ -15,12 +15,16 @@ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent +#TIKETTE_OUT_DIR = BASE_DIR / 'data' +TIKETTE_OUT_DIR = Path('/data') +MEDIA_ROOT = TIKETTE_OUT_DIR +MEDIA_URL = 'data/' # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-a$!y$504(^om%yac)!!vb68arv*e*+r^t-4%y=d%8fda5x38=o' +SECRET_KEY = 'django-insecure-64qxpe55#9wy=5@#dl0)3w7ywxh48m!f&!slp9e7v4lh@hjdct' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -37,6 +41,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'tikette', ] MIDDLEWARE = [ diff --git a/backend/zetikettes/zetikettes/urls.py b/backend/zetikettes/zetikettes/urls.py index 562e83f..ef57f02 100644 --- a/backend/zetikettes/zetikettes/urls.py +++ b/backend/zetikettes/zetikettes/urls.py @@ -14,9 +14,16 @@ 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 import settings +from django.conf.urls.static import static from django.contrib import admin from django.urls import path +from django.views.generic.base import TemplateView + +import tikette.views urlpatterns = [ path('admin/', admin.site.urls), -] + path('list', tikette.views.index), + path('', tikette.views.generate), +] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)