publication suggestions
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 9 Jun 2011 10:48:48 +0000 (12:48 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 9 Jun 2011 10:48:48 +0000 (12:48 +0200)
15 files changed:
apps/catalogue/views.py
apps/pdcounter/views.py
apps/suggest/admin.py
apps/suggest/forms.py
apps/suggest/locale/pl/LC_MESSAGES/django.mo
apps/suggest/locale/pl/LC_MESSAGES/django.po
apps/suggest/models.py
apps/suggest/urls.py
apps/suggest/views.py
wolnelektury/static/css/master.css
wolnelektury/static/js/catalogue.js
wolnelektury/templates/base.html
wolnelektury/templates/catalogue/search_no_hits.html
wolnelektury/templates/pdcounter/author_detail.html
wolnelektury/templates/pdcounter/book_stub_detail.html

index 84cce7b..7addb7f 100644 (file)
@@ -37,6 +37,7 @@ from catalogue.utils import split_tags
 from newtagging import views as newtagging_views
 from pdcounter import models as pdcounter_models
 from pdcounter import views as pdcounter_views
+from suggest.forms import PublishingSuggestForm
 from slughifi import slughifi
 
 
@@ -468,7 +469,9 @@ def search(request):
             {'tags':tag_list, 'prefix':prefix, 'results':((x, _get_result_link(x, tag_list), _get_result_type(x)) for x in result)},
             context_instance=RequestContext(request))
     else:
