Projet

Général

Profil

0001-import-subscribers-from-csv-14010.patch

Serghei Mihai (congés, retour 15/05), 30 janvier 2017 18:06

Télécharger (8,92 ko)

Voir les différences:

Subject: [PATCH] import subscribers from csv (#14010)

 corbo/forms.py                                     | 22 ++++++++++++
 corbo/manage_urls.py                               |  4 ++-
 corbo/static/css/corbo.css                         | 39 ++++++++++++++++++++++
 corbo/static/js/corbo.manager.js                   |  6 ++++
 corbo/templates/corbo/base.html                    |  2 ++
 corbo/templates/corbo/category_detail.html         |  5 +++
 .../templates/corbo/subscriptions_import_form.html | 23 +++++++++++++
 corbo/views.py                                     | 31 +++++++++++++++--
 8 files changed, 129 insertions(+), 3 deletions(-)
 create mode 100644 corbo/static/js/corbo.manager.js
 create mode 100644 corbo/templates/corbo/subscriptions_import_form.html
corbo/forms.py
1
import csv
2

  
1 3
from django import forms
2 4
from django.utils.translation import ugettext_lazy as _
3 5
from django.utils.text import slugify
4 6
from django.core.exceptions import ObjectDoesNotExist
7
from django.core import validators
8
from django.core.exceptions import ValidationError
5 9

  
6 10
from .models import Announce, Category, Broadcast, channel_choices
7 11

  
......
45 49
                slug = '%s-%s' % (base_slug, i)
46 50
            self.instance.slug = slug
47 51
        return super(CategoryForm, self).save(commit=commit)
52

  
53

  
54
class SubscriptionsImportForm(forms.Form):
55
    subscribers = forms.FileField(_('Subscribers'),
56
                    help_text=_('CSV file with email addresses on first column'))
57

  
58
    def clean_subscribers(self, *args, **kwargs):
59
        subscribers = []
60
        reader = csv.reader(self.cleaned_data['subscribers'])
61
        for idx, row in enumerate(reader, 1):
62
            if not row[0]:
63
                continue
64
            try:
65
                validators.validate_email(row[0])
66
                subscribers.append(row[0])
67
            except ValidationError:
68
                raise ValidationError(_('Invalid email address at line %s' % idx))
69
        return subscribers
corbo/manage_urls.py
2 2

  
3 3
from .views import add_announce, edit_announce, delete_announce, \
4 4
    add_category, edit_category, view_category, delete_category, manage, \
5
    menu_json
5
    subscriptions_import, menu_json
6 6

  
7 7
urlpatterns = patterns('',
8 8
            url(r'^$', manage, name='manage'),
......
20 20
                name='edit_category'),
21 21
            url(r'^category/delete/(?P<slug>[\w-]+)$', delete_category,
22 22
                name='delete_category'),
23
            url(r'^category/(?P<slug>[\w-]+)/import-subscriptions$', subscriptions_import,
24
                name='subscriptions-import'),
23 25
            url(r'^menu.json$', menu_json),
24 26
)
corbo/static/css/corbo.css
165 165
    border-radius: 0.3em;
166 166
    text-transform: uppercase;
167 167
}
168

  
169
#appbar .menu-opener {
170
        border: none;
171
        cursor: pointer;
172
}
173

  
174
#appbar .menu {
175
        background: white;
176
        padding: 10px;
177
        list-style: none;
178
        position: absolute;
179
        right: 0px;
180
        margin-top: -24px;
181
        border: 1px solid #d0d0d0;
182
        background: #fafafa;
183
        box-shadow: 0px 1px 1px 2px rgba(0, 0, 0, 0.04);
184
        z-index: 100;
185
}
186

  
187
#appbar .menu a {
188
        float: none;
189
        top: 0;
190
        right: 0;
191
        margin: 0;
192
        display: block;
193
        min-width: 12em;
194
}
195

  
196
#appbar .menu li {
197
        margin: 1ex 0;
198
}
199

  
200
#appbar .menu li a {
201
        border: none;
202
}
203

  
204
#appbar .menu li a:hover {
205
        background: white;
206
}
corbo/static/js/corbo.manager.js
1
$(function() {
2
    $('a.menu-opener').on('click', function() {
3
        $('#appbar .menu').toggle();
4
    });
5
});
6

  
corbo/templates/corbo/base.html
19 19
    <link rel="stylesheet" type="text/css" media="all" href="{% static 'css/datetimepicker.css' %}" />
