diff options
author | Aurélien Bompard <aurelien@bompard.org> | 2013-02-04 17:27:40 +0100 |
---|---|---|
committer | Aurélien Bompard <aurelien@bompard.org> | 2013-02-04 17:27:40 +0100 |
commit | cec92b8f26a8149b8eb1fe831a036704cb20d5d6 (patch) | |
tree | 5f2049c3124c0d1b91374fd669b0c1b32ab34f8d /hyperkitty | |
parent | 0746b9db3c828b90885d81ce64bbd33fe03c8a26 (diff) | |
parent | f6a642a52e05f44f7131dfd182e707d6f1fe6e7e (diff) | |
download | hyperkitty-cec92b8f26a8149b8eb1fe831a036704cb20d5d6.tar.gz hyperkitty-cec92b8f26a8149b8eb1fe831a036704cb20d5d6.tar.xz hyperkitty-cec92b8f26a8149b8eb1fe831a036704cb20d5d6.zip |
Merge branch 'posting'
Diffstat (limited to 'hyperkitty')
-rw-r--r-- | hyperkitty/static/css/hyperkitty.css | 36 | ||||
-rw-r--r-- | hyperkitty/static/img/reply.png | bin | 0 -> 641 bytes | |||
-rw-r--r-- | hyperkitty/static/js/hyperkitty.js | 70 | ||||
-rw-r--r-- | hyperkitty/static/libs/bootstrap/bootstrap.css | 2 | ||||
-rw-r--r-- | hyperkitty/templates/messages/message.html | 1 | ||||
-rw-r--r-- | hyperkitty/templates/messages/reply_form.html | 14 | ||||
-rw-r--r-- | hyperkitty/urls.py | 2 | ||||
-rw-r--r-- | hyperkitty/views/accounts.py | 1 | ||||
-rw-r--r-- | hyperkitty/views/forms.py | 2 | ||||
-rw-r--r-- | hyperkitty/views/message.py | 35 | ||||
-rw-r--r-- | hyperkitty/views/thread.py | 1 |
11 files changed, 151 insertions, 13 deletions
diff --git a/hyperkitty/static/css/hyperkitty.css b/hyperkitty/static/css/hyperkitty.css index 6017c74..c6aefa1 100644 --- a/hyperkitty/static/css/hyperkitty.css +++ b/hyperkitty/static/css/hyperkitty.css @@ -855,3 +855,39 @@ ul.attachments-list li { border-left: 2px solid rgb(55, 113, 200); padding-left: 0.2em; } + + +/* + * Replies + */ +a.reply { + background: url("../img/reply.png") no-repeat left center; + padding-left: 20px; + margin-left: 2em; +} +.reply-form { + display: none; + padding-top: 1em; +} +.reply-form p { + margin: 0; +} +.reply-form textarea { + width: 95%; +} +.reply-form .buttons .submit { + margin-right: 2em; +} +.reply-result { + text-align: center; +} +.reply-result .alert { + display: inline-block; +} +.reply-result .alert-success { + margin-bottom: 0; +} +.reply-result .alert-error { + white-space: pre; + text-align: left; +} diff --git a/hyperkitty/static/img/reply.png b/hyperkitty/static/img/reply.png Binary files differnew file mode 100644 index 0000000..7348aed --- /dev/null +++ b/hyperkitty/static/img/reply.png diff --git a/hyperkitty/static/js/hyperkitty.js b/hyperkitty/static/js/hyperkitty.js index 1bb6719..7464314 100644 --- a/hyperkitty/static/js/hyperkitty.js +++ b/hyperkitty/static/js/hyperkitty.js @@ -20,17 +20,25 @@ */ - /* - * Voting + * Generic */ - -function vote(elem, value) { - var form_data = $(elem).parent("form").serializeArray(); +function form_to_json(form) { + var form_data = form.serializeArray(); var data = {}; for (input in form_data) { data[form_data[input].name] = form_data[input].value; } + return data; +} + + +/* + * Voting + */ + +function vote(elem, value) { + var data = form_to_json($(elem).parent("form")); data['vote'] = value; $.ajax({ type: "POST", @@ -102,11 +110,7 @@ function setup_favorites() { e.preventDefault(); var form = $(this).parents("form").first(); var action_field = form.find("input[name='action']"); - var form_data = form.serializeArray(); - var data = {}; - for (input in form_data) { - data[form_data[input].name] = form_data[input].value; - } + var data = form_to_json(form); $.ajax({ type: "POST", url: form.attr("action"), @@ -131,6 +135,51 @@ function setup_favorites() { } +/* + * Replies + */ + +function setup_replies() { + $("a.reply").click(function(e) { + e.preventDefault(); + $(this).next().slideToggle("fast", function() { + if ($(this).css("display") === "block") { + $(this).find("textarea").focus(); + } + }); + }); + $(".reply-form button[type='submit']").click(function(e) { + e.preventDefault(); + var form = $(this).parents("form").first(); + var data = form_to_json(form); + $.ajax({ + type: "POST", + url: form.attr("action"), + //dataType: "json", + data: data, + success: function(response) { + form.parents(".reply-form").first().slideUp(function() { + form.find("textarea").val(""); + }); + $('<div class="reply-result"><div class="alert alert-success">' + + response + '</div></div>') + .appendTo(form.parents('.email_info').first()) + .delay(2000).fadeOut('slow', function() { $(this).remove(); }); + }, + error: function(jqXHR, textStatus, errorThrown) { + $('<div class="reply-result"><div class="alert alert-error">' + + '<button type="button" class="close" data-dismiss="alert">×</button> ' + + jqXHR.responseText + '</div></div>') + .css("display", "none").insertBefore(form).slideDown(); + } + }); + }); + $(".reply-form a.cancel").click(function(e) { + e.preventDefault(); + $(this).parents(".reply-form").first().slideUp(); + }); +} + /* * Recent activity graph @@ -230,4 +279,5 @@ $(document).ready(function() { setup_quotes(); setup_months_list(); setup_favorites(); + setup_replies(); }); diff --git a/hyperkitty/static/libs/bootstrap/bootstrap.css b/hyperkitty/static/libs/bootstrap/bootstrap.css index 8ab3cef..4da7f6d 100644 --- a/hyperkitty/static/libs/bootstrap/bootstrap.css +++ b/hyperkitty/static/libs/bootstrap/bootstrap.css @@ -2249,7 +2249,7 @@ table th[class*="span"], width: 14px; height: 14px; margin-top: 1px; - *margin-right: .3em; + margin-right: .3em; line-height: 14px; vertical-align: text-top; background-image: url("../img/glyphicons-halflings.png"); diff --git a/hyperkitty/templates/messages/message.html b/hyperkitty/templates/messages/message.html index 5d7261d..a47d831 100644 --- a/hyperkitty/templates/messages/message.html +++ b/hyperkitty/templates/messages/message.html @@ -57,6 +57,7 @@ </ul> </li> {% endif %} + {% include "messages/reply_form.html" with mlist_fqdn=list_address message_id=email.message_id_hash %} </ul> {# vim: set noet: #} diff --git a/hyperkitty/templates/messages/reply_form.html b/hyperkitty/templates/messages/reply_form.html new file mode 100644 index 0000000..29bd15b --- /dev/null +++ b/hyperkitty/templates/messages/reply_form.html @@ -0,0 +1,14 @@ + <a class="reply icon-envelope" href="#">Reply</a> + <div class="reply-form dropdown"> + <form method="post" + action="{% url message_reply mlist_fqdn=mlist_fqdn, message_id=message_id %}"> + {% csrf_token %} + {{ reply_form.as_p }} + <p class="buttons"> + <button type="submit" class="submit btn btn-primary">Send</button> + or <a class="cancel" href="#">cancel</a> + </p> + </form> + </div> + +{# vim: set noet: #} diff --git a/hyperkitty/urls.py b/hyperkitty/urls.py index ae38fe7..591ad41 100644 --- a/hyperkitty/urls.py +++ b/hyperkitty/urls.py @@ -61,6 +61,8 @@ urlpatterns = patterns('hyperkitty.views', 'message.attachment', name='message_attachment'), url(r'^list/(?P<mlist_fqdn>[^/@]+@[^/@]+)/message/(?P<hashid>\w+)/vote$', 'message.vote', name='message_vote'), + url(r'^list/(?P<mlist_fqdn>[^/@]+@[^/@]+)/message/(?P<message_id>\w+)/reply$', + 'message.reply', name='message_reply'), # Thread url(r'^list/(?P<mlist_fqdn>[^/@]+@[^/@]+)/thread/(?P<threadid>\w+)/$', diff --git a/hyperkitty/views/accounts.py b/hyperkitty/views/accounts.py index 85b6a9a..2ee36da 100644 --- a/hyperkitty/views/accounts.py +++ b/hyperkitty/views/accounts.py @@ -33,7 +33,6 @@ from django.contrib.auth.decorators import (login_required, user_passes_test) from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User -from django.core.urlresolvers import reverse from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render_to_response, redirect from django.template import Context, loader, RequestContext diff --git a/hyperkitty/views/forms.py b/hyperkitty/views/forms.py index d52eaea..90c288f 100644 --- a/hyperkitty/views/forms.py +++ b/hyperkitty/views/forms.py @@ -101,3 +101,5 @@ class SearchForm(forms.Form): ) +class ReplyForm(forms.Form): + message = forms.CharField(widget=forms.Textarea, label="") diff --git a/hyperkitty/views/message.py b/hyperkitty/views/message.py index 15aee66..509205c 100644 --- a/hyperkitty/views/message.py +++ b/hyperkitty/views/message.py @@ -26,10 +26,12 @@ import urllib import django.utils.simplejson as simplejson from django.http import HttpResponse, HttpResponseRedirect, Http404 -from django.shortcuts import redirect +from django.shortcuts import redirect, render from django.template import RequestContext, loader from django.conf import settings from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, InvalidPage +from django.core.urlresolvers import reverse +from django.core.mail import EmailMessage from django.contrib.auth.decorators import (login_required, permission_required, user_passes_test) @@ -92,6 +94,7 @@ def index(request, mlist_fqdn, hashid): 'hashid' : hashid, 'archives_length': get_months(store, mlist_fqdn), 'use_mockups': settings.USE_MOCKUPS, + 'reply_form': ReplyForm(), }) return HttpResponse(t.render(c)) @@ -153,3 +156,33 @@ def vote(request, mlist_fqdn, hashid): return HttpResponse(simplejson.dumps(status), mimetype='application/javascript') + + +@login_required +def reply(request, mlist_fqdn, message_id): + """ Sends a reply to the list. + TODO: unit tests + """ + if request.method != 'POST': + return HttpResponse("Something went wrong", content_type="text/plain", status=500) + form = ReplyForm(request.POST) + if not form.is_valid(): + return HttpResponse(form.errors.as_text(), content_type="text/plain", status=400) + store = get_store(request) + message = store.get_message_by_hash_from_list(mlist_fqdn, message_id) + subject = message.subject + if not message.subject.lower().startswith("re:"): + subject = "Re: %s" % subject + reply = EmailMessage( + subject=subject, + body=form.cleaned_data["message"], + from_email='"%s %s" <%s>' % + (request.user.first_name, request.user.last_name, + request.user.email), + to=[mlist_fqdn], + cc=['aurelien@bompard.org'], + headers={ + "In-Reply-To": message.message_id, + }) + reply.send() + return HttpResponse("The reply has been sent successfully.", mimetype="text/plain") diff --git a/hyperkitty/views/thread.py b/hyperkitty/views/thread.py index 6769034..549dfe0 100644 --- a/hyperkitty/views/thread.py +++ b/hyperkitty/views/thread.py @@ -144,6 +144,7 @@ def thread_index(request, mlist_fqdn, threadid, month=None, year=None): 'use_mockups': settings.USE_MOCKUPS, 'sort_mode': sort_mode, 'fav_action': fav_action, + 'reply_form': ReplyForm(), }) return HttpResponse(t.render(c)) |