Add last unread function

This commit is contained in:
Skia 2017-01-29 00:16:41 +01:00
parent 4cc57c183e
commit 254126fd79
14 changed files with 229 additions and 36 deletions

View File

@ -18,7 +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
from forum.models import Forum, ForumMessage, ForumTopic
class Command(BaseCommand):
@ -438,8 +438,10 @@ Welcome to the wiki page!
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()
hall = Forum(name="Hall de discussions", description="Pour toutes les discussions", parent=room)
hall.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()
ForumTopic(forum=hall)

View File

@ -426,6 +426,16 @@ class User(AbstractBaseUser):
def subscribed(self):
return self.is_in_group(settings.SITH_MAIN_MEMBERS_GROUP)
@property
def forum_infos(self):
try:
return self._forum_infos
except:
from forum.models import ForumUserInfo
infos = ForumUserInfo(user=self)
infos.save()
return infos
class AnonymousUser(AuthAnonymousUser):
def __init__(self, request):
super(AnonymousUser, self).__init__()

View File

@ -412,6 +412,9 @@ textarea {
margin: 2px;
background: skyblue;
}
.unread {
background: #e6ddad;
}
.message h5 {
font-size: 100%;
}

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
from django.utils.timezone import utc
import datetime
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('forum', '0003_forum_owner_club'),
]
operations = [
migrations.CreateModel(
name='ForumUserInfo',
fields=[
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
('last_read_date', models.DateTimeField(verbose_name='last read date', default=datetime.datetime(1999, 1, 1, 0, 0, tzinfo=utc))),
('user', models.OneToOneField(related_name='_forum_infos', to=settings.AUTH_USER_MODEL)),
],
),
]

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', '0004_forumuserinfo'),
]
operations = [
migrations.AddField(
model_name='forumuserinfo',
name='read_messages',
field=models.ManyToManyField(to='forum.ForumMessage', related_name='readers', verbose_name='read messages'),
),
]

View File

@ -0,0 +1,25 @@
# -*- 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),
('forum', '0005_forumuserinfo_read_messages'),
]
operations = [
migrations.RemoveField(
model_name='forumuserinfo',
name='read_messages',
),
migrations.AddField(
model_name='forummessage',
name='readers',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, related_name='read_messages', verbose_name='readers'),
),
]

View File

@ -7,6 +7,9 @@ from django.db import IntegrityError, transaction
from django.core.urlresolvers import reverse
from django.utils import timezone
from datetime import datetime
import pytz
from core.models import User, MetaGroup, Group, SithFile
from club.models import Club
@ -136,10 +139,14 @@ class ForumMessage(models.Model):
title = models.CharField(_("title"), default="", max_length=64, blank=True)
message = models.TextField(_("message"), default="")
date = models.DateTimeField(_('date'), default=timezone.now)
readers = models.ManyToManyField(User, related_name="read_messages", verbose_name=_("readers"))
class Meta:
ordering = ['id']
def __str__(self):
return "%s" % (self.title)
def is_owned_by(self, user):
return self.topic.is_owned_by(user) or user.id == self.author.id
@ -150,5 +157,14 @@ class ForumMessage(models.Model):
return user.can_view(self.topic)
def get_absolute_url(self):
return self.topic.get_absolute_url()
return self.topic.get_absolute_url() + "#first_unread"
def mark_as_read(self, user):
self.readers.add(user)
class ForumUserInfo(models.Model):
user = models.OneToOneField(User, related_name="_forum_infos")
last_read_date = models.DateTimeField(_('last read date'), default=datetime(year=settings.SITH_SCHOOL_START_YEAR,
month=1, day=1, tzinfo=pytz.UTC))
# read_messages = models.ManyToManyField(ForumMessage, related_name="readers", verbose_name=_("read messages"))

View File

@ -1,6 +1,9 @@
{% extends "core/base.jinja" %}
{% from 'forum/macros.jinja' import display_forum %}
{% from 'core/macros.jinja' import user_profile_link %}
{% from 'forum/macros.jinja' import display_forum, display_topic %}
{% block title %}
{{ forum }}
{% endblock %}
{% block content %}
<div>
@ -21,34 +24,7 @@
{{ display_forum(f, user) }}
{% endfor %}
{% for t in topics %}
<div class="topic">
<div class="ib w_medium">
<a class="ib w_big" href="{{ url('forum:view_topic', topic_id=t.id) }}">
<h5>{{ t.title }}</h5>
<p>{{ t.description }}</p>
</a>
{% if user.is_owner(t) %}
<div class="ib" style="text-align: center;">
<a href="{{ url('forum:edit_topic', topic_id=t.id) }}">Edit</a>
</div>
{% endif %}
</div>
<div class="ib w_medium">
<div class="ib w_medium">
<div class="ib w_medium" style="text-align: center;">
{{ user_profile_link(t.author) }}
</div>
<div class="ib w_medium" style="text-align: center;">
{{ t.messages.count() }}
</div>
</div>
<div class="ib w_medium" style="text-align: center;">
{% set last_msg = t.messages.order_by('id').last() %}
{{ user_profile_link(last_msg.author) }} <br/>
{{ last_msg.date|date(DATETIME_FORMAT) }} {{ last_msg.date|time(DATETIME_FORMAT) }}
</div>
</div>
</div>
{{ display_topic(t, user) }}
{% endfor %}
{% endblock %}

View File

@ -0,0 +1,24 @@
{% extends "core/base.jinja" %}
{% from 'forum/macros.jinja' import display_topic %}
{% block title %}
{% trans %}Last unread messages{% endtrans %}
{% endblock %}
{% block content %}
<p>
<a href="{{ url('forum:main') }}">Forum</a> >
</p>
<h3>{% trans %}Forum{% endtrans %}</h3>
<h4>{% trans %}Last unread messages{% endtrans %}</h4>
<p>
<a class="ib" href="{{ url('forum:mark_all_as_read') }}">{% trans %}Mark all as read{% endtrans %}</a>
<a class="ib" href="{{ url('forum:last_unread') }}">{% trans %}Refresh{% endtrans %}</a>
</p>
{% for t in forumtopic_list %}
{{ display_topic(t, user, True) }}
{% endfor %}
{% endblock %}

View File

@ -1,3 +1,5 @@
{% from 'core/macros.jinja' import user_profile_link %}
{% macro display_forum(forum, user) %}
<div class="forum {% if forum.is_category %}category{% endif %}">
<div class="ib w_big">
@ -35,4 +37,38 @@
</div>
{% endmacro %}
{% macro display_topic(topic, user, first_unread=False) %}
<div class="topic">
<div class="ib w_medium">
{% if first_unread %}
<a class="ib w_big" href="{{ url('forum:view_topic', topic_id=topic.id) }}#first_unread">
{% else %}
<a class="ib w_big" href="{{ url('forum:view_topic', topic_id=topic.id) }}">
{% endif %}
<h5>{{ topic.title }}</h5>
<p>{{ topic.description }}</p>
</a>
{% if user.is_owner(topic) %}
<div class="ib" style="text-align: center;">
<a href="{{ url('forum:edit_topic', topic_id=topic.id) }}">{% trans %}Edit{% endtrans %}</a>
</div>
{% endif %}
</div>
<div class="ib w_medium">
<div class="ib w_medium">
<div class="ib w_medium" style="text-align: center;">
{{ user_profile_link(topic.author) }}
</div>
<div class="ib w_medium" style="text-align: center;">
{{ topic.messages.count() }}
</div>
</div>
<div class="ib w_medium" style="text-align: center;">
{% set last_msg = topic.messages.order_by('id').last() %}
{{ user_profile_link(last_msg.author) }} <br/>
{{ last_msg.date|date(DATETIME_FORMAT) }} {{ last_msg.date|time(DATETIME_FORMAT) }}
</div>
</div>
</div>
{% endmacro %}

View File

@ -2,16 +2,25 @@
{% from 'core/macros.jinja' import user_profile_link %}
{% from 'forum/macros.jinja' import display_forum %}
{% block title %}
{% trans %}Forum{% endtrans %}
{% endblock %}
{% block content %}
<p>
<a href="{{ url('forum:main') }}">Forum</a> >
</p>
<h3>{% trans %}Forum{% endtrans %}</h3>
<p>
{% if user.is_in_group(settings.SITH_GROUP_FORUM_ADMIN_ID) or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
<a href="{{ url('forum:new_forum') }}">New forum</a>
{% endif %}
<a class="ib" href="{{ url('forum:last_unread') }}">{% trans %}View last unread messages{% endtrans %}</a>
<a class="ib" href="{{ url('forum:mark_all_as_read') }}">{% trans %}Mark all as read{% endtrans %}</a>
<a class="ib" href="{{ url('forum:main') }}">{% trans %}Refresh{% endtrans %}</a>
</p>
{% if user.is_in_group(settings.SITH_GROUP_FORUM_ADMIN_ID) or user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) %}
<p>
<a href="{{ url('forum:new_forum') }}">{% trans %}New forum{% endtrans %}</a>
</p>
{% endif %}
{% for f in forum_list %}
<div style="padding: 4px; margin: 4px">
{{ display_forum(f, user) }}

View File

@ -1,6 +1,10 @@
{% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import user_profile_link %}
{% block title %}
{{ topic }}
{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css" media="all">
@ -32,8 +36,16 @@
<h3>{{ topic.title }}</h3>
<p>{{ topic.description }}</p>
<p><a href="{{ url('forum:new_message', topic_id=topic.id) }}">Reply</a></p>
{% set unread = False %}
{% for m in topic.messages.all() %}
{% if m.id == first_unread_message_id %}
<div class="message unread" id="first_unread">
{% set unread = True %}
{% elif unread %}
<div class="message unread">
{% else %}
<div class="message">
{% endif %}
<div class="msg_author">
{% if m.author.profile_pict %}
<img src="{{ m.author.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}" id="picture" />
@ -64,6 +76,7 @@
</div>
</div>
</div>
{# m.mark_as_read(user) or "" #}
{% endfor %}
{% endblock %}

View File

@ -5,6 +5,8 @@ from forum.views import *
urlpatterns = [
url(r'^$', ForumMainView.as_view(), name='main'),
url(r'^new_forum$', ForumCreateView.as_view(), name='new_forum'),
url(r'^mark_all_as_read$', ForumMarkAllAsRead.as_view(), name='mark_all_as_read'),
url(r'^last_unread$', ForumLastUnread.as_view(), name='last_unread'),
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]+)/delete$', ForumDeleteView.as_view(), name='delete_forum'),

View File

@ -16,6 +16,29 @@ class ForumMainView(CanViewMixin, ListView):
queryset = Forum.objects.filter(parent=None)
template_name = "forum/main.jinja"
class ForumMarkAllAsRead(RedirectView):
permanent = False
url = reverse_lazy('forum:last_unread')
def get(self, request, *args, **kwargs):
try:
fi = request.user.forum_infos
fi.last_read_date = timezone.now()
fi.save()
except: pass
return super(ForumMarkAllAsRead, self).get(request, *args, **kwargs)
class ForumLastUnread(ListView):
model = ForumTopic
template_name = "forum/last_unread.jinja"
def get_queryset(self):
l = ForumMessage.objects.exclude(readers=self.request.user).filter(
date__gt=self.request.user.forum_infos.last_read_date).values_list('topic') # TODO try to do better
return self.model.objects.filter(id__in=l).annotate(models.Max('messages__date')).order_by('-messages__date__max')
# return self.model.objects.exclude(messages__readers=self.request.user).distinct().annotate(
# models.Max('messages__date')).order_by('-messages__date__max')
class ForumCreateView(CanCreateMixin, CreateView):
model = Forum
fields = ['name', 'parent', 'owner_club', 'is_category', 'edit_groups', 'view_groups']
@ -95,6 +118,15 @@ class ForumTopicDetailView(CanViewMixin, DetailView):
template_name = "forum/topic.jinja"
context_object_name = "topic"
def get_context_data(self, **kwargs):
kwargs = super(ForumTopicDetailView, self).get_context_data(**kwargs)
msg = self.object.messages.exclude(readers=self.request.user).order_by('id').first()
try:
kwargs['first_unread_message_id'] = msg.id
except:
kwargs['first_unread_message_id'] = -1
return kwargs
class ForumMessageEditView(CanEditMixin, UpdateView):
model = ForumMessage
fields = ['title', 'message']