-        return render_to_response('catalogue/search_no_hits.html', {'tags':tag_list, 'prefix':prefix},
+        form = PublishingSuggestForm(initial={"books": prefix + ", "})
+        return render_to_response('catalogue/search_no_hits.html', 
+            {'tags':tag_list, 'prefix':prefix, "pubsuggest_form": form},
             context_instance=RequestContext(request))
 
 
index fa32909..efcfe95 100644 (file)
@@ -8,6 +8,7 @@ from django.template import RequestContext
 from django.shortcuts import render_to_response, get_object_or_404
 from pdcounter import models
 from catalogue import forms
+from suggest.forms import PublishingSuggestForm
 
 
 def book_stub_detail(request, slug):
@@ -15,6 +16,9 @@ def book_stub_detail(request, slug):
     pd_counter = book.pd
     form = forms.SearchForm()
 
+    pubsuggest_form = PublishingSuggestForm(
+            initial={"books": u"%s — %s, \n" % (book.author, book.title)})
+
     return render_to_response('pdcounter/book_stub_detail.html', locals(),
         context_instance=RequestContext(request))
 
@@ -24,5 +28,7 @@ def author_detail(request, slug):
     pd_counter = author.goes_to_pd()
     form = forms.SearchForm()
 
+    pubsuggest_form = PublishingSuggestForm(initial={"books": author.name + ", \n"})
+
     return render_to_response('pdcounter/author_detail.html', locals(),
         context_instance=RequestContext(request))
index d1ce07b..b5fcb5c 100644 (file)
@@ -4,9 +4,15 @@
 #
 from django.contrib import admin
 
-from suggest.models import Suggestion
+from suggest.models import Suggestion, PublishingSuggestion
 
 class SuggestionAdmin(admin.ModelAdmin):
     list_display = ('created_at', 'contact', 'user', 'description')
 
 admin.site.register(Suggestion, SuggestionAdmin)
+
+
+class PublishingSuggestionAdmin(admin.ModelAdmin):
+    list_display = ('created_at', 'contact', 'user', 'books', 'audiobooks')
+
+admin.site.register(PublishingSuggestion, PublishingSuggestionAdmin)
index 7084eff..5c034e6 100644 (file)
@@ -3,8 +3,61 @@
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 from django import forms
+from django.core.mail import send_mail, mail_managers
+from django.core.urlresolvers import reverse
+from django.core.validators import email_re
 from django.utils.translation import ugettext_lazy as _
 
+from suggest.models import PublishingSuggestion
+
+
 class SuggestForm(forms.Form):
     contact = forms.CharField(label=_('Contact'), max_length=120, required=False)
     description = forms.CharField(label=_('Description'), widget=forms.Textarea, required=True)
+
+
+class PublishingSuggestForm(forms.Form):
+    contact = forms.CharField(label=_('Contact'), max_length=120, required=False)
+    books = forms.CharField(label=_('books'), widget=forms.Textarea, required=True)
+    audiobooks = forms.CharField(label=_('audiobooks'), widget=forms.Textarea, required=True)
+
+    def save(self, request):
+        contact = self.cleaned_data['contact']
+        books = self.cleaned_data['books']
+        audiobooks = self.cleaned_data['audiobooks']
+
+        suggestion = PublishingSuggestion(contact=contact, books=books,
+            audiobooks=audiobooks, ip=request.META['REMOTE_ADDR'])
+        if request.user.is_authenticated():
+            suggestion.user = request.user
+        suggestion.save()
+
+        mail_managers(u'Konsultacja planu wydawniczego na WolneLektury.pl', u'''\
+Zgłoszono nową sugestię nt. planu wydawniczego w serwisie WolneLektury.pl.
+%(url)s
+
+Użytkownik: %(user)s
+Kontakt: %(contact)s
+
+Książki:
+%(books)s
+
+Audiobooki:
+%(audiobooks)s''' % {
+            'url': request.build_absolute_uri(reverse('admin:suggest_suggestion_change', args=[suggestion.id])),
+            'user': str(request.user) if request.user.is_authenticated() else '',
+            'contact': contact,
+            'books': books,
+            'audiobooks': audiobooks,
+            }, fail_silently=True)
+
+        if email_re.match(contact):
+            send_mail(u'[WolneLektury] ' + _(u'Thank you for your suggestion.'),
+                    _(u"""\
+Thank you for your comment on WolneLektury.pl.
+The suggestion has been referred to the project coordinator.""") +
+u"""
+
+-- 
+""" + _(u'''Message sent automatically. Please do not reply.'''),
+                    'no-reply@wolnelektury.pl', [contact], fail_silently=True)
index 40fe313..2e3e5d7 100644 (file)
Binary files a/apps/suggest/locale/pl/LC_MESSAGES/django.mo and b/apps/suggest/locale/pl/LC_MESSAGES/django.mo differ
index 5531d67..a14e7f3 100644 (file)
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-02-23 10:46+0100\n"
-"PO-Revision-Date: 2011-02-23 10:52+0100\n"
+"POT-Creation-Date: 2011-06-09 12:31+0200\n"
+"PO-Revision-Date: 2011-06-09 12:35+0100\n"
 "Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "Language: \n"
@@ -17,27 +17,60 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "X-Translated-Using: django-rosetta 0.5.3\n"
 
-#: forms.py:9
+#: forms.py:15
+#: forms.py:20
 msgid "Contact"
 msgstr "Kontakt"
 
-#: forms.py:10
+#: forms.py:16
 msgid "Description"
 msgstr "Opis"
 
+#: forms.py:21
+msgid "books"
+msgstr "książki"
+
+#: forms.py:22
+msgid "audiobooks"
+msgstr "audiobooki"
+
+#: forms.py:55
+#: views.py:95
+msgid "Thank you for your suggestion."
+msgstr "Dziękujemy za zgłoszenie."
+
+#: forms.py:56
+#: views.py:96
+msgid ""
+"Thank you for your comment on WolneLektury.pl.\n"
+"The suggestion has been referred to the project coordinator."
+msgstr ""
+"Dziękujemy za zgłoszenie uwag do serwisu Wolne Lektury.\n"
+"Sugestia została przekazana koordynatorce projektu."
+
+#: forms.py:62
+#: views.py:102
+msgid "Message sent automatically. Please do not reply."
+msgstr "Wiadomość wysłana automatycznie. Proszę nie odpowiadać."
+
 #: models.py:10
+#: models.py:26
 msgid "contact"
 msgstr "kontakt"
 
 #: models.py:11
+#: models.py:27
+#: models.py:28
 msgid "description"
 msgstr "opis"
 
 #: models.py:12
+#: models.py:29
 msgid "creation date"
 msgstr "data utworzenia"
 
 #: models.py:13
+#: models.py:30
 msgid "IP address"
 msgstr "adres IP"
 
@@ -49,31 +82,45 @@ msgstr "sugestia"
 msgid "suggestions"
 msgstr "sugestie"
 
-#: views.py:49
-msgid "Thank you for your suggestion."
-msgstr "Dziękujemy za zgłoszenie."
-
-#: views.py:51
-msgid ""
-"Thank you for your comment on WolneLektury.pl.\n"
-"The suggestion has been referred to the project coordinator."
-msgstr ""
-"Dziękujemy za zgłoszenie uwag do serwisu Wolne Lektury.\n"
-"Sugestia została przekazana koordynatorce projektu."
+#: models.py:35
+msgid "publishing suggestion"
+msgstr "sugestia publikacji"
 
-#: views.py:56
-msgid "Message sent automatically. Please do not reply."
-msgstr "Wiadomość wysłana automatycznie. Proszę nie odpowiadać."
+#: models.py:36
+msgid "publishing suggestions"
+msgstr "sugestie publikacji"
 
-#: views.py:59
+#: views.py:40
+#: views.py:105
 msgid "Report was sent successfully."
 msgstr "Zgłoszenie zostało wysłane."
 
-#: templates/suggest.html:2
-msgid "Report a bug or suggestion"
-msgstr "Zgłoś błąd lub sugestię"
+#: templates/publishing_suggest.html:2
+msgid "Didn't find a book? Make a suggestion."
+msgstr "Nie znalazłeś utworu na stronie? Zgłoś sugestię."
+
+#: templates/publishing_suggest.html:7
+msgid "I'd like to find in WolneLektury.pl these…"
+msgstr "Chciałabym/chciałbym znaleźć w bibliotece Wolne Lektury następujące"
 
+#: templates/publishing_suggest.html:13
 #: templates/suggest.html:7
 msgid "Send report"
 msgstr "Wyślij zgłoszenie"
 
+#: templates/publishing_suggest_full.html:12
+msgid "Search"
+msgstr ""
+
+#: templates/publishing_suggest_full.html:12
+msgid "or"
+msgstr ""
+
+#: templates/publishing_suggest_full.html:12
+msgid "return to main page"
+msgstr ""
+
+#: templates/suggest.html:2
+msgid "Report a bug or suggestion"
+msgstr "Zgłoś błąd lub sugestię"
+
index e24afae..492f4ce 100644 (file)
@@ -20,3 +20,20 @@ class Suggestion(models.Model):
 
     def __unicode__(self):
         return unicode(self.created_at)
+
+
+class PublishingSuggestion(models.Model):
+    contact = models.CharField(_('contact'), blank=True, max_length=120)
+    books = models.TextField(_('books'))
+    audiobooks = models.TextField(_('audiobooks'))
+    created_at = models.DateTimeField(_('creation date'), auto_now_add=True)
+    ip = models.IPAddressField(_('IP address'))
+    user = models.ForeignKey(User, blank=True, null=True)
+
+    class Meta:
+        ordering = ('-created_at',)
+        verbose_name = _('publishing suggestion')
+        verbose_name_plural = _('publishing suggestions')
+
+    def __unicode__(self):
+        return unicode(self.created_at)
index d5982cf..b769e49 100644 (file)
@@ -4,11 +4,20 @@
 #
 from django.conf.urls.defaults import *
 from django.views.generic.simple import direct_to_template
-from suggest.forms import SuggestForm
+from suggest.forms import SuggestForm, PublishingSuggestForm
+from suggest.views import PublishingSuggestionFormView
 
 urlpatterns = patterns('',
     url(r'^$', 'django.views.generic.simple.direct_to_template',
         {'template': 'suggest.html', 'extra_context': {'form': SuggestForm }}, name='suggest'),
     url(r'^wyslij/$', 'suggest.views.report', name='report'),
+
+    #url(r'^plan/$', 'suggest.views.publishing', name='suggest_publishing'),
+    url(r'^plan/$', PublishingSuggestionFormView(), name='suggest_publishing'),
+    #url(r'^plan_block/$', 'django.views.generic.simple.direct_to_template',
+    #    {'template': 'publishing_suggest.html', 
+    #            'extra_context': {'pubsuggest_form': PublishingSuggestForm }},
+    #    name='suggest_publishing'),
+    #url(r'^plan/wyslij/$', 'suggest.views.publishing_commit', name='suggest_publishing_commit'),
 )
 
index 1fcb336..24ee12c 100644 (file)
@@ -10,15 +10,59 @@ from django.utils.translation import ugettext as _
 from django.views.decorators import cache
 from django.views.decorators.http import require_POST
 from django.contrib.sites.models import Site
+from django.shortcuts import render_to_response
+from django.template import RequestContext
 
+from catalogue.forms import SearchForm
 from suggest import forms
-from suggest.models import Suggestion
+from suggest.models import Suggestion, PublishingSuggestion
+
 
 # FIXME - shouldn't be in catalogue
 from catalogue.views import LazyEncoder
 
 
-#@require_POST
+class AjaxableFormView(object):
+    formClass = None
+    template = None
+    ajax_template = None
+    formname = None
+
+    def __call__(self, request):
+        """
+            A view displaying a form, or JSON if `ajax' GET param is set.
+        """
+        ajax = request.GET.get('ajax', False)
+        if request.method == "POST":
+            form = self.formClass(request.POST)
+            if form.is_valid():
+                form.save(request)
+                response_data = {'success': True, 'message': _('Report was sent successfully.')}
+            else:
+                response_data = {'success': False, 'errors': form.errors}
+            if ajax:
+                return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
+        else:
+            form = self.formClass()
+            response_data = None
+
+        template = self.ajax_template if ajax else self.template
+        return render_to_response(template, {
+                self.formname: form, 
+                "form": SearchForm(),
+                "response_data": response_data,
+            },
+            context_instance=RequestContext(request))
+
+
+class PublishingSuggestionFormView(AjaxableFormView):
+    formClass = forms.PublishingSuggestForm
+    ajax_template = "publishing_suggest.html"
+    template = "publishing_suggest_full.html"
+    formname = "pubsuggest_form"
+
+
+@require_POST
 @cache.never_cache
 def report(request):
     suggest_form = forms.SuggestForm(request.POST)
index 9377c84..e30fbda 100644 (file)
@@ -912,6 +912,46 @@ div.shown-tags p, div.all-tags p {
        width: 30em;
 }
 
+
+.big-top-link {
+    margin-top: .6em;
+    font-size: 2em;
+    /*max-width: 15em;*/
+    line-height: 1.2em;
+}
+
+#suggest-publishing-window {
+    position: absolute;
+    display: none;
+    width: 45em;
+    background-color: transparent;
+    margin-top: -0.5em;
+    margin-left: 1em;
+}
+
+#suggest-publishing-window div.header {
+    background-color: #FFF;
+    border-right: 0.3em solid #DDD;
+    width: 4em;
+    right: 0;
+    left: auto;
+    padding: 0.5em 1em 0.5em 1em;
+    float: right;
+    text-align: center;
+}
+
+#suggest-publishing-window div.target {
+    clear: both;
+    background-color: #FFF;
+    border-right: 0.3em solid #DDD;
+    border-bottom: 0.3em solid #DDD;
+    padding: 1em;
+}
+#suggest-publishing-form textarea {
+       width: 40em;
+    height: 6em;
+}
+
 /* ======================== */
 /* = Alphabetic book list = */
 /* ======================== */
