Add Forum

This commit is contained in:
Skia 2017-01-21 03:42:06 +01:00
parent fcaa740710
commit ea52462217
19 changed files with 449 additions and 1 deletions

View File

@ -18,6 +18,7 @@ from subscription.models import Subscription
from counter.models import Customer, ProductType, Product, Counter
from com.models import Sith, Weekmail
from election.models import Election, Role, Candidature, ElectionList
from forum.models import Forum, ForumMessage
class Command(BaseCommand):
@ -429,3 +430,13 @@ Welcome to the wiki page!
cand = Candidature(role=pres, user=sli, election_list=listeT, program="En fait j'aime pas l'info, je voulais faire GMC")
cand.save()
# Forum
room = Forum(name="Salon de discussions", description="Pour causer de tout", is_category=True)
room.save()
Forum(name="AE", description="Réservé au bureau AE", parent=room).save()
Forum(name="BdF", description="Réservé au bureau BdF", parent=room).save()
Forum(name="Hall de discussions", description="Pour toutes les discussions", parent=room).save()
various = Forum(name="Divers", description="Pour causer de rien", is_category=True)
various.save()
Forum(name="Promos", description="Réservé aux Promos", parent=various).save()

View File

@ -91,7 +91,7 @@
<a href="https://ae.utbm.fr/matmatronch/">{% trans %}Matmatronch{% endtrans %}</a>
<a href="{{ url('core:page', page_name="Index") }}">{% trans %}Wiki{% endtrans %}</a>
<a href="{{ url('sas:main') }}">{% trans %}SAS{% endtrans %}</a>
<a href="https://ae.utbm.fr/forum2/">{% trans %}Forum{% endtrans %}</a>
<a href="{{ url('forum:main') }}">{% trans %}Forum{% endtrans %}</a>
<a href="{{ url('core:page', "services") }}">{% trans %}Services{% endtrans %}</a>
<a href="{{ url('core:file_list') }}">{% trans %}Files{% endtrans %}</a>
<a href="https://ae.utbm.fr/article.php?name=liens">{% trans %}Sponsors{% endtrans %}</a>

0
forum/__init__.py Normal file
View File

