Add news system, still miss nices templates and moderation tools

This commit is contained in:
Skia 2016-12-23 03:02:46 +01:00
parent f79ffbee7d
commit 1ca6bf7c62
9 changed files with 372 additions and 5 deletions

View File

@ -3,6 +3,7 @@ from django.contrib import admin
from com.models import *
admin.site.register(Sith)
admin.site.register(News)

View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('club', '0005_auto_20161120_1149'),
('com', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='News',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
('title', models.CharField(max_length=64, verbose_name='title')),
('summary', models.TextField(verbose_name='summary')),
('content', models.TextField(verbose_name='content')),
('type', models.CharField(max_length=16, choices=[('NOTICE', 'Notice'), ('EVENT', 'Event'), ('WEEKLY', 'Weekly'), ('CALL', 'Call')], default='EVENT', verbose_name='type')),
('is_moderated', models.BooleanField(default=False, verbose_name='is moderated')),
('club', models.ForeignKey(to='club.Club', verbose_name='club', related_name='news')),
('moderator', models.ForeignKey(verbose_name='owner', to=settings.AUTH_USER_MODEL, related_name='moderated_news', null=True)),
('owner', models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='owner', related_name='owned_news')),
],
),
migrations.CreateModel(
name='NewsDate',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
('start_date', models.DateTimeField(null=True, blank=True, verbose_name='start_date')),
('end_date', models.DateTimeField(null=True, blank=True, verbose_name='end_date')),
('news', models.ForeignKey(to='com.News', verbose_name='news_date', related_name='dates')),
],
),
]

View File

@ -1,8 +1,13 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse_lazy, reverse
from django.conf import settings
from core.models import User
from club.models import Club
class Sith(models.Model):
"""A one instance class storing all the modifiable infos"""
alert_msg = models.TextField(_("alert message"), default="", blank=True)
info_msg = models.TextField(_("info message"), default="", blank=True)
index_page = models.TextField(_("index page"), default="", blank=True)
@ -13,3 +18,40 @@ class Sith(models.Model):
def __str__(self):
return "⛩ Sith ⛩"
NEWS_TYPES = [
('NOTICE', _('Notice')),
('EVENT', _('Event')),
('WEEKLY', _('Weekly')),
('CALL', _('Call')),
]
class News(models.Model):
"""The news class"""
title = models.CharField(_("title"), max_length=64)
summary = models.TextField(_("summary"))
content = models.TextField(_("content"))
type = models.CharField(_("type"), max_length=16, choices=NEWS_TYPES, default="EVENT")
club = models.ForeignKey(Club, related_name="news", verbose_name=_("club"))
owner = models.ForeignKey(User, related_name="owned_news", verbose_name=_("owner"))
is_moderated = models.BooleanField(_("is moderated"), default=False)
moderator = models.ForeignKey(User, related_name="moderated_news", verbose_name=_("owner"), null=True)
def get_absolute_url(self):
return reverse('com:news_detail', kwargs={'news_id': self.id})
def __str__(self):
return "%s: %s" % (self.type, self.title)
class NewsDate(models.Model):
"""
A date class, useful for weekly events, or for events that just have no date
This class allows more flexibilty managing the dates related to a news, particularly when this news is weekly, since
we don't have to make copies
"""
news = models.ForeignKey(News, related_name="dates", verbose_name=_("news_date"))
start_date = models.DateTimeField(_('start_date'), null=True, blank=True)
end_date = models.DateTimeField(_('end_date'), null=True, blank=True)
def __str__(self):
return "%s: %s - %s" % (self.news.title, self.start_date, self.end_date)

View File

@ -0,0 +1,25 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}News admin{% endtrans %}
{% endblock %}
{% block content %}
<h3>{% trans %}News{% endtrans %}</h3>
<ul>
{% for news in object_list %}
<li>
<p>{{ news.get_type_display() }} - {{ news.title }}:
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span> -
<a href="{{ url('com:news_edit', news_id=news.id) }}">{% trans %}Edit{% endtrans %}</a>
</p>
</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}News{% endtrans %} -
{{ object.title }}
{% endblock %}
{% block content %}
<h3>{% trans %}News{% endtrans %}</h3>
{{ object }}
{{ object.dates.all() }}
{% endblock %}

View File

