summaryrefslogtreecommitdiff
path: root/showcase
diff options
context:
space:
mode:
Diffstat (limited to 'showcase')
-rw-r--r--showcase/__init__.py0
-rw-r--r--showcase/admin.py3
-rw-r--r--showcase/apps.py5
-rw-r--r--showcase/migrations/0001_initial.py63
-rw-r--r--showcase/migrations/__init__.py0
-rw-r--r--showcase/models.py103
-rw-r--r--showcase/templates/showcase/item-find.html12
-rw-r--r--showcase/templates/showcase/show_case.html22
-rw-r--r--showcase/tests.py3
-rw-r--r--showcase/urls.py8
-rw-r--r--showcase/views.py30
-rw-r--r--showcase/wagtail_hooks.py33
12 files changed, 282 insertions, 0 deletions
diff --git a/showcase/__init__.py b/showcase/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/showcase/__init__.py
diff --git a/showcase/admin.py b/showcase/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/showcase/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/showcase/apps.py b/showcase/apps.py
new file mode 100644
index 0000000..d879f9b
--- /dev/null
+++ b/showcase/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class ShowcaseConfig(AppConfig):
+ name = 'showcase'
diff --git a/showcase/migrations/0001_initial.py b/showcase/migrations/0001_initial.py
new file mode 100644
index 0000000..0abb7d7
--- /dev/null
+++ b/showcase/migrations/0001_initial.py
@@ -0,0 +1,63 @@
+# Generated by Django 2.2.3 on 2019-07-16 17:41
+
+from django.db import migrations, models
+import django.db.models.deletion
+import wagtail.core.fields
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('wagtailcore', '0041_group_collection_permissions_verbose_name_plural'),
+ ('wagtailimages', '0001_squashed_0021'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ExternalSource',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200)),
+ ('error', models.TextField(blank=True, null=True)),
+ ('api_url', models.URLField()),
+ ('api_key', models.CharField(blank=True, max_length=500, null=True)),
+ ],
+ options={
+ 'verbose_name': 'External source',
+ 'verbose_name_plural': 'External sources',
+ },
+ ),
+ migrations.CreateModel(
+ name='ExternalSourceType',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200)),
+ ('slug', models.SlugField(max_length=200)),
+ ],
+ options={
+ 'verbose_name': 'External source type',
+ 'verbose_name_plural': 'External source types',
+ },
+ ),
+ migrations.CreateModel(
+ name='ShowCase',
+ fields=[
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
+ ('body', wagtail.core.fields.RichTextField(blank=True)),
+ ('external_source', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='showcase.ExternalSource')),
+ ('image', models.ForeignKey(blank=True, help_text='For top page: full width image. For child page: vignette.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.Image')),
+ ],
+ options={
+ 'verbose_name': 'Show case',
+ 'verbose_name_plural': 'Show cases',
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.AddField(
+ model_name='externalsource',
+ name='source_type',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='showcase.ExternalSourceType'),
+ ),
+ ]
diff --git a/showcase/migrations/__init__.py b/showcase/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/showcase/migrations/__init__.py
diff --git a/showcase/models.py b/showcase/models.py
new file mode 100644
index 0000000..ab04f93
--- /dev/null
+++ b/showcase/models.py
@@ -0,0 +1,103 @@
+import json
+import requests
+
+from django.conf import settings
+from django.core.cache import cache
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from wagtail.admin.edit_handlers import FieldPanel
+
+from home.models import BasePage
+
+
+class ExternalSourceType(models.Model):
+ name = models.CharField(max_length=200)
+ slug = models.SlugField(max_length=200)
+ panels = [
+ FieldPanel('name'),
+ FieldPanel('slug'),
+ ]
+
+ class Meta:
+ verbose_name = _("External source type")
+ verbose_name_plural = _("External source types")
+
+ def __str__(self):
+ return self.name
+
+
+class ExternalSource(models.Model):
+ name = models.CharField(max_length=200)
+ error = models.TextField(null=True, blank=True)
+ source_type = models.ForeignKey(ExternalSourceType,
+ on_delete=models.PROTECT)
+ api_url = models.URLField()
+ api_key = models.CharField(max_length=500, null=True, blank=True)
+ panels = [
+ FieldPanel('name'),
+ FieldPanel('source_type'),
+ FieldPanel('api_url'),
+ FieldPanel('api_key'),
+ ]
+
+ class Meta:
+ verbose_name = _("External source")
+ verbose_name_plural = _("External sources")
+
+ def __str__(self):
+ return self.name
+
+ def get_data(self):
+ key = "{}{}-data-{}".format(
+ settings.WAGTAIL_SITE_NAME, settings.WAGTAIL_EXTRA_SLUG,
+ self.pk
+ )
+ data = cache.get(key)
+ if data:
+ return data
+ data = []
+ headers = {}
+ base_error = str(_("Error while fetching the source:")) + " "
+ if self.api_key:
+ headers = {'Authorization': 'token {}'.format(self.api_key)}
+ try:
+ response = requests.get(self.api_url, headers=headers)
+ data = json.loads(response.text)
+ cache.set(key, data)
+ self.error = ""
+ except requests.exceptions.Timeout:
+ self.error = base_error + str(_("connection time out"))
+ except requests.exceptions.TooManyRedirects:
+ self.error = base_error + str(_("too many redirection"))
+ except requests.exceptions.RequestException as e:
+ self.error = base_error + str(_("unknown error")) + " - " + str(e)
+ self.save()
+ return data
+
+ @property
+ def data(self):
+ # TODO: cache
+ return self.get_data()
+
+ def get_item(self, item_number):
+ if item_number >= len(self.data):
+ return
+ return self.data[item_number]
+
+
+class ShowCase(BasePage):
+ external_source = models.ForeignKey(ExternalSource,
+ on_delete=models.PROTECT)
+ content_panels = [
+ FieldPanel('slug'), FieldPanel('external_source')
+ ] + BasePage.content_panels
+
+ class Meta:
+ verbose_name = _("Show case")
+ verbose_name_plural = _("Show cases")
+
+ @property
+ def data(self):
+ return self.external_source.get_data()
+
diff --git a/showcase/templates/showcase/item-find.html b/showcase/templates/showcase/item-find.html
new file mode 100644
index 0000000..3cd3b6f
--- /dev/null
+++ b/showcase/templates/showcase/item-find.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% load i18n static wagtailcore_tags wagtailimages_tags %}
+
+{% block body_class %}template-showcase{% endblock %}
+
+{% block content %}
+<main>
+ {{denomination}}
+ <img src="{{images.0.thumbnail}}">
+</main>
+
+{% endblock %}
diff --git a/showcase/templates/showcase/show_case.html b/showcase/templates/showcase/show_case.html
new file mode 100644
index 0000000..4940b43
--- /dev/null
+++ b/showcase/templates/showcase/show_case.html
@@ -0,0 +1,22 @@
+{% extends "base.html" %}
+{% load i18n static wagtailcore_tags wagtailimages_tags %}
+
+{% block body_class %}template-showcase{% endblock %}
+
+{% block content %}
+<main>
+ {% image page.image width-500 %}
+ {{ page.body|richtext }}
+ {% if page.data %}<ul>
+ {% for item in page.data %}
+ <li>
+ <a href="{% url 'display-item' page.slug forloop.counter0 %}">
+ {{item.denomination}}
+ <img src="{{item.images.0.thumbnail}}">
+ </a>
+ </li>
+ {% endfor %}
+ </ul>{% endif %}
+</main>
+
+{% endblock %}
diff --git a/showcase/tests.py b/showcase/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/showcase/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/showcase/urls.py b/showcase/urls.py
new file mode 100644
index 0000000..173d415
--- /dev/null
+++ b/showcase/urls.py
@@ -0,0 +1,8 @@
+from django.conf.urls import url
+
+from .views import display_item
+
+urlpatterns = [
+ url(r'^display-item/(?P<slug>[\w-]+)/(?P<number>\d+)/$',
+ display_item, name='display-item'),
+] \ No newline at end of file
diff --git a/showcase/views.py b/showcase/views.py
new file mode 100644
index 0000000..7134830
--- /dev/null
+++ b/showcase/views.py
@@ -0,0 +1,30 @@
+from django.http import Http404, HttpResponse
+from django.template import TemplateDoesNotExist
+from django.template.loader import get_template
+from django.utils.translation import ugettext_lazy as _
+
+from .models import ShowCase
+
+
+def display_item(request, slug, number):
+ q = ShowCase.objects.filter(slug=slug)
+ if not q.count():
+ return Http404(_("Unknown source."))
+ showcase = q.all()[0]
+ source = showcase.external_source
+ template_name = "showcase/item-{}.html".format(source.source_type.slug)
+ try:
+ template = get_template(template_name)
+ except TemplateDoesNotExist:
+ raise Http404(
+ str(_("Template {} is not defined. Ask your administrator to "
+ "define a template for this source type.")).format(
+ template_name))
+ data = source.get_item(int(number))
+ if not data:
+ raise Http404(
+ str(_("Data unavailable"))
+ )
+ data["showcase"] = slug
+ return HttpResponse(template.render(data, request))
+
diff --git a/showcase/wagtail_hooks.py b/showcase/wagtail_hooks.py
new file mode 100644
index 0000000..86690df
--- /dev/null
+++ b/showcase/wagtail_hooks.py
@@ -0,0 +1,33 @@
+from django.utils.translation import ugettext_lazy as _
+
+from wagtail.contrib.modeladmin.options import (
+ ModelAdmin, modeladmin_register)
+
+from .models import ExternalSource, ExternalSourceType
+
+
+class ExternalSourceTypeAdmin(ModelAdmin):
+ model = ExternalSourceType
+ menu_label = _("External source types")
+ menu_icon = 'cogs'
+ menu_order = 700
+ add_to_settings_menu = True
+ exclude_from_explorer = True
+ list_display = ('name', 'slug')
+
+
+modeladmin_register(ExternalSourceTypeAdmin)
+
+
+class ExternalSourceAdmin(ModelAdmin):
+ model = ExternalSource
+ menu_label = _("External sources")
+ menu_icon = 'site'
+ menu_order = 400
+ add_to_settings_menu = False
+ exclude_from_explorer = False
+ list_display = ('name', 'slug', 'source_type', 'error')
+ search_fields = ('name',)
+
+
+modeladmin_register(ExternalSourceAdmin)