Skip to content

Commit

Permalink
Refactor templates and signatures
Browse files Browse the repository at this point in the history
Asking for templates/signatures json will now return the minimum
amount of information that the frontend needs to know about.
  • Loading branch information
MaxJohansen committed Jul 4, 2018
1 parent 41d9553 commit 6aa457e
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 124 deletions.
6 changes: 3 additions & 3 deletions diploma.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def create_diploma_image(template):
for name, field in template.fields.items():
draw_centered_full_size(context, base_template.size, field)

if template.signature is not None:
if template.signature and template.signature.value:
draw_scaled_signature(text, base_template.size, template.signature)

return Image.alpha_composite(base_template, text)
Expand Down Expand Up @@ -109,7 +109,7 @@ def create_signature_preview(signature, size):


def generate_diploma(template_name, **fields):
t = import_templates('templates/templates.json')[template_name]
t = import_templates()[template_name]

path = fields.pop('signature', None)
if path and t.signature is not None:
Expand All @@ -125,7 +125,7 @@ def generate_diploma(template_name, **fields):


def preview_template(template_name, size):
template = import_templates('templates/templates.json')[template_name]
template = import_templates()[template_name]
return create_template_preview(template, size)


Expand Down
20 changes: 13 additions & 7 deletions server.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from io import BytesIO
from flask import Flask, send_file, request
from json import dumps
from diploma import generate_diploma, UnknownFields, MissingFields, preview_template, preview_signature
from template import valid_template_names, BadSignature
from diploma import generate_diploma, UnknownFields, \
MissingFields, preview_template, preview_signature
from template import import_templates, BadSignature, \
frontend_templates_as_json, frontend_signatures_as_json
import os

app = Flask(__name__)


def get_size(width, height):
if not (width or height):
size = None
Expand All @@ -32,7 +35,12 @@ def serve_image(diploma_image):

@app.route('/<data>.json')
def serve_json_file(data):
return send_file(f"{data}/{data}.json")
if data == "templates":
return frontend_templates_as_json()
elif data == "signatures":
return frontend_signatures_as_json()

return my404('not found')


@app.route('/preview/<filename>')
Expand All @@ -43,9 +51,9 @@ def serve_preview_image(filename):

signature = f"signatures/{filename}.png"

if filename in valid_template_names():
if filename in import_templates():
return serve_image(preview_template(filename, size))
elif os.path.exists(signature):
if os.path.exists(signature):
return serve_image(preview_signature(signature, size))
else:
return my404('whoops')
Expand All @@ -54,8 +62,6 @@ def serve_preview_image(filename):
@app.route('/<template_name>')
def serve_diploma(template_name):
template_name = template_name.lower()
if template_name not in valid_template_names():
return my404('whoops')

kwargs = {k: ' '.join(v) for k, v in dict(request.args).items()}
finished_diploma = generate_diploma(template_name, **kwargs)
Expand Down
20 changes: 8 additions & 12 deletions signatures/signatures.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
[{
"name": "Gavin Belson",
"path": "gavinbelson.png",
"description": "Visionary behind 'The Box 3'"
"id": "gavinbelson",
"name": "Gavin Belson"
},
{
"name": "Walt Disney",
"path": "waltdisney.png",
"description": "Old-timey nazi sympathizer"
"id": "waltdisney",
"name": "Walt Disney"
},
{
"name": "Donald Trump",
"path": "donaldtrump.png",
"description": "Nazi sympathizer"
"id": "donaldtrump",
"name": "Donald Trump"
},
{
"name": "Harry Potter",
"path": "harrypotter.png",
"description": "The boy who lived"
"id": "harrypotter",
"name": "Harry Potter"
}]
134 changes: 95 additions & 39 deletions template.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
from json import loads
from json import loads, dumps
import os

TEMPLATE_FOLDER = 'templates'
TEMPLATE_FILE = 'templates.json'
SIGNATURE_FOLDER = 'signatures'
SIGNATURE_FILE = 'signatures.json'


class BadSignature(ValueError):
pass


class Field(object):
def __init__(self, name, color, x, y, w, h):
def __init__(self, color, x, y, w, h):
self.color = color
self.value = ""
self.x = x
self.y = y
self.w = w
self.h = h

@classmethod
def fromdict(cls, field_dict):
return cls(**field_dict)

def copy(self):
return self.__class__(None, self.color, self.x, self.y, self.w, self.h)