@ -0,0 +1,59 @@
{% extends "core/base.jinja" %}
{% block title %}
{% if object %}
{% trans %}Edit news{% endtrans %}
{% else %}
{% trans %}Create news{% endtrans %}
{% endif %}
{% endblock %}
{% block content %}
{% if object %}
<h2>{% trans %}Edit news{% endtrans %}</h2>
{% else %}
<h2>{% trans %}Create news{% endtrans %}</h2>
{% endif %}
<form action="" method="post">
{% csrf_token %}
{{ form.non_field_errors() }}
{{ form.owner }}
<p>{{ form.type.errors }}<label for="{{ form.type.name }}">{{ form.type.label }}</label> {{ form.type }}</p>
<p class="date">{{ form.start_date.errors }}<label for="{{ form.start_date.name }}">{{ form.start_date.label }}</label> {{ form.start_date }}</p>
<p class="date">{{ form.end_date.errors }}<label for="{{ form.end_date.name }}">{{ form.end_date.label }}</label> {{ form.end_date }}</p>
<p class="until">{{ form.until.errors }}<label for="{{ form.until.name }}">{{ form.until.label }}</label> {{ form.until }}</p>
<p>{{ form.title.errors }}<label for="{{ form.title.name }}">{{ form.title.label }}</label> {{ form.title }}</p>
<p>{{ form.club.errors }}<label for="{{ form.club.name }}">{{ form.club.label }}</label> {{ form.club }}</p>
<p>{{ form.summary.errors }}<label for="{{ form.summary.name }}">{{ form.summary.label }}</label> {{ form.summary }}</p>
<p>{{ form.content.errors }}<label for="{{ form.content.name }}">{{ form.content.label }}</label> {{ form.content }}</p>
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form>
{% endblock %}
{% block script %}
{{ super() }}
<script>
$( function() {
var type = $('input[name=type]');
var dates = $('.date');
var until = $('.until');
function update_targets () {
type_checked = $('input[name=type]:checked');
if (type_checked.val() == "EVENT" || type_checked.val() == "CALL") {
dates.show();
until.hide();
} else if (type_checked.val() == "WEEKLY") {
dates.show();
until.show();
} else {
dates.hide();
until.hide();
}
}
update_targets();
type.change(update_targets);
} );
</script>
{% endblock %}

View File

@ -0,0 +1,86 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}News{% endtrans %}
{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css" media="all">
section {
padding: 5px;
}
section.news_call {
background: lightgrey;
}
section.news_event:nth-child(even) {
background: lightblue;
}
.date {
font-size: small;
color: grey;
}
</style>
{% endblock %}
{% block content %}
<h3>{% trans %}News{% endtrans %}</h3>
<hr>
<h4>Notice</h4>
{% for news in object_list.filter(type="NOTICE") %}
<section class="news_notice">
<h4>{{ news.title }}</h4>
<p>{{ news.summary }}</p>
</section>
{% endfor %}
<hr>
<h4>Calls</h4>
{% for news in object_list.filter(dates__start_date__lte=timezone.now(), dates__end_date__gte=timezone.now(), type="CALL") %}
<section class="news_call">
<h4>{{ news.title }}</h4>
<p class="date">
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
</p>
<p>{{ news.summary }}</p>
</section>
{% endfor %}
<hr>
<h4>Events</h4>
{% for news in object_list.filter(dates__end_date__gte=timezone.now(), type="EVENT") %}
<section class="news_event">
<h4>{{ news.title }}</h4>
<p class="date">
<span>{{ news.dates.first().start_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().start_date|localtime|time(DATETIME_FORMAT) }}</span> -
<span>{{ news.dates.first().end_date|localtime|date(DATETIME_FORMAT) }}
{{ news.dates.first().end_date|localtime|time(DATETIME_FORMAT) }}</span>
</p>
<p><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></p>
<p>{{ news.summary|markdown }}</p>
</section>
{% endfor %}
<hr>
<h4>Weekly</h4>
{% for news in object_list.filter(dates__end_date__gte=timezone.now(), type="WEEKLY").distinct() %}
<!-- buggy when more than one news, anyway, we won't use it this way -->
{% for d in news.dates.all() %}
<section class="news_weekly">
<h4>{{ news.title }}</h4>
<p class="date">
<span>{{ d.start_date|localtime|date(DATETIME_FORMAT) }}
{{ d.start_date|localtime|time(DATETIME_FORMAT) }}</span> -
<span>{{ d.end_date|localtime|date(DATETIME_FORMAT) }}
{{ d.end_date|localtime|time(DATETIME_FORMAT) }}</span>
</p>
<p><a href="{{ news.club.get_absolute_url() }}">{{ news.club }}</a></p>
<p>{{ news.summary|markdown }}</p>
</section>
{% endfor %}
{% endfor %}
{% endblock %}

View File

@ -3,8 +3,13 @@ from django.conf.urls import url, include
from com.views import *
urlpatterns = [
url(r'^edit/alert$', AlertMsgEditView.as_view(), name='alert_edit'),
url(r'^edit/info$', InfoMsgEditView.as_view(), name='info_edit'),
url(r'^edit/index$', IndexEditView.as_view(), name='index_edit'),
url(r'^sith/edit/alert$', AlertMsgEditView.as_view(), name='alert_edit'),
url(r'^sith/edit/info$', InfoMsgEditView.as_view(), name='info_edit'),
url(r'^sith/edit/index$', IndexEditView.as_view(), name='index_edit'),
url(r'^news$', NewsListView.as_view(), name='news_list'),
url(r'^news/admin$', NewsAdminListView.as_view(), name='news_admin_list'),
url(r'^news/create$', NewsCreateView.as_view(), name='news_new'),
url(r'^news/(?P<news_id>[0-9]+)/edit$', NewsEditView.as_view(), name='news_edit'),
url(r'^news/(?P<news_id>[0-9]+)$', NewsDetailView.as_view(), name='news_detail'),
]

View File

@ -1,12 +1,22 @@
from django.shortcuts import render
from django.views.generic.edit import UpdateView
from django.views.generic import ListView, DetailView, RedirectView
from django.views.generic.edit import UpdateView, CreateView
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse, reverse_lazy
from django.core.exceptions import ValidationError
from django.utils import timezone
from django import forms
from com.models import Sith
from datetime import timedelta
from com.models import Sith, News, NewsDate
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin
from core.views.forms import SelectDateTime
from club.models import Club
# Sith object
sith = Sith.objects.first
class ComTabsMixin(TabedViewMixin):
@ -53,3 +63,87 @@ class IndexEditView(ComEditView):
fields = ['index_page']
current_tab = "index"
success_url = reverse_lazy('com:index_edit')
# News
class NewsForm(forms.ModelForm):
class Meta:
model = News
fields = ['type', 'title', 'club', 'summary', 'content', 'owner']
widgets = {
'owner': forms.HiddenInput,
'type': forms.RadioSelect,
}
start_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Start date"), widget=SelectDateTime, required=False)
end_date = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("End date"), widget=SelectDateTime, required=False)
until = forms.DateTimeField(['%Y-%m-%d %H:%M:%S'], label=_("Until"), widget=SelectDateTime, required=False)
def clean(self):
self.cleaned_data = super(NewsForm, self).clean()
if self.cleaned_data['type'] != "NOTICE":
if not self.cleaned_data['start_date']:
self.add_error('start_date', ValidationError(_("This field is required.")))
if not self.cleaned_data['end_date']:
self.add_error('end_date', ValidationError(_("This field is required.")))
if self.cleaned_data['type'] == "WEEKLY" and not self.cleaned_data['until']:
self.add_error('until', ValidationError(_("This field is required.")))
return self.cleaned_data
def save(self):
ret = super(NewsForm, self).save()
self.instance.dates.all().delete()
if self.instance.type == "EVENT" or self.instance.type == "CALL":
NewsDate(start_date=self.cleaned_data['start_date'],
end_date=self.cleaned_data['end_date'],
news=self.instance).save()
elif self.instance.type == "WEEKLY":
start_date = self.cleaned_data['start_date']
end_date = self.cleaned_data['end_date']
while start_date <= self.cleaned_data['until']:
NewsDate(start_date=start_date,
end_date=end_date,
news=self.instance).save()
start_date += timedelta(days=7)
end_date += timedelta(days=7)
return ret
class NewsEditView(UpdateView):
model = News
form_class = NewsForm
template_name = 'com/news_edit.jinja'
pk_url_kwarg = 'news_id'
def get_initial(self):
init = {}
try:
init['start_date'] = self.object.dates.order_by('id').first().start_date.strftime('%Y-%m-%d %H:%M:%S')
except: pass
try:
init['end_date'] = self.object.dates.order_by('id').first().end_date.strftime('%Y-%m-%d %H:%M:%S')
except: pass
return init
class NewsCreateView(CreateView):
model = News
form_class = NewsForm
template_name = 'com/news_edit.jinja'
def get_initial(self):
init = {'owner': self.request.user}
try:
init['club'] = Club.objects.filter(id=self.request.GET['club']).first()
except: pass
return init
class NewsAdminListView(ListView):
model = News
template_name = 'com/news_admin_list.jinja'
class NewsListView(ListView):
model = News
template_name = 'com/news_list.jinja'
class NewsDetailView(DetailView):
model = News
template_name = 'com/news_detail.jinja'
pk_url_kwarg = 'news_id'