3
forum/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,51 @@
# -*- 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),
('core', '0019_preferences_receive_weekmail'),
]
operations = [
migrations.CreateModel(
name='Forum',
fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
('name', models.CharField(verbose_name='name', max_length=64)),
('description', models.CharField(default='', verbose_name='description', max_length=256)),
('is_category', models.BooleanField(default=False, verbose_name='is a category')),
('edit_groups', models.ManyToManyField(to='core.Group', blank=True, related_name='editable_forums')),
('owner_group', models.ForeignKey(to='core.Group', default=4, related_name='owned_forums')),
('parent', models.ForeignKey(blank=True, null=True, to='forum.Forum', related_name='children')),
('view_groups', models.ManyToManyField(to='core.Group', blank=True, related_name='viewable_forums')),
],
),
migrations.CreateModel(
name='ForumMessage',
fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
('title', models.CharField(default='', blank=True, verbose_name='title', max_length=64)),
('message', models.TextField(verbose_name='message', default='')),
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='forum_messages')),
],
),
migrations.CreateModel(
name='ForumTopic',
fields=[
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
('author', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='forum_topics')),
('forum', models.ForeignKey(to='forum.Forum', related_name='topics')),
],
),
migrations.AddField(
model_name='forummessage',
name='topic',
field=models.ForeignKey(to='forum.ForumTopic', related_name='messages'),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('forum', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='forumtopic',
name='title',
field=models.CharField(verbose_name='title', max_length=64, default=''),
),
]

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('forum', '0002_forumtopic_title'),
]
operations = [
migrations.AlterModelOptions(
name='forumtopic',
options={'ordering': ['messages__date', '-id']},
),
migrations.AddField(
model_name='forummessage',
name='date',
field=models.DateTimeField(verbose_name='date', default=django.utils.timezone.now),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('forum', '0003_auto_20170121_0311'),
]
operations = [
migrations.AddField(
model_name='forumtopic',
name='description',
field=models.CharField(max_length=256, verbose_name='description', default=''),
),
]

View File

79
forum/models.py Normal file
View File

@ -0,0 +1,79 @@
from django.db import models
from django.core import validators
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from django.db import IntegrityError, transaction
from django.core.urlresolvers import reverse
from django.utils import timezone
from core.models import User, MetaGroup, Group, SithFile
class Forum(models.Model):
"""
The Forum class, made as a tree to allow nice tidy organization
"""
name = models.CharField(_('name'), max_length=64)
description = models.CharField(_('description'), max_length=256, default="")
is_category = models.BooleanField(_('is a category'), default=False)
parent = models.ForeignKey('Forum', related_name='children', null=True, blank=True)
owner_group = models.ForeignKey(Group, related_name="owned_forums",
default=settings.SITH_GROUP_COM_ADMIN_ID)
edit_groups = models.ManyToManyField(Group, related_name="editable_forums", blank=True)
view_groups = models.ManyToManyField(Group, related_name="viewable_forums", blank=True)
def check_loop(self):
"""Raise a validation error when a loop is found within the parent list"""
objs = []
cur = self
while cur.parent is not None:
if cur in objs:
raise ValidationError(_('You can not make loops in forums'))
objs.append(cur)
cur = cur.parent
def clean(self):
self.check_loop()
def __str__(self):
return "%s" % (self.name)
def get_absolute_url(self):
return reverse('forum:view_forum', kwargs={'forum_id': self.id})
def get_parent_list(self):
l = []
p = self.parent
while p is not None:
l.append(p)
p = p.parent
return l
class ForumTopic(models.Model):
forum = models.ForeignKey(Forum, related_name='topics')
author = models.ForeignKey(User, related_name='forum_topics')
title = models.CharField(_("title"), default="", max_length=64)
description = models.CharField(_('description'), max_length=256, default="")
class Meta:
ordering = ['-id']
def get_absolute_url(self):
return reverse('forum:view_topic', kwargs={'topic_id': self.id})
class ForumMessage(models.Model):
"""
"A ForumMessage object is a message in the forum" Cpt. Obvious
"""
topic = models.ForeignKey(ForumTopic, related_name='messages')
author = models.ForeignKey(User, related_name='forum_messages')
title = models.CharField(_("title"), default="", max_length=64, blank=True)
message = models.TextField(_("message"), default="")
date = models.DateTimeField(_('date'), default=timezone.now)
class Meta:
ordering = ['-id']
def get_absolute_url(self):
return self.topic.get_absolute_url()

View File

@ -0,0 +1,44 @@
{% extends "core/base.jinja" %}
{% from 'forum/macros.jinja' import display_forum %}
{% block head %}
{{ super() }}
<style type="text/css" media="all">
.topic {
border: solid skyblue 1px;
padding: 2px;
margin: 2px;
}
.forum {
background: lightblue;
padding: 2px;
margin: 2px;
}
.category {
background: skyblue;
}
</style>
{% endblock %}
{% block content %}
<p>{{ forum.get_parent_list() }}</p>
<h3>{{ forum.name }}</h3>
<a href="{{ url('forum:new_forum') }}?parent={{ forum.id }}">New forum</a>
{% for f in forum.children.all() %}
{{ display_forum(f) }}
{% endfor %}
{% for t in forum.topics.all() %}
<div class="topic">
<p>
<a href="{{ url('forum:view_topic', topic_id=t.id) }}">View</a>
<a href="{{ url('forum:edit_topic', topic_id=t.id) }}">Edit</a>
</p>
<h5>{{ t.title }}</h5>
<p>{{ t.description }}</p>
</div>
{% endfor %}
<a href="{{ url('forum:new_topic', forum_id=forum.id) }}">New topic</a>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% macro display_forum(forum) %}
<div class="forum {% if forum.is_category %}category{% endif %}">
<p>
{% if not forum.is_category %}
<a href="{{ url('forum:view_forum', forum_id=forum.id) }}">View</a>
{% endif %}
<a href="{{ url('forum:edit_forum', forum_id=forum.id) }}">Edit</a>
</p>
<h5>{{ forum.name }}</h5>
<p>{{ forum.description }}</p>
</div>
{% endmacro %}

View File

@ -0,0 +1,33 @@
{% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import user_profile_link %}
{% from 'forum/macros.jinja' import display_forum %}
{% block head %}
{{ super() }}
<style type="text/css" media="all">
.forum {
background: lightblue;
padding: 2px;
margin: 2px;
}
.category {
background: skyblue;
}
</style>
{% endblock %}
{% block content %}
<h3>{% trans %}Forum{% endtrans %}</h3>
<a href="{{ url('forum:new_forum') }}">New forum</a>
{% for f in forum_list %}
<div style="padding: 4px; margin: 4px">
{{ display_forum(f) }}
{% for c in f.children.all() %}
{{ display_forum(c) }}
{% endfor %}
</div>
{% endfor %}
{% endblock %}

View File

@ -0,0 +1,38 @@
{% extends "core/base.jinja" %}
{% block head %}
{{ super() }}
<style type="text/css" media="all">
.topic {
border: solid skyblue 1px;
padding: 2px;
margin: 2px;
}
.forum {
background: lightblue;
padding: 2px;
margin: 2px;
}
.category {
background: skyblue;
}
</style>
{% endblock %}
{% block content %}
<h3>{{ topic.title }}</h3>
<p>{{ topic.description }}</p>
<p><a href="{{ url('forum:new_message', topic_id=topic.id) }}">Reply</a></p>
{% for m in topic.messages.all() %}
<div>
<h5>{{ m.title }}</h5>
<p><strong>{{ m.author.get_display_name() }}</strong> - {{ m.date|date(DATETIME_FORMAT) }}
{{ m.date|time(DATETIME_FORMAT) }} -
<a href="{{ url('forum:new_message', topic_id=topic.id) }}?quote_id={{ m.id }}">Reply as quote</a></p>
<p>{{ m.message|markdown }}</p>
</div>
{% endfor %}
{% endblock %}

