Rename Matmat to Trombi

This commit is contained in:
Skia
2017-05-10 22:17:05 +02:00
parent dec1a2cdd7
commit f2b2ff533d
19 changed files with 158 additions and 206 deletions

24
trombi/__init__.py Normal file
View File

@ -0,0 +1,24 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

29
trombi/admin.py Normal file
View File

@ -0,0 +1,29 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.contrib import admin
from trombi.models import Trombi
admin.site.register(Trombi)

View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import django.utils.timezone
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('club', '0007_auto_20170324_0917'),
]
operations = [
migrations.CreateModel(
name='Trombi',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
('subscription_deadline', models.DateField(verbose_name='subscription deadline', default=django.utils.timezone.now, help_text='Before this date, users are allowed to subscribe to this Trombi. After this date, users subscribed will be allowed to comment on each other.')),
('comments_deadline', models.DateField(verbose_name='comments deadline', default=django.utils.timezone.now, help_text="After this date, users won't be able to make comments anymore")),
('max_chars', models.IntegerField(verbose_name='maximum characters', default=400, help_text='maximum number of characters allowed in a comment')),
('club', models.OneToOneField(to='club.Club', related_name='trombi')),
],
),
migrations.CreateModel(
name='TrombiComment',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
('content', models.TextField(verbose_name='content', default='')),
],
),
migrations.CreateModel(
name='TrombiUser',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
('trombi', models.ForeignKey(to='trombi.Trombi', related_name='users', verbose_name='trombi', null=True, blank=True, on_delete=django.db.models.deletion.SET_NULL)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='trombi_user', verbose_name='trombi user')),
],
),
migrations.AddField(
model_name='trombicomment',
name='author',
field=models.ForeignKey(to='trombi.TrombiUser', related_name='given_comments', verbose_name='author'),
),
migrations.AddField(
model_name='trombicomment',
name='target',
field=models.ForeignKey(to='trombi.TrombiUser', related_name='received_comments', verbose_name='target'),
),
]

View File

107
trombi/models.py Normal file
View File

@ -0,0 +1,107 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.conf import settings
from django.utils import timezone
from django.core.exceptions import ValidationError
from datetime import timedelta, date
from core.models import User
from club.models import Club
class TrombiManager(models.Manager):
def get_queryset(self):
return super(TrombiManager, self).get_queryset()
class AvailableTrombiManager(models.Manager):
def get_queryset(self):
return super(AvailableTrombiManager,
self).get_queryset().filter(subscription_deadline__gte=date.today())
class Trombi(models.Model):
"""
This is the main class, the Trombi itself.
It contains the deadlines for the users, and the link to the club that makes
its Trombi.
"""
subscription_deadline = models.DateField(_('subscription deadline'),
default=timezone.now, help_text=_("Before this date, users are "
"allowed to subscribe to this Trombi. "
"After this date, users subscribed will be allowed to comment on each other."))
comments_deadline = models.DateField(_('comments deadline'),
default=timezone.now, help_text=_("After this date, users won't be "
"able to make comments anymore"))
max_chars = models.IntegerField(_('maximum characters'), default=400,
help_text=_('maximum number of characters allowed in a comment'))
club = models.OneToOneField(Club, related_name='trombi')
objects = TrombiManager()
availables = AvailableTrombiManager()
def __str__(self):
return str(self.club.name)
def clean(self):
if self.subscription_deadline > self.comments_deadline:
raise ValidationError(_("Closing the subscriptions after the "
"comments is definitively not a good idea."))
def get_absolute_url(self):
return reverse('trombi:detail', kwargs={'trombi_id': self.id})
def is_owned_by(self, user):
return user.is_owner(self.club)
def can_be_edited_by(self, user):
return user.can_edit(self.club)
def can_be_viewed_by(self, user):
return user.id in [u.user.id for u in self.users.all()]
class TrombiUser(models.Model):
"""
This class is only here to avoid cross references between the core, club,
and trombi modules. It binds a User to a Trombi without needing to import
Trombi into the core.
"""
user = models.OneToOneField(User, verbose_name=_("trombi user"), related_name='trombi_user')
trombi = models.ForeignKey(Trombi, verbose_name=_("trombi"), related_name='users', blank=True, null=True, on_delete=models.SET_NULL)
class TrombiComment(models.Model):
"""
This represent a comment given by someone to someone else in the same Trombi
instance.
"""
author = models.ForeignKey(TrombiUser, verbose_name=_("author"), related_name='given_comments')
target = models.ForeignKey(TrombiUser, verbose_name=_("target"), related_name='received_comments')
content = models.TextField(_("content"), default="")
def can_be_viewed_by(self, user):
if user.id == self.target.user.id:
return False
return user.id == self.author.user.id or user.can_edit(self.author.trombi)

