Add an inline admin interface to the log module
This commit is contained in:
parent
fdf879a6b3
commit
28e0743b3c
9 changed files with 187 additions and 28 deletions
|
@ -1,5 +1,4 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Source, Entry
|
from .models import Source
|
||||||
|
|
||||||
admin.site.register(Source)
|
admin.site.register(Source)
|
||||||
admin.site.register(Entry)
|
|
||||||
|
|
14
logs/forms.py
Normal file
14
logs/forms.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.forms.widgets import DateInput
|
||||||
|
from django import forms
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class SearchForm(forms.Form):
|
||||||
|
source = forms.CharField(max_length=128)
|
||||||
|
date = forms.DateField(
|
||||||
|
label=_('date'),
|
||||||
|
initial=datetime.date.today(),
|
||||||
|
widget=DateInput(format='%d-%m-%Y'),
|
||||||
|
input_formats=['%d-%m-%Y'],
|
||||||
|
)
|
|
@ -2,7 +2,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: 1.0\n"
|
"Project-Id-Version: 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-01-27 18:32+0100\n"
|
"POT-Creation-Date: 2018-02-04 19:45+0100\n"
|
||||||
"PO-Revision-Date: 2018-01-27 18:35+0100\n"
|
"PO-Revision-Date: 2018-01-27 18:35+0100\n"
|
||||||
"Last-Translator: Khaganat <assoc@khaganat.net>\n"
|
"Last-Translator: Khaganat <assoc@khaganat.net>\n"
|
||||||
"Language-Team: Khaganat <assoc@khaganat.net>\n"
|
"Language-Team: Khaganat <assoc@khaganat.net>\n"
|
||||||
|
@ -12,7 +12,11 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: templates/logs/entries.html:10 templates/logs/entries.html:18
|
#: forms.py:10
|
||||||
|
msgid "date"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/entries.html:10 templates/logs/entries.html:21
|
||||||
msgid "logs_back"
|
msgid "logs_back"
|
||||||
msgstr "Back"
|
msgstr "Back"
|
||||||
|
|
||||||
|
@ -20,6 +24,28 @@ msgstr "Back"
|
||||||
msgid "logs_title"
|
msgid "logs_title"
|
||||||
msgstr "Khaganat's logs"
|
msgstr "Khaganat's logs"
|
||||||
|
|
||||||
#: templates/logs/index.html:33
|
#: templates/logs/index.html:32
|
||||||
|
msgid "go"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/index.html:36
|
||||||
|
#, python-format
|
||||||
|
msgid "%(name)s is hidden."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/index.html:37
|
||||||
|
msgid "show"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/index.html:39
|
||||||
|
#, python-format
|
||||||
|
msgid "%(name)s is published."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/index.html:40
|
||||||
|
msgid "hide"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/index.html:51
|
||||||
msgid "logs_no_logs_available"
|
msgid "logs_no_logs_available"
|
||||||
msgstr "No logs available."
|
msgstr "No logs available."
|
||||||
|
|
|
@ -2,7 +2,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: 1.0\n"
|
"Project-Id-Version: 1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-01-27 18:32+0100\n"
|
"POT-Creation-Date: 2018-02-04 19:45+0100\n"
|
||||||
"PO-Revision-Date: 2018-01-27 18:35+0100\n"
|
"PO-Revision-Date: 2018-01-27 18:35+0100\n"
|
||||||
"Last-Translator: Khaganat <assoc@khaganat.net>\n"
|
"Last-Translator: Khaganat <assoc@khaganat.net>\n"
|
||||||
"Language-Team: Khaganat <assoc@khaganat.net>\n"
|
"Language-Team: Khaganat <assoc@khaganat.net>\n"
|
||||||
|
@ -12,7 +12,11 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
#: templates/logs/entries.html:10 templates/logs/entries.html:18
|
#: forms.py:10
|
||||||
|
msgid "date"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/entries.html:10 templates/logs/entries.html:21
|
||||||
msgid "logs_back"
|
msgid "logs_back"
|
||||||
msgstr "Retour"
|
msgstr "Retour"
|
||||||
|
|
||||||
|
@ -20,6 +24,28 @@ msgstr "Retour"
|
||||||
msgid "logs_title"
|
msgid "logs_title"
|
||||||
msgstr "Journaux de conversation de Khaganat"
|
msgstr "Journaux de conversation de Khaganat"
|
||||||
|
|
||||||
#: templates/logs/index.html:33
|
#: templates/logs/index.html:32
|
||||||
|
msgid "go"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logs/index.html:36
|
||||||
|
#, python-format
|
||||||
|
msgid "%(name)s is hidden."
|
||||||
|
msgstr "%(name)s est masqué."
|
||||||
|
|
||||||
|
#: templates/logs/index.html:37
|
||||||
|
msgid "show"
|
||||||
|
msgstr "montrer"
|
||||||
|
|
||||||
|
#: templates/logs/index.html:39
|
||||||
|
#, python-format
|
||||||
|
msgid "%(name)s is published."
|
||||||
|
msgstr "%(name)s est publié."
|
||||||
|
|
||||||
|
#: templates/logs/index.html:40
|
||||||
|
msgid "hide"
|
||||||
|
msgstr "masquer"
|
||||||
|
|
||||||
|
#: templates/logs/index.html:51
|
||||||
msgid "logs_no_logs_available"
|
msgid "logs_no_logs_available"
|
||||||
msgstr "Aucun journal de conversation disponible."
|
msgstr "Aucun journal de conversation disponible."
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{% for entry in entries%}
|
{% for entry in entries%}
|
||||||
|
{% if request.user.is_staff %}
|
||||||
|
<a href="{% url 'log_switch_entry' entry.pk %}?next={{ request.path_info }}">{% if entry.hidden %}<span class="text-warning">⚠</span>{% else %}<span class="text-success">✓</span>{% endif %}</a>
|
||||||
|
{% endif %}
|
||||||
{{ entry.created|date:"H:i:s" }} {% if entry.nick %}<span class="log-nick"><{{ entry.nick }}></span> <span class="log-content">{{ entry.content }}</span>{% else %}<span class="log-action">* {{ entry.content }}</span>{% endif %}<br />
|
{{ entry.created|date:"H:i:s" }} {% if entry.nick %}<span class="log-nick"><{{ entry.nick }}></span> <span class="log-content">{{ entry.content }}</span>{% else %}<span class="log-action">* {{ entry.content }}</span>{% endif %}<br />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,6 +23,24 @@
|
||||||
{% for date in source.stats %}
|
{% for date in source.stats %}
|
||||||
<a href="{% url 'log_day' source=source.source__slug year=date.date.year month=date.date.month day=date.date.day %}" class="list-group-item list-group-item-action">{{ date.date }}</a>
|
<a href="{% url 'log_day' source=source.source__slug year=date.date.year month=date.date.month day=date.date.day %}" class="list-group-item list-group-item-action">{{ date.date }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if request.user.is_staff %}
|
||||||
|
<div class="list-group-item list-group-item-action">
|
||||||
|
<form method="post" action="{% url 'log_search' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.date }}
|
||||||
|
<input type="hidden" name="{{ form.source.name }}" value="{{ source.source__slug }}" />
|
||||||
|
<input type="submit" value="{% trans 'go'|capfirst %}" class="btn btn-secondary" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if source.source__hidden %}
|
||||||
|
{% blocktrans with name=source.source__name %}{{ name }} is hidden.{% endblocktrans %}
|
||||||
|
<a href="{% url 'log_switch_source' source.source__id %}" class="btn btn-warning">{% trans 'show'|capfirst %}</a>
|
||||||
|
{% else %}
|
||||||
|
{% blocktrans with name=source.source__name %}{{ name }} is published.{% endblocktrans %}
|
||||||
|
<a href="{% url 'log_switch_source' source.source__id %}" class="btn btn-warning">{% trans 'hide'|capfirst %}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
14
logs/urls.py
14
logs/urls.py
|
@ -6,6 +6,18 @@ urlpatterns = [
|
||||||
path('', views.IndexView.as_view(), name='log_index'),
|
path('', views.IndexView.as_view(), name='log_index'),
|
||||||
path(
|
path(
|
||||||
'<slug:source>/<int:year>/<int:month>/<int:day>/',
|
'<slug:source>/<int:year>/<int:month>/<int:day>/',
|
||||||
views.EntriesView.as_view(), name='log_day'
|
views.EntriesView.as_view(),
|
||||||
|
name='log_day'
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
'switch/source/<int:pk>/',
|
||||||
|
views.switch_source,
|
||||||
|
name='log_switch_source'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'switch/entry/<int:pk>/',
|
||||||
|
views.switch_entry,
|
||||||
|
name='log_switch_entry'
|
||||||
|
),
|
||||||
|
path('search/', views.search_view, name='log_search'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,29 +1,86 @@
|
||||||
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
|
from django.shortcuts import redirect, get_object_or_404
|
||||||
from django.db.models.functions import TruncDate
|
from django.db.models.functions import TruncDate
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.http import Http404
|
||||||
from .models import Source, Entry
|
from .models import Source, Entry
|
||||||
|
from .forms import SearchForm
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def _get_dates():
|
||||||
|
now = datetime.date.today()
|
||||||
|
start_date = now - datetime.timedelta(
|
||||||
|
days=settings.KHAGANAT_LOGS_MAX_DAYS
|
||||||
|
)
|
||||||
|
end_date = now - datetime.timedelta(
|
||||||
|
days=settings.KHAGANAT_LOGS_MIN_DAYS - 1
|
||||||
|
)
|
||||||
|
return (now, start_date, end_date)
|
||||||
|
|
||||||
|
|
||||||
|
def _switch_hidden(request, obj, pk):
|
||||||
|
e = get_object_or_404(obj, pk=pk)
|
||||||
|
e.hidden = not e.hidden
|
||||||
|
e.save()
|
||||||
|
|
||||||
|
next_page = request.GET.get('next', '')
|
||||||
|
if next_page == '':
|
||||||
|
next_page = reverse('log_index')
|
||||||
|
return redirect(next_page)
|
||||||
|
|
||||||
|
|
||||||
|
@staff_member_required
|
||||||
|
def switch_source(request, pk):
|
||||||
|
return _switch_hidden(request, Source, pk)
|
||||||
|
|
||||||
|
|
||||||
|
@staff_member_required
|
||||||
|
def switch_entry(request, pk):
|
||||||
|
return _switch_hidden(request, Entry, pk)
|
||||||
|
|
||||||
|
|
||||||
|
def search_view(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = SearchForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
date = form.cleaned_data['date']
|
||||||
|
return redirect(reverse('log_day', kwargs={
|
||||||
|
'source': form.cleaned_data['source'],
|
||||||
|
'year': date.year,
|
||||||
|
'month': date.month,
|
||||||
|
'day': date.day,
|
||||||
|
}))
|
||||||
|
raise Http404('No search parameters.')
|
||||||
|
|
||||||
|
|
||||||
class IndexView(generic.ListView):
|
class IndexView(generic.ListView):
|
||||||
template_name = 'logs/index.html'
|
template_name = 'logs/index.html'
|
||||||
context_object_name = 'sources'
|
context_object_name = 'sources'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['form'] = SearchForm()
|
||||||
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
now = datetime.date.today()
|
now, start_date, end_date = _get_dates()
|
||||||
start_date = now - datetime.timedelta(
|
|
||||||
days=settings.KHAGANAT_LOGS_MAX_DAYS
|
|
||||||
)
|
|
||||||
end_date = now - datetime.timedelta(
|
|
||||||
days=settings.KHAGANAT_LOGS_MIN_DAYS - 1
|
|
||||||
)
|
|
||||||
out = []
|
out = []
|
||||||
qs = Entry.objects.filter(
|
qs = Entry.objects.all()
|
||||||
hidden=False,
|
|
||||||
source__hidden=False,
|
if not self.request.user.is_staff:
|
||||||
created__range=(start_date, end_date)
|
qs = qs.filter(
|
||||||
).values('source', 'source__name', 'source__slug').annotate(
|
hidden=False,
|
||||||
|
source__hidden=False,
|
||||||
|
created__range=(start_date, end_date)
|
||||||
|
)
|
||||||
|
qs = qs.values(
|
||||||
|
'source', 'source__name', 'source__slug',
|
||||||
|
'source__id', 'source__hidden'
|
||||||
|
).annotate(
|
||||||
nb=Count('id')
|
nb=Count('id')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,6 +117,7 @@ class EntriesView(generic.ListView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
is_staff = self.request.user.is_staff
|
||||||
dt = datetime.date(
|
dt = datetime.date(
|
||||||
self.kwargs['year'],
|
self.kwargs['year'],
|
||||||
self.kwargs['month'],
|
self.kwargs['month'],
|
||||||
|
@ -70,15 +128,19 @@ class EntriesView(generic.ListView):
|
||||||
(now - dt).days > settings.KHAGANAT_LOGS_MAX_DAYS,
|
(now - dt).days > settings.KHAGANAT_LOGS_MAX_DAYS,
|
||||||
(now - dt).days < settings.KHAGANAT_LOGS_MIN_DAYS,
|
(now - dt).days < settings.KHAGANAT_LOGS_MIN_DAYS,
|
||||||
))
|
))
|
||||||
if out_of_bounds:
|
if out_of_bounds and not is_staff:
|
||||||
return Entry.objects.none()
|
return Entry.objects.none()
|
||||||
src = Source.objects.get(slug=self.kwargs['source'])
|
src = Source.objects.get(slug=self.kwargs['source'])
|
||||||
if src is None or src.hidden:
|
if src is None:
|
||||||
return Entry.objects.none()
|
return Entry.objects.none()
|
||||||
return Entry.objects.filter(
|
if src.hidden and not is_staff:
|
||||||
hidden=False,
|
return Entry.objects.none()
|
||||||
|
qs = Entry.objects.filter(
|
||||||
source=src,
|
source=src,
|
||||||
created__year=dt.year,
|
created__year=dt.year,
|
||||||
created__month=dt.month,
|
created__month=dt.month,
|
||||||
created__day=dt.day
|
created__day=dt.day
|
||||||
).order_by('created')
|
)
|
||||||
|
if not is_staff:
|
||||||
|
qs = qs.filter(hidden=False)
|
||||||
|
return qs.order_by('created')
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.contrib.auth.tokens import default_token_generator
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
@ -7,7 +7,6 @@ from django.core.mail import EmailMultiAlternatives
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
|
||||||
from .forms import RegistrationForm
|
from .forms import RegistrationForm
|
||||||
from .models import NelUser
|
from .models import NelUser
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue