Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better handling of deleted messages (Fixes #40) #45

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions django_messages/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.conf import settings
from appconf import AppConf

class MessagesAppConf(AppConf):
DELETED_MAX_AGE = 30

class Meta:
prefix = 'MESSAGES'
2 changes: 2 additions & 0 deletions django_messages/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ def create_notice_types(app, created_models, verbosity, **kwargs):
notification.create_notice_type("messages_replied", _("Message Replied"), _("you have replied to a message"), default=1)
notification.create_notice_type("messages_reply_received", _("Reply Received"), _("you have received a reply to a message"), default=2)
notification.create_notice_type("messages_deleted", _("Message Deleted"), _("you have deleted a message"), default=1)
notification.create_notice_type("messages_permanently_deleted", _("Message Permanently Deleted"), _("you have permanently deleted a message"), default=0)
notification.create_notice_type("messages_recovered", _("Message Recovered"), _("you have undeleted a message"), default=1)
notification.create_notice_type("empty_trash", _("Emptied Trash"), _("you have permanently deleted all messages in your trash bin"), default=0)

signals.post_syncdb.connect(create_notice_types, sender=notification)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone
from ...models import Message
from django_messages.conf import settings


class Command(BaseCommand):
args = '<minimum age in days (e.g. 30)>'
help = (
'Deletes messages that have been marked as deleted by both the sender '
'and recipient. You must provide the minimum age in days.'
'and recipient. Minimum age in days is pulled from settings or given as an argument.'
)

def handle(self, *args, **options):
if len(args) == 0:
raise CommandError('You must provide the minimum age in days.')
args = [settings.MESSAGES_DELETED_MAX_AGE]
elif len(args) > 1:
raise CommandError(
'This management command accepts only one argument.'
Expand Down
9 changes: 6 additions & 3 deletions django_messages/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import datetime
from django.conf import settings
from django.db import models
from django.db.models import signals
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django_messages.conf import settings

AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')

Expand Down Expand Up @@ -33,14 +35,15 @@ def outbox_for(self, user):
def trash_for(self, user):
"""
Returns all messages that were either received or sent by the given
user and are marked as deleted.
user and are marked as deleted since less than MESSAGES_DELETED_MAX_AGE days.
"""
the_date = timezone.now() - datetime.timedelta(days=settings.MESSAGES_DELETED_MAX_AGE)
return self.filter(
recipient=user,
recipient_deleted_at__isnull=False,
recipient_deleted_at__gt=the_date,
) | self.filter(
sender=user,
sender_deleted_at__isnull=False,
sender_deleted_at__gt=the_date,
)


Expand Down
5 changes: 3 additions & 2 deletions django_messages/templates/django_messages/trash.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{% block content %}
<h1>{% trans "Deleted Messages" %}</h1>
{% if message_list %}
<a href="{% url 'empty_trash' %}">{% trans "Empty trash" %}</a>
<table class="messages">
<thead>
<tr><th>{% trans "Sender" %}</th><th>{% trans "Subject" %}</th><th>{% trans "Date" %}</th><th>{% trans "Action" %}</th></tr>
Expand All @@ -17,7 +18,7 @@ <h1>{% trans "Deleted Messages" %}</h1>
{{ message.subject }}
</td>
<td>{{ message.sent_at|date:_("DATETIME_FORMAT") }}</td>
<td><a href="{% url 'messages_undelete' message.id %}">{% trans "undelete" %}</a></td>
<td><a href="{% url 'messages_undelete' message.id %}">{% trans "undelete" %}</a>, <a href="{% url 'messages_permanently_delete' message.id %}">{% trans "permanently delete" %}</a></td>
</tr>
{% endfor %}
</tbody>
Expand All @@ -26,5 +27,5 @@ <h1>{% trans "Deleted Messages" %}</h1>
<p>{% trans "No messages." %}</p>
{% endif %}
<br />
<p>{% trans "Deleted Messages are removed from the trash at unregular intervals, don't rely on this feature for long-time storage." %}</p>
<p>{% blocktrans with deleted_max_age=max_age %} Deleted Messages are removed from the trash after {{deleted_max_age}} days, don't rely on this feature for long-time storage.{% endblocktrans %}</p>
{% endblock %}
2 changes: 2 additions & 0 deletions django_messages/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
url(r'^reply/(?P<message_id>[\d]+)/$', reply, name='messages_reply'),
url(r'^view/(?P<message_id>[\d]+)/$', view, name='messages_detail'),
url(r'^delete/(?P<message_id>[\d]+)/$', delete, name='messages_delete'),
url(r'^permanently_delete/(?P<message_id>[\d]+)/$', permanently_delete, name='messages_permanently_delete'),
url(r'^undelete/(?P<message_id>[\d]+)/$', undelete, name='messages_undelete'),
url(r'^trash/$', trash, name='messages_trash'),
url(r'^empty_trash/$', empty_trash, name='messages_empty_trash'),
)
64 changes: 62 additions & 2 deletions django_messages/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
Expand All @@ -11,6 +12,7 @@
from django_messages.models import Message
from django_messages.forms import ComposeForm
from django_messages.utils import format_quote, get_user_model, get_username_field
from django_messages.conf import settings

User = get_user_model()

Expand Down Expand Up @@ -46,15 +48,15 @@ def outbox(request, template_name='django_messages/outbox.html'):
@login_required
def trash(request, template_name='django_messages/trash.html'):
"""
Displays a list of deleted messages.
Displays a list of deleted messages which are less than MESSAGES_DELETED_MAX_AGE days old.
Optional arguments:
``template_name``: name of the template to use
Hint: A Cron-Job could periodicly clean up old messages, which are deleted
by sender and recipient.
"""
message_list = Message.objects.trash_for(request.user)
return render_to_response(template_name, {
'message_list': message_list,
'message_list': message_list, 'max_age': settings.MESSAGES_DELETED_MAX_AGE
}, context_instance=RequestContext(request))

@login_required
Expand Down Expand Up @@ -189,6 +191,64 @@ def undelete(request, message_id, success_url=None):
return HttpResponseRedirect(success_url)
raise Http404

def permanently_delete_message(user, message):
"""
Function called to permanently delete a message
"""
permanently_deleted_date = timezone.now() - datetime.timedelta(days=settings.MESSAGES_DELETED_MAX_AGE)
deleted = False

if message.sender == user:
message.sender_deleted_at = permanently_deleted_date
deleted = True
if message.recipient == user:
message.recipient_deleted_at = permanently_deleted_date
deleted = True
if deleted:
message.save()
if message.sender_deleted_at and message.recipient_deleted_at:
if message.sender_deleted_at <= permanently_deleted_date and message.recipient_deleted_at <= permanently_deleted_date:
message.delete()
return deleted

@login_required
def permanently_delete(request, message_id, success_url=None):
"""
Marks a message as permanently deleted by sender or recipient.
This is done by marking deleted_at to more than MESSAGES_DELETED_MAX_AGE
days ago.
The message is permanently deleted if both users permanently deleted it or
if it was deleted more than MESSAGES_DELETED_MAX_AGE days ago.
"""
message = get_object_or_404(Message, id=message_id)
if success_url is None:
success_url = reverse('messages_inbox')
if 'next' in request.GET:
success_url = request.GET['next']
if permanently_delete_message(request.user, message):
messages.info(request, _(u"Message permanently deleted."))
if notification:
notification.send([user], "messages_permanently_deleted")
return HttpResponseRedirect(success_url)
raise Http404

@login_required
def empty_trash(request, success_url=None):
"""
Empties a user's trash.
"""
if success_url is None:
success_url = reverse('messages_inbox')
if 'next' in request.GET:
success_url = request.GET['next']
message_list = Message.objects.trash_for(request.user)
for message in message_list.all():
permanently_delete_message(request.user, message)
messages.info(request, _(u"Trash is now empty."))
if notification:
notification.send([user], "trash_empty")
return HttpResponseRedirect(success_url)

@login_required
def view(request, message_id, form_class=ComposeForm, quote_helper=format_quote,
subject_template=_(u"Re: %(subject)s"),
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
'locale/*/LC_MESSAGES/*',
]
},
install_requires=[
"django-appconf>=0.6",
],
classifiers=(
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
Expand Down