class Template(object):
def __init__(self, name, path, fields, signature=None, dirpath=''):
self.name = name
self.path = os.path.join(dirpath, path)
self.fields = {
field_dict['name'].lower(): Field.fromdict(field_dict)
for field_dict in fields
}
self._signature = Field.fromdict(signature) if signature else None
def __init__(self, path, fields, signature=None):
self.path = path
self.fields = create_fields(fields)
# This private instance variable will only have its
# 'value' attribute modified by the setter for signature
self._signature = Field(**signature) if signature else None

@property
def signature(self):
Expand All @@ -42,22 +41,19 @@ def signature(self):

@signature.setter
def signature(self, value):
if not value.endswith('.png'):
value += ".png"
if value and not os.path.exists(value):
new_value = 'signatures/' + value
if not os.path.exists(new_value):
raise BadSignature(f"{value} is not a valid signature")
else:
value = new_value
self._signature.value = value
path = os.path.join(SIGNATURE_FOLDER, f"{value}.png")
if not os.path.isfile(path):
raise BadSignature(f"{value} is not a valid signature")
self._signature.value = path

@property
def valid(self):
file_exists = os.path.exists(self.path)
if self.signature and self.signature.value:
# Check if signature is set to a valid signature file
signature_exists = os.path.exists(self.signature.value)
else:
# A blank signature is also fine
signature_exists = True
fields_valid = all(f.value for f in self.fields.values())
return file_exists and signature_exists and fields_valid
Expand All @@ -71,23 +67,83 @@ def copy(self):
signature = self.signature.copy if self.signature else None
return self.__class__(self.name, self.path, [f.copy() for f in self.fields], signature)

@classmethod
def from_dict(cls, template_dict, dirpath=''):
template_dict['dirpath'] = dirpath
return cls(**template_dict)


def import_templates(filename):
def load_json_from(filename):
"""Returns the dumped JSON metadata from filename"""
with open(filename) as infile:
dicts = loads(infile.read())

directory_name = os.path.dirname(filename)

return {template_dict['name'].lower(): Template.from_dict(template_dict, dirpath=directory_name)
for template_dict in dicts}


def valid_template_names():
return [k for k, v
in import_templates('templates/templates.json').items()
if os.path.exists(v.path)]
return dicts


def discard_nonexistant_templates(template_dicts):
"""Returns a new dictionary of template attributes, discarding
all templates that are not actually available on disk"""
return {
k: v for k, v
in template_dicts.items()
if os.path.isfile(os.path.join(TEMPLATE_FOLDER, v['path']))
}


def discard_nonexistant_signatures(signature_dicts):
"""Returns a new dictionary of signature attributes, discarding
all signatures that are not actually available on disk"""
return [
d for d in signature_dicts
if os.path.isfile(os.path.join(SIGNATURE_FOLDER, d['id'] + '.png'))
]


def create_fields(field_dicts):
"""Takes a list of dicts that have Field attributes and
returns a dictionary where they keys are names of fields
and the values are the fields themselves."""
return {k.lower(): Field(**v) for k, v in field_dicts.items()}


def create_clean_template(template_dict):
"""Takes a dictionary that has Template attributes
and removes all attributes that the frontend does not need.
Transforms the list of Field dicts into a list of their names."""
cleaned = template_dict.copy()
cleaned.pop('path', None)
signature = cleaned.pop('signature', False)
field_dicts = cleaned['fields']
cleaned['fields'] = list(field_dicts.keys())
cleaned['signature'] = bool(signature)
return cleaned


def frontend_templates_as_json():
"""Returns the frontend-friendly JSON version of all valid templates.
They look like this:
{
"template name" : {
"signature" : true,
"fields" : ["first field", "second field"]
}
}
"""
dicts = load_json_from(os.path.join(TEMPLATE_FOLDER, TEMPLATE_FILE))
valid = discard_nonexistant_templates(dicts)
return dumps({k: create_clean_template(v) for k, v in valid.items()})


def frontend_signatures_as_json():
"""Returns the frontend-friendly JSON for all valid signatures"""
dicts = load_json_from(os.path.join(SIGNATURE_FOLDER, SIGNATURE_FILE))
valid = discard_nonexistant_signatures(dicts)
return dumps(valid)


def import_templates():
"""Returns a dictionary where the keys are template names
and the values are the actual Template instances.
"""
dicts = load_json_from(os.path.join(TEMPLATE_FOLDER, TEMPLATE_FILE))
valid = discard_nonexistant_templates(dicts)

for d in valid.values():
d['path'] = os.path.join(TEMPLATE_FOLDER, d['path'])
return {k.lower(): Template(**v) for k, v in valid.items()}
Loading

0 comments on commit 6aa457e

Please sign in to comment.