diff options
Diffstat (limited to 'showcase')
-rw-r--r-- | showcase/__init__.py | 0 | ||||
-rw-r--r-- | showcase/admin.py | 3 | ||||
-rw-r--r-- | showcase/apps.py | 5 | ||||
-rw-r--r-- | showcase/migrations/0001_initial.py | 63 | ||||
-rw-r--r-- | showcase/migrations/__init__.py | 0 | ||||
-rw-r--r-- | showcase/models.py | 103 | ||||
-rw-r--r-- | showcase/templates/showcase/item-find.html | 12 | ||||
-rw-r--r-- | showcase/templates/showcase/show_case.html | 22 | ||||
-rw-r--r-- | showcase/tests.py | 3 | ||||
-rw-r--r-- | showcase/urls.py | 8 | ||||
-rw-r--r-- | showcase/views.py | 30 | ||||
-rw-r--r-- | showcase/wagtail_hooks.py | 33 |
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) |