View File

@ -0,0 +1,19 @@
{% extends 'core/base.jinja' %}
{% block title %}
{% trans club=object.club %}{{ club }}'s Trombi{% endtrans %}
{% endblock %}
{% block content %}
<h2>{% trans club=object.club %}{{ club }}'s Trombi{% endtrans %}</h2>
<a href="{{ url('trombi:edit', trombi_id=object.id) }}">Edit</a>
<p>Subscription deadline: {{ object.subscription_deadline|date(DATETIME_FORMAT) }}</p>
<p>Comment deadline: {{ object.comments_deadline|date(DATETIME_FORMAT) }}</p>
<a href="#">Export</a>
<p>People:</p>
<ul>
{% for u in object.users.all() %}
<li>{{ u.user.get_display_name() }} - <a href="{{ url('trombi:delete_user', trombi_id=object.id, user_id=u.id) }}">Delete</a></li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans user_name=user.get_display_name() %}{{ user_name }}'s Trombi{% endtrans %}
{% endblock %}
{% block content %}
<h3>{% trans%}Trombi'{% endtrans %}</h3>
{% if subscribe_form %}
<form action="" method="post">
{% csrf_token %}
{{ subscribe_form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form>
{% else %}
<p>{% trans trombi = user.trombi_user.trombi %}You are subscribed to the Trombi {{ trombi }}{% endtrans %}</p>
<p><a href="{{ url("trombi:profile") }}">Edit my profile</a></p>
<hr>
<div>
{% for u in user.trombi_user.trombi.users.exclude(id=user.trombi_user.id) %}
<div class="ib">
<div>{{ u.user.get_display_name() }}</div>
{% set comment = u.received_comments.filter(author__id=user.trombi_user.id).first() %}
{% if comment %}
<a href="{{ url("trombi:edit_comment", comment_id=comment.id) }}">Edit comment</a>
{% else %}
<a href="{{ url("trombi:new_comment", user_id=u.id) }}">Comment</a>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% endblock %}

27
trombi/tests.py Normal file
View File

@ -0,0 +1,27 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.test import TestCase
# Create your tests here.

39
trombi/urls.py Normal file
View File

@ -0,0 +1,39 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.conf.urls import url, include
from trombi.views import *
urlpatterns = [
url(r'^(?P<club_id>[0-9]+)/new$', TrombiCreateView.as_view(), name='create'),
url(r'^(?P<trombi_id>[0-9]+)/edit$', TrombiEditView.as_view(), name='edit'),
url(r'^(?P<trombi_id>[0-9]+)/delete/(?P<user_id>[0-9]+)$', TrombiDeleteUserView.as_view(), name='delete_user'),
url(r'^(?P<trombi_id>[0-9]+)$', TrombiDetailView.as_view(), name='detail'),
url(r'^(?P<user_id>[0-9]+)/new_comment$', TrombiCommentCreateView.as_view(), name='new_comment'),
url(r'^comment/(?P<comment_id>[0-9]+)/edit$', TrombiCommentEditView.as_view(), name='edit_comment'),
url(r'^tools$', UserTrombiToolsView.as_view(), name='user_tools'),
url(r'^profile$', UserTrombiEditProfileView.as_view(), name='profile'),
]

170
trombi/views.py Normal file
View File

@ -0,0 +1,170 @@
# -*- coding:utf-8 -*
#
# Copyright 2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.shortcuts import render, get_object_or_404, redirect
from django.core.urlresolvers import reverse_lazy, reverse
from django.views.generic import ListView, DetailView, RedirectView, TemplateView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView, SingleObjectMixin
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.forms.models import modelform_factory
from trombi.models import Trombi, TrombiUser, TrombiComment
from core.views.forms import SelectFile, SelectDate
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, TabedViewMixin, CanCreateMixin, QuickNotifMixin
from core.models import User
from club.models import Club
class TrombiForm(forms.ModelForm):
class Meta:
model = Trombi
fields = ['subscription_deadline', 'comments_deadline', 'max_chars']
widgets = {
'subscription_deadline': SelectDate,
'comments_deadline': SelectDate,
}
class TrombiCreateView(CanEditPropMixin, CreateView):
"""
Create a trombi for a club
"""
model = Trombi
form_class = TrombiForm
template_name = 'core/create.jinja'
def post(self, request, *args, **kwargs):
"""
Affect club
"""
form = self.get_form()
if form.is_valid():
club = get_object_or_404(Club, id=self.kwargs['club_id'])
form.instance.club = club
ret = self.form_valid(form)
return ret
else:
return self.form_invalid(form)
class TrombiEditView(CanEditPropMixin, UpdateView):
model = Trombi
form_class = TrombiForm
template_name = 'core/edit.jinja'
pk_url_kwarg = 'trombi_id'
class TrombiDetailView(CanEditMixin, DetailView):
model = Trombi
template_name = 'trombi/detail.jinja'
pk_url_kwarg = 'trombi_id'
class TrombiDeleteUserView(CanEditPropMixin, SingleObjectMixin, RedirectView):
model = Trombi
pk_url_kwarg = 'trombi_id'
permanent = False
def get(self, request, *args, **kwargs):
self.object = self.get_object()
user = get_object_or_404(TrombiUser, id=self.kwargs['user_id'])
user.delete()
# See if we need to also delete the comments on the user, or if we keep them
return redirect(self.object.get_absolute_url())
# User side
class UserTrombiForm(forms.Form):
trombi = forms.ModelChoiceField(Trombi.availables.all(), required=False, label=_("Select trombi"),
help_text=_("This allows you to subscribe to a Trombi. "
"Be aware that you can subscribe only once, so don't play with that, "
"or you will expose yourself to the admins' wrath!"))
class UserTrombiToolsView(QuickNotifMixin, TemplateView):
"""
Display a user's trombi tools
"""
template_name = "trombi/user_tools.jinja"
def post(self, request, *args, **kwargs):
self.form = UserTrombiForm(request.POST)
if self.form.is_valid():
trombi_user = TrombiUser(user=request.user,
trombi=self.form.cleaned_data['trombi'])
trombi_user.save()
self.quick_notif_list += ['qn_success']
return super(UserTrombiToolsView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
kwargs = super(UserTrombiToolsView, self).get_context_data(**kwargs)
kwargs['user'] = self.request.user
if not hasattr(self.request.user, 'trombi_user'):
kwargs['subscribe_form'] = UserTrombiForm()
return kwargs
class UserTrombiEditProfileView(UpdateView):
model = User
form_class = modelform_factory(User,
fields=['second_email', 'phone', 'department', 'dpt_option',
'quote', 'parent_address'],
labels={
'second_email': _("Personal email (not UTBM)"),
'phone': _("Phone"),
'parent_address': _("Native town"),
})
template_name = "core/edit.jinja"
success_url = reverse_lazy('trombi:user_tools')
def get_object(self):
return self.request.user
class TrombiCommentFormView():
"""
Create/edit a trombi comment
"""
model = TrombiComment
fields = ['content']
def get_form_class(self):
self.trombi = self.request.user.trombi_user.trombi
return modelform_factory(self.model, fields=self.fields,
widgets={
'content': forms.widgets.Textarea(attrs={'maxlength': self.trombi.max_chars})
},
help_texts={
'content': _("Maximum characters: %(max_length)s") % {'max_length': self.trombi.max_chars}
})
def get_success_url(self):
return reverse('trombi:user_tools')
class TrombiCommentCreateView(TrombiCommentFormView, CreateView):
template_name = 'core/create.jinja'
def form_valid(self, form):
target = get_object_or_404(TrombiUser, id=self.kwargs['user_id'])
form.instance.author = self.request.user.trombi_user
form.instance.target = target
return super(TrombiCommentCreateView, self).form_valid(form)
class TrombiCommentEditView(TrombiCommentFormView, CanViewMixin, UpdateView):
pk_url_kwarg = "comment_id"
template_name = 'core/edit.jinja'