Create Thabloid app

parent 27794969
......@@ -48,6 +48,13 @@ NodeJS dependencies
1. `lessc`:
* On Ubuntu or Debian, use: `apt-get install node-less node-mkdirp`
Thabloid dependencies
To be able to generate JPGs from PDFs, we need ghostscript:
apt-get install ghostscript
from django.contrib import admin
from .models import Thabloid
class ThabloidAdmin(admin.ModelAdmin):
list_filter = ('year', ), ThabloidAdmin)
from django.apps import AppConfig
class ThabloidConfig(AppConfig):
name = 'thabloid'
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-07 12:43
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import thabloid.models
import utils.validators
class Migration(migrations.Migration):
initial = True
dependencies = [
operations = [
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('year', models.IntegerField(validators=[django.core.validators.MinValueValidator(1990)])),
('issue', models.IntegerField()),
('file', models.FileField(upload_to=thabloid.models.thabloid_filename, validators=[utils.validators.validate_file_extension])),
unique_together=set([('year', 'issue')]),
from django.db import models
from django.conf import settings
from django.core.validators import MinValueValidator
from django.utils.text import slugify
from utils.validators import validate_file_extension
import os
import subprocess
import shutil
def thabloid_filename(instance, filename):
ext = os.path.splitext(filename)[1]
return os.path.join('public/thabloids/', slugify(instance) + ext)
class Thabloid(models.Model):
year = models.IntegerField(validators=[MinValueValidator(1990)])
issue = models.IntegerField()
file = models.FileField(
class Meta:
unique_together = ('year', 'issue',)
def __str__(self):
return 'Thabloid {}-{}, #{}'.format(self.year, self.year+1, self.issue)
def page_url(self, page=None):
if page is None:
page = '%03d.jpg'
page = '{:03}.jpg'.format(page)
dst, ext = os.path.splitext(
return os.path.join(os.path.dirname(dst), 'pages',
os.path.basename(dst), page)
def cover(self):
return self.page_url(1)
def pages(self):
pages = os.listdir(os.path.join(settings.MEDIA_ROOT,
return [self.page_url(i+1) for i in range(len(pages))]
def save(self, *args, **kwargs):
super(Thabloid, self).save(*args, **kwargs)
src = self.file.path
dst = os.path.join(settings.MEDIA_ROOT, self.page_url())
shutil.rmtree(os.path.dirname(dst)) # Clean up potential remainders
os.makedirs(os.path.dirname(dst), exist_ok=True)
# TODO reconsider if this resolution / quality is sufficient
subprocess.Popen(['gs', '-o', dst,
# '-g2100x2970', '-dPDFFitPage',
'-g1050x1485', '-dPDFFitPage',
'-sDEVICE=jpeg', '-f', src])
{% extends 'base.html' %}
{% load i18n thumbnail %}
{% block page_title %}{% trans "Thabloid" %}{% endblock %}
{% block body %}
<div class="portfolio portfolio-isotope">
<div class="portfolio-filter tabs-wrapper tabs-centered clearfix">
<ul class="tabs">
<li class="current"><a href="#">{% trans "All Thabloids" %}</a></li>
<li data-filter="{{ year|add:0 }}"><a href="#">{{ year|add:0 }}-{{ year|add:1 }}</a></li>
<li data-filter="{{ year|add:-1 }}"><a href="#">{{ year|add:-1 }}-{{ year|add:0 }}</a></li>
<li data-filter="{{ year|add:-2 }}"><a href="#">{{ year|add:-2 }}-{{ year|add:-1 }}</a></li>
<li data-filter="{{ year|add:-3 }}"><a href="#">{{ year|add:-3 }}-{{ year|add:-2 }}</a></li>
<li data-filter="older"><a href="#">{% trans "Older" %}</a></li>
<ul class="portfolio-posts row isotope" style="position: relative; overflow: hidden; height: 1195px;">
{% for thabloid in thabloids %}
<li data-filter="{% if thabloid.year < year|add:-3 %}older{% else %}{{ thabloid.year }}{% endif %}" class="post span3 has-overlay isotope-item" style="position: absolute; left: 0px; top: 0px;">
<div class="post-inner ">
<div class="post-header">
<img alt="{{ thabloid.year }}-{{ thabloid.year|add:1 }}, #{{ thabloid.issue }}" src="{% thumbnail thabloid.cover '220x310' %}">
<div class="post-overlay">
<div class="post-overlay-meta">
<h2>{{ thabloid.year }}-{{ thabloid.year|add:1 }}, #{{ thabloid.issue }}</h2>
<ul class="post-overlay-icons">
<li><span></span><a class="gallery-box overlay-icon-open" data-fancybox-type='iframe' href="{% url 'thabloid:viewer' thabloid.year thabloid.issue %}"></a></li>
<li><span></span><a class="overlay-icon-link" href="{{ thabloid.file.url }}" target="_blank"></a></li>
{% endfor %}
{% endblock %}
<!DOCTYPE html>
TODO: embed a viewer that displays the page files;
{% for page in thabloid.pages %}
<li>{{ MEDIA_URL }}{{ page }}</li>
{% endfor %}
\ No newline at end of file
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^viewer/(?P<year>[0-9]{4})/(?P<issue>[0-9]+)/$', views.viewer, name='viewer'),
from django.shortcuts import get_object_or_404, render
from django.db.models import Max
from .models import Thabloid
def index(request):
thabloids = Thabloid.objects.all()
context = {'thabloids': thabloids,
'year': thabloids.aggregate(Max('year')).get('year__max')}
return render(request, 'thabloid/index.html', context)
def viewer(request, year, issue):
thabloid = get_object_or_404(Thabloid, year=int(year), issue=int(issue))
return render(request, 'thabloid/viewer.html', {'thabloid': thabloid})
......@@ -11,7 +11,7 @@ main = [
{'title': _('Members'), 'name': '#'},
{'title': _('Sister Associations'), 'name': 'sister-associations'},
{'title': _('Become a Member'), 'name': 'become-a-member'},
{'title': _('Thabloid'), 'name': '#'},
{'title': _('Thabloid'), 'name': 'thabloid:index'},
{'title': _('For Members'), 'name': '#', 'authenticated': True,
'submenu': [
......@@ -51,6 +51,7 @@ INSTALLED_APPS = [
'django_template_check', # This is only necessary in development
......@@ -36,6 +36,7 @@ urlpatterns = [
url(r'^documents/', include('documents.urls', namespace='documents')),
url(r'^become-a-member/', members.views.become_a_member, name='become-a-member'),
url(r'^sister-associations', TemplateView.as_view(template_name='singlepages/sister_associations.html'), name='sister-associations'),
url(r'^thabloid/', include('thabloid.urls', namespace='thabloid')),
url(r'^for-members/', include([
url(r'^become-active', TemplateView.as_view(template_name='singlepages/become_active.html'), name='become-active'),
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment