diff --git a/README.md b/README.md index 8ab37aa..db22ad1 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,5 @@ You can set the following variables in the `.env` file: * `KHAGANAT_TIME_ZONE`: Time zone, default is `Europe/Paris`. * `KHAGANAT_STATIC_URL`: URL for static files, default is `/static/`. * `KHAGANAT_STATIC_ROOT`: Absolute path to the directory where static files should be collected. +* `KHAGANAT_LOGS_MIN_DAYS`: Numbers of days before logs are hidden, default is 7. +* `KHAGANAT_LOGS_MAX_DAYS`: Number of days before logs are published, default is 0. diff --git a/khaganat/settings.py b/khaganat/settings.py index d780236..c7d31b5 100644 --- a/khaganat/settings.py +++ b/khaganat/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ 'khaganat', 'pages.apps.PagesConfig', 'navbar.apps.NavbarConfig', + 'logs.apps.LogsConfig', ] MIDDLEWARE = [ @@ -131,3 +132,7 @@ USE_TZ = True STATIC_URL = os.getenv('KHAGANAT_STATIC_URL', default='/static/') STATIC_ROOT = os.getenv('KHAGANAT_STATIC_ROOT', default='') or None + +# Logs configuration +KHAGANAT_LOGS_MIN_DAYS = int(os.getenv('KHAGANAT_LOGS_MIN_DAYS', default='0')) +KHAGANAT_LOGS_MAX_DAYS = int(os.getenv('KHAGANAT_LOGS_MAX_DAYS', default='7')) diff --git a/khaganat/urls.py b/khaganat/urls.py index 15ae96d..9205bba 100644 --- a/khaganat/urls.py +++ b/khaganat/urls.py @@ -27,4 +27,5 @@ urlpatterns = [ urlpatterns += i18n_patterns( path('', index), path('page/', include('pages.urls')), + path('logs/', include('logs.urls')), ) diff --git a/logs/__init__.py b/logs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/logs/admin.py b/logs/admin.py new file mode 100644 index 0000000..19a3f73 --- /dev/null +++ b/logs/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from .models import Source,Entry + +admin.site.register(Source) +admin.site.register(Entry) diff --git a/logs/apps.py b/logs/apps.py new file mode 100644 index 0000000..7f3a755 --- /dev/null +++ b/logs/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class LogsConfig(AppConfig): + name = 'logs' diff --git a/logs/locale/en/LC_MESSAGES/django.po b/logs/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..f41c716 --- /dev/null +++ b/logs/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,25 @@ +msgid "" +msgstr "" +"Project-Id-Version: 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-27 18:32+0100\n" +"PO-Revision-Date: 2018-01-27 18:35+1\n" +"Last-Translator: Rodolphe Bréard \n" +"Language-Team: Khaganat \n" +"Language: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: templates/logs/entries.html:10 templates/logs/entries.html:18 +msgid "logs_back" +msgstr "Back" + +#: templates/logs/index.html:4 templates/logs/index.html:8 +msgid "logs_title" +msgstr "Khaganat's logs" + +#: templates/logs/index.html:33 +msgid "logs_no_logs_available" +msgstr "No logs available." diff --git a/logs/locale/fr/LC_MESSAGES/django.po b/logs/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..8ebd924 --- /dev/null +++ b/logs/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,25 @@ +msgid "" +msgstr "" +"Project-Id-Version: 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-27 18:32+0100\n" +"PO-Revision-Date: 2018-01-27 18:35+1\n" +"Last-Translator: Rodolphe Bréard \n" +"Language-Team: Khaganat \n" +"Language: Français\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: templates/logs/entries.html:10 templates/logs/entries.html:18 +msgid "logs_back" +msgstr "Retour" + +#: templates/logs/index.html:4 templates/logs/index.html:8 +msgid "logs_title" +msgstr "Journaux de conversation de Khaganat" + +#: templates/logs/index.html:33 +msgid "logs_no_logs_available" +msgstr "Aucun journal de conversation disponible." diff --git a/logs/migrations/0001_initial.py b/logs/migrations/0001_initial.py new file mode 100644 index 0000000..de938d9 --- /dev/null +++ b/logs/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 2.0.1 on 2018-01-27 13:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Entry', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('hidden', models.BooleanField(default=False)), + ('created', models.DateTimeField()), + ('nick', models.CharField(max_length=128)), + ('content', models.CharField(max_length=2048)), + ], + ), + migrations.CreateModel( + name='Source', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=128)), + ('hidden', models.BooleanField(default=False)), + ], + ), + migrations.AddField( + model_name='entry', + name='source', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='logs.Source'), + ), + ] diff --git a/logs/migrations/0002_source_slug.py b/logs/migrations/0002_source_slug.py new file mode 100644 index 0000000..ad326a3 --- /dev/null +++ b/logs/migrations/0002_source_slug.py @@ -0,0 +1,19 @@ +# Generated by Django 2.0.1 on 2018-01-27 15:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('logs', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='source', + name='slug', + field=models.CharField(default='', max_length=128), + preserve_default=False, + ), + ] diff --git a/logs/migrations/0003_auto_20180127_1700.py b/logs/migrations/0003_auto_20180127_1700.py new file mode 100644 index 0000000..1d0685b --- /dev/null +++ b/logs/migrations/0003_auto_20180127_1700.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.1 on 2018-01-27 16:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('logs', '0002_source_slug'), + ] + + operations = [ + migrations.AlterField( + model_name='source', + name='slug', + field=models.CharField(max_length=128, unique=True), + ), + ] diff --git a/logs/migrations/__init__.py b/logs/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/logs/models.py b/logs/models.py new file mode 100644 index 0000000..c83b978 --- /dev/null +++ b/logs/models.py @@ -0,0 +1,17 @@ +from django.db import models + +class Source(models.Model): + name = models.CharField(max_length=128) + slug = models.CharField(max_length=128, unique=True) + hidden = models.BooleanField(default=False) + + def __str__(self): + return self.name + + +class Entry(models.Model): + source = models.ForeignKey(Source, on_delete=models.CASCADE) + hidden = models.BooleanField(default=False) + created = models.DateTimeField() + nick = models.CharField(max_length=128) + content = models.CharField(max_length=2048) diff --git a/logs/templates/logs/entries.html b/logs/templates/logs/entries.html new file mode 100644 index 0000000..7855302 --- /dev/null +++ b/logs/templates/logs/entries.html @@ -0,0 +1,21 @@ +{% extends "khaganat/base.html" %} +{% load i18n %} + +{% block title %}{{ source_channel.name }}{% endblock %} + +{% block content %} +
+

{{ source_channel.name }} ({{ date }})

+ +
+ {% for entry in entries%} + {{ entry.created|date:"H:i:s" }} <{{ entry.nick }}> {{ entry.content }}
+ {% endfor %} +
+ +
+{% endblock %} diff --git a/logs/templates/logs/index.html b/logs/templates/logs/index.html new file mode 100644 index 0000000..d272362 --- /dev/null +++ b/logs/templates/logs/index.html @@ -0,0 +1,36 @@ +{% extends "khaganat/base.html" %} +{% load i18n %} + +{% block title %}{% trans "logs_title" %}{% endblock %} + +{% block content %} +
+

{% trans "logs_title" %}

+ {% if sources %} +
+
+
+ {% for source in sources %} + {{ source.source__name }} + {% endfor %} +
+
+
+ +
+
+ {% else %} +

{% trans "logs_no_logs_available" %}

+ {% endif %} +
+{% endblock %} diff --git a/logs/tests.py b/logs/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/logs/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/logs/urls.py b/logs/urls.py new file mode 100644 index 0000000..5a8c81e --- /dev/null +++ b/logs/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + + +urlpatterns = [ + path('', views.IndexView.as_view(), name='log_index'), + path('////', views.EntriesView.as_view(), name='log_day'), +] diff --git a/logs/views.py b/logs/views.py new file mode 100644 index 0000000..fd40014 --- /dev/null +++ b/logs/views.py @@ -0,0 +1,44 @@ +from django.db.models.functions import TruncDate +from django.db.models import Count +from django.views import generic +from django.conf import settings +from .models import Source,Entry +import datetime + +class IndexView(generic.ListView): + template_name = 'logs/index.html' + context_object_name = 'sources' + + def get_queryset(self): + now = datetime.date.today() + begin_date = now - datetime.timedelta(days=settings.KHAGANAT_LOGS_MAX_DAYS) + end_date = now - datetime.timedelta(days=settings.KHAGANAT_LOGS_MIN_DAYS - 1) + out = [] + for src in Entry.objects.filter(hidden=False, source__hidden=False, created__range=(begin_date, end_date)).values('source', 'source__name', 'source__slug').annotate(nb=Count('id')): + src['stats'] = Entry.objects.filter(hidden=False, source=src['source'], created__range=(begin_date, end_date)).annotate(date=TruncDate('created')).values('date').annotate(nb=Count('date')).order_by('-date') + out.append(src) + return out + + +class EntriesView(generic.ListView): + context_object_name = 'entries' + template_name = 'logs/entries.html' + allow_empty = False + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['date'] = datetime.date(self.kwargs['year'], self.kwargs['month'], self.kwargs['day']) + context['source_channel'] = Source.objects.get(slug=self.kwargs['source']), + if isinstance(context['source_channel'], tuple): + context['source_channel'] = context['source_channel'][0] + return context + + def get_queryset(self): + dt = datetime.date(self.kwargs['year'], self.kwargs['month'], self.kwargs['day']) + now = datetime.date.today() + if (now - dt).days > settings.KHAGANAT_LOGS_MAX_DAYS or (now - dt).days < settings.KHAGANAT_LOGS_MIN_DAYS: + return Entry.objects.none() + src = Source.objects.get(slug=self.kwargs['source']) + if src is None or src.hidden: + return Entry.objects.none() + return Entry.objects.filter(hidden=False, source=src, created__year=dt.year, created__month=dt.month, created__day=dt.day).order_by('created')