20 20
    <script src="{% static 'js/bootstrap-datetimepicker.js' %}"></script>
21 21
    <script src="{% static 'js/locales/bootstrap-datetimepicker.fr.js' %}"></script>
22
    <script src="{% static 'js/corbo.manager.js' %}"></script>
23
    <script src="{% static 'js/gadjo.js' %}"></script>
22 24
{% endblock %}
23 25

  
24 26
{% block logout-url %}
corbo/templates/corbo/category_detail.html
10 10

  
11 11
{% block appbar %}
12 12
<h2>{{ object.name }}</h2>
13
<a class="menu-opener">☰</a>
14
<ul class="menu" style="display: none">
15
  <li><a href="{% url 'subscriptions-import' slug=category.slug %}" rel="popup">{% trans 'Import subscriptions' %}</a></li>
16
</ul>
17

  
13 18
<a href="{% url 'delete_category' slug=object.slug %}" rel="popup">{% trans 'Delete' %}</a>
14 19
<a href="{% url 'edit_category' slug=object.slug %}" rel="popup">{% trans 'Edit' %}</a>
15 20
<a href="{% url 'add_announce' slug=object.slug %}">{% trans 'New announce' %}</a>
corbo/templates/corbo/subscriptions_import_form.html
1
{% extends "corbo/category_detail.html" %}
2
{% load i18n static %}
3

  
4
{% block breadcrumb %}
5
{{ block.super }}
6
<a href='{% url "view_category" slug=category.slug %}'>{{ category }}</a>
7
{% endblock %}
8

  
9
{% block appbar %}
10
<h2>{% trans "Import subscriptions" %}</h2>
11
{% endblock %}
12

  
13

  
14
{% block content %}
15
<form method="post" enctype="multipart/form-data">
16
  {% csrf_token %}
17
  {{ form }}
18
<div class="buttons">
19
  <button>{% trans "Save" %}</button>
20
  <a href="{% url "view_category" slug=category.slug %}" class="cancel">{% trans "Cancel" %}</a>
21
</div>
22
</form>
23
{% endblock %}
corbo/views.py
6 6
from django.utils import timezone
7 7
from django.core.urlresolvers import reverse
8 8
from django.views.generic import CreateView, UpdateView, DeleteView, \
9
    ListView, TemplateView, RedirectView, DetailView
9
    ListView, TemplateView, RedirectView, DetailView, FormView
10 10
from django.contrib.syndication.views import Feed
11 11
from django.shortcuts import resolve_url
12 12
from django.utils.encoding import force_text
......
14 14
from django.http import HttpResponseRedirect, HttpResponse, Http404
15 15
from django.contrib.auth import logout as auth_logout
16 16
from django.contrib.auth import views as auth_views
17
from django.contrib import messages
17 18
from django.utils.translation import ugettext_lazy as _
18 19

  
19 20
import models
20
from .forms import AnnounceForm, CategoryForm
21
from .forms import AnnounceForm, CategoryForm, SubscriptionsImportForm
21 22

  
22 23
try:
23 24
    from mellon.utils import get_idps
......
222 223
atom = AtomView()
223 224

  
224 225

  
226
class SubscriptionsImportView(FormView):
227
    form_class = SubscriptionsImportForm
228
    template_name = 'corbo/subscriptions_import_form.html'
229

  
230
    def get_context_data(self, **kwargs):
231
        context = super(SubscriptionsImportView, self).get_context_data(**kwargs)
232
        context['category'] = models.Category.objects.get(slug=self.kwargs['slug'])
233
        return context
234

  
235
    def get_success_url(self):
236
        category = models.Category.objects.get(slug=self.kwargs['slug'])
237
        return reverse('view_category', kwargs={'slug': category.slug})
238

  
239
    def form_valid(self, form):
240
        new = 0
241
        c = models.Category.objects.get(slug=self.kwargs['slug'])
242
        for email in form.cleaned_data['subscribers']:
243
            obj, created = models.Subscription.objects.get_or_create(category=c, identifier='mailto:%s' % email)
244
            if created:
245
               new += 1
246
        messages.info(self.request, _('%s subscriptions added') % new)
247
        return super(SubscriptionsImportView, self).form_valid(form)
248

  
249
subscriptions_import = SubscriptionsImportView.as_view()
250

  
251

  
225 252
def menu_json(request):
226 253
    label = _('Announces')
227 254
    json_str = json.dumps([{'label': force_text(label),
228
-