3
forum/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

16
forum/urls.py Normal file
View File

@ -0,0 +1,16 @@
from django.conf.urls import url, include
from forum.views import *
urlpatterns = [
url(r'^$', ForumMainView.as_view(), name='main'),
url(r'^new_forum$', ForumCreateView.as_view(), name='new_forum'),
url(r'^(?P<forum_id>[0-9]+)$', ForumDetailView.as_view(), name='view_forum'),
url(r'^(?P<forum_id>[0-9]+)/edit$', ForumEditView.as_view(), name='edit_forum'),
url(r'^(?P<forum_id>[0-9]+)/new_topic$', ForumTopicCreateView.as_view(), name='new_topic'),
url(r'^topic/(?P<topic_id>[0-9]+)$', ForumTopicDetailView.as_view(), name='view_topic'),
url(r'^topic/(?P<topic_id>[0-9]+)/edit$', ForumTopicEditView.as_view(), name='edit_topic'),
url(r'^topic/(?P<topic_id>[0-9]+)/new_message$', ForumMessageCreateView.as_view(), name='new_message'),
# url(r'^(?P<club_id>[0-9]+)/tools$', ClubToolsView.as_view(), name='tools'),
]

92
forum/views.py Normal file
View File

@ -0,0 +1,92 @@
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, RedirectView
from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils import timezone
from django.conf import settings
from django import forms
from django.core.exceptions import PermissionDenied
from forum.models import Forum, ForumMessage, ForumTopic
class ForumMainView(ListView):
queryset = Forum.objects.filter(parent=None)
template_name = "forum/main.jinja"
class ForumCreateView(CreateView):
model = Forum
fields = ['name', 'parent', 'is_category', 'owner_group', 'edit_groups', 'view_groups']
template_name = "core/create.jinja"
def get_initial(self):
init = super(ForumCreateView, self).get_initial()
parent = Forum.objects.filter(id=self.request.GET['parent']).first()
init['parent'] = parent
return init
class ForumEditView(UpdateView):
model = Forum
pk_url_kwarg = "forum_id"
fields = ['name', 'parent', 'is_category', 'owner_group', 'edit_groups', 'view_groups']
template_name = "core/edit.jinja"
success_url = reverse_lazy('forum:main')
class ForumDetailView(DetailView):
model = Forum
template_name = "forum/forum.jinja"
pk_url_kwarg = "forum_id"
class ForumTopicCreateView(CreateView):
model = ForumTopic
fields = ['title']
template_name = "core/create.jinja"
def dispatch(self, request, *args, **kwargs):
self.forum = get_object_or_404(Forum, id=self.kwargs['forum_id'], is_category=False)
if not request.user.can_view(self.forum):
raise PermissionDenied
return super(ForumTopicCreateView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
form.instance.forum = self.forum
form.instance.author = self.request.user
return super(ForumTopicCreateView, self).form_valid(form)
class ForumTopicEditView(UpdateView):
model = ForumTopic
fields = ['title']
pk_url_kwarg = "topic_id"
template_name = "core/edit.jinja"
class ForumTopicDetailView(DetailView):
model = ForumTopic
pk_url_kwarg = "topic_id"
template_name = "forum/topic.jinja"
context_object_name = "topic"
class ForumMessageCreateView(CreateView):
model = ForumMessage
fields = ['title', 'message']
template_name = "core/create.jinja"
def dispatch(self, request, *args, **kwargs):
self.topic = get_object_or_404(ForumTopic, id=self.kwargs['topic_id'])
if not request.user.can_view(self.topic):
raise PermissionDenied
return super(ForumMessageCreateView, self).dispatch(request, *args, **kwargs)
def get_initial(self):
init = super(ForumMessageCreateView, self).get_initial()
try:
init['message'] = "\n".join([
" > " + line for line in ForumMessage.objects.filter(id=self.request.GET['quote_id']).first().message.split('\n')
])
except: pass
return init
def form_valid(self, form):
form.instance.topic = self.topic
form.instance.author = self.request.user
return super(ForumMessageCreateView, self).form_valid(form)

View File

@ -59,6 +59,7 @@ INSTALLED_APPS = (
'sas',
'com',
'election',
'forum',
)
MIDDLEWARE_CLASSES = (

View File

@ -40,6 +40,7 @@ urlpatterns = [
url(r'^sas/', include('sas.urls', namespace="sas", app_name="sas")),
url(r'^api/v1/', include('api.urls', namespace="api", app_name="api")),
url(r'^election/', include('election.urls', namespace="election", app_name="election")),
url(r'^forum/', include('forum.urls', namespace="forum", app_name="forum")),
url(r'^admin/', include(admin.site.urls)),
url(r'^ajax_select/', include(ajax_select_urls)),
url(r'^i18n/', include('django.conf.urls.i18n')),