This commit is contained in:
khashashin 2017-09-05 14:04:28 +02:00
commit d5c13742ce
17 changed files with 277 additions and 44 deletions

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from guess_language import guess_language
def parse(obj, raw, stream):
"""
@ -47,14 +48,18 @@ def parse(obj, raw, stream):
else:
obj.content = ''
# Detect language
obj.lang = guess_language(obj.content) or ''
# Collect tags
tags = []
for tag in obj.raw['tags']:
if 'label' in tag:
label = tag['label'].replace(',','-')
label = label.strip().lower()
if len(label) > 3 and not label in tags:
tags.append(label)
obj.tags = ','.join(tags)
if 'tags' in obj.raw:
for tag in obj.raw['tags']:
if 'label' in tag:
label = tag['label'].replace(',','-')
label = label.strip().lower()
if len(label) > 3 and not label in tags:
tags.append(label)
obj.tags = ','.join(tags)
return obj

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-04 20:33
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('feedler', '0002_feedpage'),
]
operations = [
migrations.AddField(
model_name='entry',
name='lang',
field=models.CharField(blank=True, default='', max_length=2),
),
]

View file

@ -61,5 +61,7 @@ def handle_save_settings(sender, instance, *args, **kwargs):
except Entry.DoesNotExist:
logger.info("Adding entry '%s'" % eid)
entry = Entry()
# Parse the Feedly object
entry = feedparser.parse(entry, raw_entry, stream)
# Persist resulting object
entry.save()

View file

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.utils import translation
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.wagtailcore.models import Page, Orderable
from wagtail.wagtailadmin.edit_handlers import FieldPanel
@ -13,6 +15,14 @@ class Stream(models.Model):
def __str__(self):
return self.title
LANGUAGE_CHOICES = (
('de', 'Deutsch'),
('fr', 'Français'),
('it', 'Italiano'),
('en', 'English'),
('', ' * * * '),
)
class Entry(models.Model):
"""Implementation of the Entry from the feedly API as generic Django model
"""
@ -25,7 +35,7 @@ class Entry(models.Model):
author = models.CharField(max_length=255, blank=True)
link = models.URLField()
visual = models.URLField(blank=True)
lang = models.CharField(max_length=2, blank=True, default='', choices=LANGUAGE_CHOICES)
content = models.TextField()
tags = models.TextField(blank=True)
@ -53,14 +63,28 @@ class FeedPage(Page):
entries = Entry.objects.filter(stream=self.stream)
else:
entries = Entry.objects.all()
# Filter out by chosen language
curlang = translation.get_language()
if curlang in ['de']:
entries = entries.exclude(lang='fr')
elif curlang in ['fr']:
entries = entries.exclude(lang='de')
# Order by most recent date first
entries = entries.order_by('-published')
return entries[:10]
return entries.order_by('-published')[:72]
def get_context(self, request):
# Update template context
context = super(FeedPage, self).get_context(request)
context['feedentries'] = self.feedentries
# Wrap with pagination
paginator = Paginator(self.feedentries, 9)
page = request.GET.get('page')
try:
feedentries = paginator.page(page)
except (PageNotAnInteger, EmptyPage):
feedentries = paginator.page(1)
context['feedentries'] = feedentries
return context
class Meta:

View file

@ -19,12 +19,32 @@
</div>
</section>
<!-- Page body -->
<section id="news" class="feedpage-body">
<div class="container">
<!-- Pagination -->
<center>
<ul class="pagination">
{% if feedentries.has_previous %}
<li><a href="?page={{ feedentries.previous_page_number }}" title="Previous">
<span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span></a></li>
{% endif %}
{% for page_num in feedentries.paginator.page_range %}
<li {% if page_num == feedentries.number %}class="active"{% endif %}>
<a href="?page={{ page_num }}">{{ page_num }}</a></li>
{% endfor %}
{% if feedentries.has_next %}
<li><a href="?page={{ feedentries.next_page_number }}" title="Next">
<span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span></a></li>
{% endif %}
</ul>
</center>
<div class="row">
{% for entry in feedentries %}
<div class="col-md-4 col-sm-6 col-xs-12">
<div class="col-md-4 col-sm-6 col-xs-12 news-entry">
{% if entry.visual %}
<div class="panel panel-default">
<img src="{{ entry.visual }}">
@ -34,14 +54,13 @@
<div class="panel-body">
<h3><span>{{ entry.title|striptags|truncatewords_html:10 }}</span></h3>
<p>
<em><small><span>{{ entry.author }}</span></small></em><br><br>
{{ entry.content|striptags|truncatewords_html:25 }}
{{ entry.content|striptags|truncatewords_html:25 }}
<em><span>{{ entry.author }}</span></em>
</p>
</div>
<a href="{{ entry.link }}" target="_blank" class="fill"></a>
</div>
</div>
<!-- {{ entry.raw }} -->
{% empty %}
<!-- No news today -->
{% endfor %}

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-04 20:33
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0019_auto_20170703_1244'),
]
operations = [
migrations.AlterField(
model_name='contactformfield',
name='field_type',
field=models.CharField(choices=[('singleline', 'Single line text'), ('multiline', 'Multi-line text'), ('email', 'Email'), ('number', 'Number'), ('url', 'URL'), ('checkbox', 'Checkbox'), ('checkboxes', 'Checkboxes'), ('dropdown', 'Drop down'), ('multiselect', 'Multiple select'), ('radio', 'Radio buttons'), ('date', 'Date'), ('datetime', 'Date/time')], max_length=16, verbose_name='field type'),
),
]

View file

@ -16,6 +16,8 @@ from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtailsearch import index
from puput.models import EntryPage, BlogPage
from feedler.models import Entry
from itertools import chain
from ..util import TranslatedField
@ -193,11 +195,6 @@ class HomePage(Page):
'infos_fr',
)
# news_home_de = models.ForeignKey(
# 'puput.EntryPage',
# null=True, blank=True, on_delete=models.SET_NULL,
# )
content_panels = Page.content_panels + [
MultiFieldPanel([
FieldPanel('intro_de', classname="full"),
@ -227,16 +224,29 @@ class HomePage(Page):
if not curlang in ['de', 'fr']: curlang = 'de' # Default language
parent = BlogPage.objects.filter(slug='news-%s' % curlang)
if not parent: return []
entries = EntryPage.objects.live().descendant_of(parent[0])
posts = EntryPage.objects.live().descendant_of(parent[0])
# Order by most recent date first
entries = entries.order_by('-date')
return entries[:6]
posts = posts.order_by('-date')
return posts[:3]
@property
def newsentries(self):
# Get the last few news entries
entries = Entry.objects.all().order_by('-published')
# Filter out by current language
curlang = translation.get_language()
if curlang in ['de']:
entries = entries.exclude(lang='fr')
elif curlang in ['fr']:
entries = entries.exclude(lang='de')
return entries[:3]
def get_context(self, request):
# Update template context
context = super(HomePage, self).get_context(request)
context['featured'] = self.featured
context['blogentries'] = self.blogentries
context['newsentries'] = self.newsentries
return context
parent_page_types = ['wagtailcore.Page']

View file

@ -13,6 +13,8 @@
<!-- Banner (articles) -->
{% include 'banner.html' %}
<div class="home_page">
<!-- News -->
{% include 'news.html' %}
@ -28,4 +30,6 @@
<!-- Infoblocks -->
{% include 'infos.html' %}
</div>
{% endblock %}

View file

@ -1,10 +1,12 @@
{% load wagtailcore_tags wagtailimages_tags puput_tags %}
<!-- Front page news -->
<section id="news">
<div class="container">
<div class="row">
{% for entry in blogentries %}
<div class="col-md-4 col-sm-6 col-xs-12">
<!-- Blog post {{ entry.id }} -->
<div class="col-md-4 col-sm-6 col-xs-12 blog-entry">
<div class="panel panel-default">
{% if entry.header_image %}
{% image entry.header_image fill-360x270 %}
@ -18,11 +20,35 @@
{{ entry.body|striptags|truncatewords_html:40 }}
{% endif %}
</p>
<a href="{% pageurl entry %}" class="btn btn-default btn-xs">Mehr erfahren</a>
<a href="{% pageurl entry %}" class="btn btn-default btn-xs"> 🡆 </a>
</div>
<a href="{% pageurl entry %}" class="fill"></a>
</div>
</div>
{% empty %}
<!-- No blogs today -->
{% endfor %}
<!-- <h4 class="partner-news"><a href="/aktuelles/">Partner news</a></h4> -->
{% for entry in newsentries %}
<!-- News entry {{ entry.id }} -->
<div class="col-md-4 col-sm-6 col-xs-12 news-entry">
{% if entry.visual %}
<div class="panel panel-default">
<img src="{{ entry.visual }}">
{% else %}
<div class="panel panel-fulltext">
{% endif %}
<div class="panel-body">
<h3><span>{{ entry.title|striptags|truncatewords_html:10 }}</span></h3>
<p>
{{ entry.content|striptags|truncatewords_html:25 }}
<em><span>{{ entry.author }}</span></em>
</p>
</div>
<a href="/aktuelles/" class="fill"></a>
<!-- <a href="{{ entry.link }}" target="_blank" class="fill"></a> -->
</div>
</div>
{% empty %}
<!-- No news today -->
{% endfor %}

View file

@ -127,10 +127,15 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
PASSWORD_REQUIRED_TEMPLATE = 'password.html'
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGES = (
('de', u'Deutsch'),
('fr', u'Français'),
)
LANGUAGE_CODE = 'de' # default language
TIME_ZONE = 'Europe/Zurich'

View file

@ -80,8 +80,11 @@
}
}
/* Home page banner background */
body.template-frontpage {
background: $gray-lighter;
.home_page section:nth-child(even) { background: white; }
}
/* Page header */
$banner-height: 700px;

View file

@ -46,6 +46,12 @@
margin: 10px 0 0 15px;
text-align: center;
}
em {
display: block;
font-size: 95%;
margin: 0.5em 0;
font-weight: 500;
}
}
// expand link over the thumbnail
@ -75,6 +81,29 @@
transform: rotateY(0);
}
}
.news-entry {
// height: 8em;
.panel {
background: none;
box-shadow: none;
border: none;
}
.panel-body {
// height: 50%;
background-color: #ffffff;
border-radius: 4px;
border-top: 3px solid $brand-primary;
// border: 2px solid rgba(38, 67, 169, 0.8);
*,a { color: black !important; }
}
}
.partner-news {
text-align: center;
margin-top: 2em;
margin-bottom: 1em;
}
}
// News detail article

View file

@ -18,11 +18,11 @@ $(document).ready(function() {
nextArrow: '<span class="arrow right glyphicon glyphicon-chevron-right" aria-hidden="true">Next</span>',
});
// Formatting of live news
$('.feedpage-body .panel').each(function() {
var hue = Math.floor(Math.random() * 360);
var pastel = 'hsl(' + hue + ', 100%, 87.5%)';
$(this).css('border-top', '3px solid ' + pastel);
});
// Pastel colors on live news
// $('.feedpage-body .panel').each(function() {
// var hue = Math.floor(Math.random() * 360);
// var pastel = 'hsl(' + hue + ', 100%, 87.5%)';
// $(this).css('border-top', '3px solid ' + pastel);
// });
});

View file

@ -1,11 +1,35 @@
{% extends "base.html" %}
{% block title %}404 - Page not found{% endblock %}
{% block title %}404 - Seite nicht gefunden{% endblock %}
{% block body_class %}template-404{% endblock %}
{% block content %}
<h1>Page not found</h1>
<section>
<div class="container">
<h2>Sorry, this page could not be found.</h2>
<h1>Nicht gefunden/Introuvable</h1>
<center>
<!-- Search form -->
<form action="/search/" method="get">
<input type="text" name="query" value="" id="search-form-404" class="form-control">
<button type="submit" title="Search">
<span class="glyphicon glyphicon-search" aria-hidden="false"></span>
</button>
</form>
<em><p>
<br>Diese Seite konnte nicht gefunden werden. Möchten Sie eine Suche starten?
<br>Désolé, cette page est introuvable. Voulez-vous faire une recherche sur le site?
<br>Sorry, this page could not be found. Would you like to do a search of the site?
</p></em>
</center>
</div>
</section>
<script>
document.getElementById('search-form-404').value = document.location.pathname.split('/')[2];
</script>
{% endblock %}

View file

@ -10,5 +10,7 @@
<h1>Internal server error</h1>
<h2>Sorry, there seems to be an error. Please try again soon.</h2>
<p>In case of persistent issues, write to <b>info@datalets.ch</b></p>
</body>
</html>

View file

@ -0,0 +1,39 @@
{% extends "base.html" %}
{% block title %}Password Required{% endblock %}
{% block body_class %}password-required{% endblock %}
{% block content %}
<section>
<div class="container">
<h1>Password requis/erforderlich</h1>
<center>
<form action="{{ action_url }}" method="POST">
{% csrf_token %}
{{ form.non_field_errors }}
<div>
{{ form.password.errors }}
{{ form.password }}
</div>
{% for field in form.hidden_fields %}
{{ field }}
{% endfor %}
<input type="submit" value="Continue/Fortfahren" />
</form>
<em><p>
<br>Sie benötigen ein Passwort, um auf diese Seite zuzugreifen.
<br>Vous avez besoin d'un mot de passe pour accéder à cette page.
<br>You need a password to access this page.
</p></em>
</center>
</div>
</section>
{% endblock %}

View file

@ -1,15 +1,16 @@
# Updated: 30.5.2017
# Updated: 4.9.2017
# Core
wagtail==1.11
Django==1.11.3
wagtail==1.12.1
Django==1.11.4
# Database
psycopg2==2.7.1
psycopg2==2.7.3.1
dj-database-url==0.4.2
# Addons
puput==0.8
# Content
puput==0.9
guess-language-spirit==0.5.3
# Search
elasticsearch>=2.0.0,<3.0.0
@ -20,7 +21,7 @@ django-redis==4.8.0
# Frontend
django-libsass==0.7
libsass==0.13.2
Pillow==4.2.0
Pillow==4.2.1
# Development tools
stellar==0.4.3
@ -29,4 +30,4 @@ stellar==0.4.3
gunicorn==19.7.1
whitenoise==3.3.0
ConcurrentLogHandler==0.9.1
django-anymail==0.10
django-anymail==0.11.1