diff options
-rw-r--r-- | askbot/media/js/group_messaging.js | 53 | ||||
-rw-r--r-- | askbot/templates/group_messaging/senders_list.html | 7 | ||||
-rw-r--r-- | askbot/templates/group_messaging/threads_list.html | 5 | ||||
-rw-r--r-- | askbot/templates/user_inbox/messages.html | 11 | ||||
-rw-r--r-- | group_messaging/models.py | 22 | ||||
-rw-r--r-- | group_messaging/urls.py | 5 | ||||
-rw-r--r-- | group_messaging/views.py | 57 |
7 files changed, 130 insertions, 30 deletions
diff --git a/askbot/media/js/group_messaging.js b/askbot/media/js/group_messaging.js index 2ab677ff..04d5086c 100644 --- a/askbot/media/js/group_messaging.js +++ b/askbot/media/js/group_messaging.js @@ -331,6 +331,14 @@ var ThreadHeading = function() { }; inherits(ThreadHeading, SimpleControl); +ThreadHeading.prototype.setParent = function(elem) { + this._threadsList = elem; +}; + +ThreadHeading.prototype.getParent = function() { + return this._threadsList; +}; + ThreadHeading.prototype.getId = function() { return this._id; }; @@ -338,6 +346,12 @@ ThreadHeading.prototype.getId = function() { ThreadHeading.prototype.decorate = function(element) { this._element = element; this._id = element.data('threadId'); + var deleter = element.find('.delete-or-restore'); + var me = this; + setupButtonEventHandlers($(deleter), function() { + me.getParent().deleteOrRestoreThread(me.getId()); + return false; + }); }; /** @@ -359,12 +373,9 @@ ThreadsList.prototype.getOpenThreadHandler = function(threadId) { }; }; -ThreadsList.prototype.setHTML = function(html) { - $.each(this._threads, function(idx, thread) { - thread.dispose(); - }); - this._element.html(html); - this.decorate(this._element); +ThreadsList.prototype.deleteOrRestoreThread = function(threadId) { + var ctr = this._messageCenter; + ctr.deleteOrRestoreThread(threadId, this._senderId); }; ThreadsList.prototype.decorate = function(element) { @@ -374,12 +385,14 @@ ThreadsList.prototype.decorate = function(element) { var threads = []; $.each(headingElements, function(idx, headingElement) { var heading = new ThreadHeading(); + heading.setParent(me); heading.decorate($(headingElement)); var threadId = heading.getId(); heading.setHandler(me.getOpenThreadHandler(threadId)); threads.push(heading); }); this._threads = threads; + this._senderId = element.data('senderId'); } @@ -604,25 +617,43 @@ MessageCenter.prototype.openThread = function(threadId) { }); }; -MessageCenter.prototype.loadThreadsForSender = function(senderId) { +MessageCenter.prototype.setThreadsList = function(list) { + this._threadsList = list; + this._secondCol.prepend(list.getElement()); +}; + +MessageCenter.prototype.hitThreadsList = function(url, senderId, requestMethod) { var threadsList = this._threadsList; - var url = this._urls['getThreads']; - me = this; + var me = this; $.ajax({ - type: 'GET', + type: requestMethod, dataType: 'json', url: url, cache: false, data: {sender_id: senderId}, success: function(data) { if (data['success']) { - threadsList.setHTML(data['html']); + threadsList.dispose(); + var threads = new ThreadsList(); + threads.setMessageCenter(me); + threads.decorate($(data['html'])); + me.setThreadsList(threads); me.setState('show-list'); } } }); }; +MessageCenter.prototype.deleteOrRestoreThread = function(threadId, senderId) { + var url = this._urls['getThreads'] + threadId + '/delete-or-restore/'; + this.hitThreadsList(url, senderId, 'POST'); +}; + +MessageCenter.prototype.loadThreadsForSender = function(senderId) { + var url = this._urls['getThreads']; + this.hitThreadsList(url, senderId, 'GET'); +}; + MessageCenter.prototype.decorate = function(element) { this._element = element; this._firstCol = element.find('.first-col'); diff --git a/askbot/templates/group_messaging/senders_list.html b/askbot/templates/group_messaging/senders_list.html index 687cacd6..4bee2626 100644 --- a/askbot/templates/group_messaging/senders_list.html +++ b/askbot/templates/group_messaging/senders_list.html @@ -1,8 +1,3 @@ -{#<ul class="mailboxes"> - <li><a class="inbox selected">{% trans %}Inbox{% endtrans %}</a></li> - <li><a class="sent">{% trans %}Sent{% endtrans %}</a></li> - <li><a class="trash">{% trans %}Trash{% endtrans %}</a></li> -</ul>#} {% if senders %} <ul class="senders-list"> <li>{% trans %}Messages by sender:{% endtrans %}</li> @@ -10,5 +5,7 @@ {% for sender in senders %} <li><a data-sender-id="{{ sender.id }}">{{ sender.username|escape }}</a></li> {% endfor %} + {# -2 is deleted messages #} + <li><a class="trash" data-sender-id="-2">{% trans %}trash{% endtrans %}</a></li> </ul> {% endif %} diff --git a/askbot/templates/group_messaging/threads_list.html b/askbot/templates/group_messaging/threads_list.html index 8469198c..224cf4f1 100644 --- a/askbot/templates/group_messaging/threads_list.html +++ b/askbot/templates/group_messaging/threads_list.html @@ -1,10 +1,13 @@ -<table class="threads-list"> +<table class="threads-list {% if sender_id == -2 %}trash{% endif %}" + data-sender-id="{{ sender_id }}" +> {% if threads %} {% for thread in threads %} {% set thread_data = threads_data[thread.id] %} <tr class="thread-heading {{ thread_data['status'] }}" data-thread-id="{{ thread.id }}" > + <td class="delete-or-restore"></td> <td class="senders">{{ thread_data['senders_info']|escape }}</td> <td class="subject">{{ thread.headline|escape }}</td> <td class="timestamp">{{ thread.last_active_at|timesince }}</td> diff --git a/askbot/templates/user_inbox/messages.html b/askbot/templates/user_inbox/messages.html index 5108d15e..8c731401 100644 --- a/askbot/templates/user_inbox/messages.html +++ b/askbot/templates/user_inbox/messages.html @@ -22,6 +22,7 @@ } table.threads-list { width: 100%; + border-spacing: 0px; } .threads-list tr { height: 2em; @@ -36,6 +37,16 @@ .threads-list tr:hover { background-color: #eff5f6; } + .threads-list td.delete-or-restore { + width: 15px; + background-image: none; + } + .threads-list tr:hover td.delete-or-restore { + background: url({{"/images/delete.png"|media}}) no-repeat center center; + } + .threads-list.trash tr:hover td.delete-or-restore { + background-image: url({{"/images/delete.png"|media}}); + } td.empty { line-height: 30px; vertical-align: middle; diff --git a/group_messaging/models.py b/group_messaging/models.py index 62f720cf..f78f2b87 100644 --- a/group_messaging/models.py +++ b/group_messaging/models.py @@ -87,7 +87,7 @@ class MessageMemo(models.Model): (ARCHIVED, 'archived') ) user = models.ForeignKey(User) - message = models.ForeignKey('Message') + message = models.ForeignKey('Message', related_name='memos') status = models.SmallIntegerField( choices=STATUS_CHOICES, default=SEEN ) @@ -99,13 +99,21 @@ class MessageMemo(models.Model): class MessageManager(models.Manager): """model manager for the :class:`Message`""" - def get_threads_for_user(self, user): + def get_threads_for_user(self, user, deleted=False): user_groups = user.groups.all() - return self.filter( - root=None, - message_type=Message.STORED, - recipients__in=user_groups - ) + user_thread_filter = models.Q( + root=None, + message_type=Message.STORED, + recipients__in=user_groups + ) + deleted_filter = models.Q( + memos__status=MessageMemo.ARCHIVED, + memos__user=user + ) + if deleted: + return self.filter(user_thread_filter & deleted_filter) + else: + return self.filter(user_thread_filter & ~deleted_filter) def create(self, **kwargs): """creates a message""" diff --git a/group_messaging/urls.py b/group_messaging/urls.py index 30002bf3..19ee35bb 100644 --- a/group_messaging/urls.py +++ b/group_messaging/urls.py @@ -15,6 +15,11 @@ urlpatterns = patterns('', name='thread_details' ), url( + '^threads/(?P<thread_id>\d+)/delete-or-restore/$', + views.DeleteOrRestoreThread().as_view(), + name='delete_or_restore_thread' + ), + url( '^threads/create/$', views.NewThread().as_view(), name='create_thread' diff --git a/group_messaging/views.py b/group_messaging/views.py index 289961ff..ef95e1d5 100644 --- a/group_messaging/views.py +++ b/group_messaging/views.py @@ -18,6 +18,7 @@ from django.http import HttpResponseNotAllowed from django.http import HttpResponseForbidden from django.utils import simplejson from group_messaging.models import Message +from group_messaging.models import MessageMemo from group_messaging.models import SenderList from group_messaging.models import LastVisitTime from group_messaging.models import get_personal_group_by_user_id @@ -139,6 +140,7 @@ class PostReply(InboxView): template_name='group_messaging/stored_message.html' ) + class ThreadsList(InboxView): """shows list of threads for a given user""" template_name = 'group_messaging/threads_list.html' @@ -147,11 +149,13 @@ class ThreadsList(InboxView): def get_context(self, request): """returns thread list data""" #get threads and the last visit time - threads = Message.objects.get_threads_for_user(request.user) - - sender_id = IntegerField().clean(request.GET.get('sender_id', '-1')) - if sender_id != -1: - threads = threads.filter(sender__id=sender_id) + sender_id = IntegerField().clean(request.REQUEST.get('sender_id', '-1')) + if sender_id == -2: + threads = Message.objects.get_threads_for_user(request.user, deleted=True) + else: + threads = Message.objects.get_threads_for_user(request.user) + if sender_id != -1: + threads = threads.filter(sender__id=sender_id) #for each thread we need to know if there is something #unread for the user - to mark "new" threads as bold @@ -179,7 +183,48 @@ class ThreadsList(InboxView): #after we have all the data - update the last visit time last_visit_times.update(at=datetime.datetime.now()) - return {'threads': threads, 'threads_data': threads_data} + return { + 'threads': threads, + 'threads_data': threads_data, + 'sender_id': sender_id + } + + +class DeleteOrRestoreThread(ThreadsList): + """subclassing :class:`ThreadsList`, because deletion + or restoring of thread needs subsequent refreshing + of the threads list""" + + http_method_list = ('POST',) + + def post(self, request, thread_id=None): + """process the post request: + * delete or restore thread + * recalculate the threads list and return it for display + by reusing the threads list "get" function + """ + #part of the threads list context + sender_id = IntegerField().clean(request.POST['sender_id']) + + #a little cryptic, but works - sender_id==-2 means deleted post + if sender_id == -2: + action = 'restore' + else: + action = 'delete' + + thread = Message.objects.get(id=thread_id) + memo, created = MessageMemo.objects.get_or_create( + user=request.user, + message=thread + ) + if action == 'delete': + memo.status = MessageMemo.ARCHIVED + else: + memo.status = MessageMemo.SEEN + memo.save() + + context = self.get_context(request) + return self.render_to_response(context) class SendersList(InboxView): |