From 5f16d1bf5419ec3f17f8762e3863d36962fc3633 2013-12-27 23:59:15 From: Branko Majic Date: 2013-12-27 23:59:15 Subject: [PATCH] DJPYD-1: Initial implementation of necessary views and URLs. --- diff --git a/django_pydenticon/settings.py b/django_pydenticon/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..7ca6a0287b632a1b3d92492948ee3709856513c0 --- /dev/null +++ b/django_pydenticon/settings.py @@ -0,0 +1,45 @@ +# Django imports +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured + +# Read project settings for Pydenticon, or fall-back to default values. +PYDENTICON_ROWS = getattr(settings, "PYDENTICON_ROWS", 5) +PYDENTICON_COLUMNS = getattr(settings, "PYDENTICON_COLUMNS", 5) +PYDENTICON_WIDTH = getattr(settings, "PYDENTICON_WIDTH", 200) +PYDENTICON_HEIGHT = getattr(settings, "PYDENTICON_HEIGHT", 200) +PYDENTICON_PADDING = getattr(settings, "PYDENTICON_PADDING", (20, 20, 20, 20)) +PYDENTICON_FORMAT = getattr(settings, "PYDENTICON_FORMAT", "png") +PYDENTICON_FOREGROUND = getattr(settings, "PYDENTICON_FOREGROUND", ( "rgb(45,79,255)", + "rgb(254,180,44)", + "rgb(226,121,234)", + "rgb(30,179,253)", + "rgb(232,77,65)", + "rgb(49,203,115)", + "rgb(141,69,170)" )) +PYDENTICON_BACKGROUND = getattr(settings, "PYDENTICON_BACKGROUND", "rgb(224,224,224)") + +# Validate the settings. +if not isinstance(PYDENTICON_ROWS, int) or PYDENTICON_ROWS <= 0: + raise ImproperlyConfigured("Setting PYDENTICON_ROWS must be a positive integer.") + +if not isinstance(PYDENTICON_COLUMNS, int) or PYDENTICON_COLUMNS <= 0: + raise ImproperlyConfigured("Setting PYDENTICON_COLUMNS must be a positive integer.") + +if not isinstance(PYDENTICON_WIDTH, int) or PYDENTICON_WIDTH <= 0: + raise ImproperlyConfigured("Setting PYDENTICON_WIDTH must be a positive integer.") + +if not isinstance(PYDENTICON_HEIGHT, int) or PYDENTICON_HEIGHT <= 0: + raise ImproperlyConfigured("Setting PYDENTICON_HEIGHT must be a positive integer.") + +if not all([isinstance(p, int) and p >= 0 for p in PYDENTICON_PADDING]) or len(PYDENTICON_PADDING) != 4: + raise ImproperlyConfigured("Setting PYDENTICON_PADDING must be a 4-tuple where each element is a non-negative integer.") + +if PYDENTICON_FORMAT not in ("png", "ascii"): + raise ImproperlyConfigured("Setting PYDENTICON_FORMAT must be set to one of: 'png', 'ascii'.") + +if not all([isinstance(f, str) for f in PYDENTICON_FOREGROUND]): + raise ImproperlyConfigured("Setting PYDENTICON_FOREGROUND must be a tuple where each element is string representation of colour.") + +if not isinstance(PYDENTICON_BACKGROUND, str): + raise ImproperlyConfigured("Setting PYDENTICON_BACKGROUND must be a string representation of colour") + diff --git a/django_pydenticon/urls.py b/django_pydenticon/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..5ed696623a6735933ed2f4ed0c55af7343a309b1 --- /dev/null +++ b/django_pydenticon/urls.py @@ -0,0 +1,12 @@ +# Django imports. +from django.conf.urls import patterns, url + +# Application imports. +from .views import image + +urlpatterns = patterns( + 'django_pydenticon.views', + + # View for rendering an identicon image. + url(r'^image/(?P.+)$', image, name="image") + ) diff --git a/django_pydenticon/views.py b/django_pydenticon/views.py index 91ea44a218fbd2f408430959283f0419c921093e..faa197d2b6c011165b2daef07cb97ce803a3e802 100644 --- a/django_pydenticon/views.py +++ b/django_pydenticon/views.py @@ -1,3 +1,72 @@ -from django.shortcuts import render +# Third-party Python library imports. +from pydenticon import Generator -# Create your views here. +# Django imports. +from django.core.exceptions import SuspiciousOperation +from django.http import HttpResponse +from django.http import HttpResponseBadRequest + +# Application imports. +from .settings import PYDENTICON_ROWS, PYDENTICON_COLUMNS, PYDENTICON_WIDTH, PYDENTICON_HEIGHT +from .settings import PYDENTICON_PADDING, PYDENTICON_FORMAT, PYDENTICON_FOREGROUND, PYDENTICON_BACKGROUND + +def image(request, data): + """ + Generates identicon image based on passed data. + + Arguments: + + data - Data which should be used for generating an identicon. This data + will be used in order to create a digest which is used for generating the + identicon. If the data passed is a hex digest already, the digest will be + used as-is. + + Returns: + + Identicon image in raw format. + """ + + # Get image width, height, padding, and format from GET parameters, or + # fall-back to default values from settings. + try: + width = int(request.GET.get("w", PYDENTICON_WIDTH)) + except ValueError: + raise SuspiciousOperation("Identicon width must be a positive integer.") + try: + height = int(request.GET.get("h", PYDENTICON_HEIGHT)) + except ValueError: + raise SuspiciousOperation("Identicon height must be a positive integer.") + output_format = request.GET.get("f", PYDENTICON_FORMAT) + try: + padding = [int(p) for p in request.GET["p"].split(",")] + except KeyError: + padding = PYDENTICON_PADDING + except ValueError: + raise SuspiciousOperation("Identicon padding must consist out of 4 positive integers separated with commas.") + + # Validate the input parameters. + if not isinstance(width, int) or width <= 0: + raise ImproperlyConfigured("Identicon width must be a positive integer.") + if not isinstance(height, int) or height <= 0: + raise SuspiciousOperation("Identicon height must be a positive integer.") + if not all([isinstance(p, int) and p >= 0 for p in padding]) or len(padding) != 4: + raise SuspiciousOperation("Padding must be a 4-element tuple consisting out of positive integers.") + + # Set-up correct content type based on requested identicon format. + if output_format == "png": + content_type = "image/png" + elif output_format == "ascii": + content_type = "text/plain" + else: + raise SuspiciousOperation("Unsupported identicon format requested - '%s' % output_format") + + # Initialise a generator. + generator = Generator(PYDENTICON_ROWS, PYDENTICON_COLUMNS) + + # Generate the identicion. + content = generator.generate(data, width, height, padding=padding, output_format=output_format) + + # Create and return the response. + response = HttpResponse(content, content_type=content_type) + + return response