index 6715685..ee8a045 100644 (file)
@@ -345,6 +345,62 @@ function serverTime() {
             }
         });
 
+        $('#suggest-publishing-window').jqm({
+            ajax: '@data-ajax',
+            target: $('#suggest-publishing-window div.target')[0],
+            overlay: 60,
+            trigger: '#suggest-publishing-link',
+            onShow: function(hash) {
+                var offset = $(hash.t).offset();
+                hash.w.css({position: 'absolute', left: offset.left - hash.w.width() + $(hash.t).width(), top: offset.top});
+                $('div.header', hash.w).css({width: $(hash.t).width()});
+                hash.w.show();
+            },
+            onLoad: function(hash) {
+                $('form', hash.w).each(function() {this.action += '?ajax=1';});
+                $('form', hash.w).ajaxForm({
+                    dataType: 'json',
+                    target: $('#suggest-publishing-window div.target'),
+                    success: function(response) {
+                        if (response.success) {
+                            $('#suggest-publishing-window div.target').text(response.message);
+                            setTimeout(function() { $('#suggest-publishing-window').jqmHide() }, 1000)
+                        }
+                        else {
+                            $('#suggest-publishing-form .error').remove();
+                            $.each(response.errors, function(id, errors) {
+                                $('#suggest-publishing-form #id_' + id).before('<span class="error">' + errors[0] + '</span>');
+                            });
+                            $('#suggest-publishing-form input[type=submit]').removeAttr('disabled');
+                            return false;
+                        }
+                    }
+                });
+            }
+        });
+
+        (function($this) {
+            $form = $('form', $this);
+            $form.each(function() {this.action += '?ajax=1';});
+            $form.ajaxForm({
+                dataType: 'json',
+                target: $this,
+                success: function(response) {
+                    if (response.success) {
+                        $this.text(response.message);
+                    }
+                    else {
+                        $('.error', $form).remove();
+                        $.each(response.errors, function(id, errors) {
+                            $('#id_' + id, $form).before('<span class="error">' + errors[0] + '</span>');
+                        });
+                        $('input[type=submit]', $form).removeAttr('disabled');
+                        return false;
+                    }
+                }
+            });
+        })($('.block-form'));
+        
         $('#books-list .book').hover(
             function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
             function() { $(this).css({background: '#FFF'}); }
index d9eaee5..9568883 100644 (file)
                                        {% endspaceless %}                              
                        </div>
                 </form>
+            {# publication plan consultations - form link #}
+            <div style="clear:right;float:right" class="big-top-link">
+                <a href="{% url suggest_publishing %}" data-ajax="{% url suggest_publishing %}?ajax=1" id="suggest-publishing-link">
+                    {% trans "Didn't find a book? Make a suggestion." %}
+                </a>
+            </div>
             <div class="clearboth"></div>
         </div>
         <div id="maincontent">
                 <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
             </div>
         </div>
+        <div id="suggest-publishing-window">
+            <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+            <div class="target">
+                <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
+            </div>
+        </div>
         {% endblock bodycontent %}
         {{ piwik_tag|safe }}
         <script type="text/javascript">
         pageTracker._trackPageview();
         </script>
     </body>
-</html>
\ No newline at end of file
+</html>
index 1a92e4b..bffefe3 100644 (file)
         {% include "info/join_us.html" %}
     </div>
 
-    <div id="set-window">
-        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
-        <div class="target">
-            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
-        </div>
+    <div class="column-right block-form">
+        {% include "publishing_suggest.html" %}
     </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}
index 05cdbb9..1fd0985 100644 (file)
         {% include "info/join_us.html" %}
     </div>
 
-    <div id="set-window">
-        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
-        <div class="target">
-            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
-        </div>
+    <div class="column-right block-form">
+        {% include "publishing_suggest.html" %}
     </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}
index 6817b65..78b04d6 100644 (file)
     {% include "info/join_us.html" %}
     </div>
 
-    <div id="set-window">
-        <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
-        <div class="target">
-            <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
-        </div>
+    <div class="column-right block-form">
+        {% include "publishing_suggest.html" %}
     </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}