Projet

Général

Profil

« Précédent | Suivant » 

Révision e01c978b

Ajouté par Frédéric Péters il y a environ 4 ans

general: update for compatibility with django 2.2 (#41626)

Voir les différences:

corbo/migrations/0001_initial.py
45 45
            name='Subscription',
46 46
            fields=[
47 47
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
48
                ('category', models.ForeignKey(verbose_name='category', to='corbo.Category')),
49
                ('user', models.ForeignKey(verbose_name='user', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
48
                ('category', models.ForeignKey(verbose_name='category',
49
                    to='corbo.Category', on_delete=models.CASCADE)),
50
                ('user', models.ForeignKey(verbose_name='user', blank=True,
51
                    to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)),
50 52
            ],
51 53
            options={
52 54
            },
......
57 59
            fields=[
58 60
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
59 61
                ('identifier', models.CharField(help_text='ex.: email, mobile phone number, jabber id', max_length=128, verbose_name='identifier', blank=True)),
60
                ('subscription', models.ForeignKey(to='corbo.Subscription')),
62
                ('subscription', models.ForeignKey(to='corbo.Subscription', on_delete=models.CASCADE)),
61 63
            ],
62 64
            options={
63 65
            },
......
70 72
        migrations.AddField(
71 73
            model_name='announce',
72 74
            name='category',
73
            field=models.ForeignKey(verbose_name='category', to='corbo.Category'),
75
            field=models.ForeignKey(verbose_name='category',
76
                to='corbo.Category', on_delete=models.CASCADE),
74 77
            preserve_default=True,
75 78
        ),
76 79
    ]
corbo/migrations/0002_auto_20150127_2221.py
18 18
                ('channel', models.CharField(max_length=32, verbose_name='channel', choices=[(b'sms', 'SMS'), (b'email', 'Email')])),
19 19
                ('time', models.DateTimeField(auto_now_add=True, verbose_name='sent time')),
20 20
                ('result', models.TextField(verbose_name='result', blank=True)),
21
                ('announce', models.ForeignKey(verbose_name='announce', to='corbo.Announce')),
21
                ('announce', models.ForeignKey(verbose_name='announce',
22
                    to='corbo.Announce', on_delete=models.CASCADE)),
22 23
            ],
23 24
            options={
24 25
                'ordering': ('-time',),
corbo/migrations/0004_auto_20160504_1744.py
33 33
        migrations.AlterField(
34 34
            model_name='subscription',
35 35
            name='category',
36
            field=models.ForeignKey(verbose_name='Category', to='corbo.Category'),
36
            field=models.ForeignKey(verbose_name='Category', to='corbo.Category', on_delete=models.CASCADE),
37 37
            preserve_default=True,
38 38
        ),
39 39
        migrations.AlterUniqueTogether(
corbo/models.py
65 65

  
66 66

  
67 67
class Announce(models.Model):
68
    category = models.ForeignKey('Category', verbose_name=_('category'))
68
    category = models.ForeignKey('Category', verbose_name=_('category'),
69
            on_delete=models.CASCADE)
69 70
    title = models.CharField(_('title'), max_length=256,
70 71
                             help_text=_('maximum 256 characters'))
71 72
    identifier = models.CharField(max_length=256, null=True, blank=True)
......
150 151

  
151 152

  
152 153
class Broadcast(models.Model):
153
    announce = models.ForeignKey(Announce, verbose_name=_('announce'))
154
    announce = models.ForeignKey(Announce, verbose_name=_('announce'), on_delete=models.CASCADE)
154 155
    deliver_time = models.DateTimeField(_('Deliver time'), null=True)
155 156
    delivery_count = models.IntegerField(_('Delivery count'), default=0)
156 157

  
......
187 188

  
188 189

  
189 190
class Subscription(models.Model):
190
    category = models.ForeignKey('Category', verbose_name=_('Category'))
191
    category = models.ForeignKey('Category', verbose_name=_('Category'), on_delete=models.CASCADE)
191 192
    uuid = models.CharField(_('User identifier'), max_length=128, blank=True)
192 193
    identifier = models.CharField(_('identifier'), max_length=128, blank=True,
193 194
                                  help_text=_('ex.: mailto, ...'))
corbo/monkeypatch.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from django.core.urlresolvers import reverse
17
from django.urls import reverse
18 18
from django.forms.utils import flatatt
19 19
from django.template.loader import render_to_string
20 20
from django.utils.encoding import force_text
......
24 24

  
25 25
import ckeditor.widgets
26 26

  
27
def ckeditor_render(self, name, value, attrs=None):
27
def ckeditor_render(self, name, value, attrs=None, renderer=None):
28 28
    if value is None:
29 29
        value = ''
30 30
    final_attrs = {'name': name}
31
    if getattr(self, 'attrs', None):
32
        final_attrs.update(self.attrs)
31 33
    if attrs:
32 34
        final_attrs.update(attrs)
33 35
    if 'filebrowserUploadUrl' not in self.config:
corbo/settings.py
42 42
    'rest_framework',
43 43
)
44 44

  
45
MIDDLEWARE_CLASSES = (
45
MIDDLEWARE = (
46 46
    'django.contrib.sessions.middleware.SessionMiddleware',
47 47
    'django.middleware.common.CommonMiddleware',
48 48
    'django.middleware.csrf.CsrfViewMiddleware',
49 49
    'django.contrib.auth.middleware.AuthenticationMiddleware',
50
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
51 50
    'django.contrib.messages.middleware.MessageMiddleware',
52 51
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
53 52
)
corbo/urls.py
8 8
from django.contrib.admin.views.decorators import staff_member_required
9 9

  
10 10
from .urls_utils import decorated_includes, manager_required
11
from .views import homepage, atom, unsubscribe, unsubscription_done, login, logout
11
from .views import homepage, atom, unsubscribe, unsubscription_done, LoginView, LogoutView
12 12

  
13 13
from .manage_urls import urlpatterns as manage_urls
14 14
from .api_urls import urlpatterns as api_urls
......
21 21
    url(r'^atom$', atom, name='atom'),
22 22
    url(r'^manage/', decorated_includes(manager_required,
23 23
                    include(manage_urls))),
24
    url(r'^admin/', include(admin.site.urls)),
24
    url(r'^admin/', admin.site.urls),
25 25
    url(r'^api/', include(api_urls)),
26 26
    url(r'^unsubscribe/done/$', unsubscription_done,
27 27
        name='unsubscription_done'),
28 28
    url(r'^unsubscribe/(?P<unsubscription_token>[\w:-]+)$', unsubscribe,
29 29
        name='unsubscribe'),
30
    url(r'^logout/$', logout, name='auth_logout'),
31
    url(r'^login/$', login, name='auth_login'),
30
    url(r'^logout/$',LogoutView.as_view(), name='auth_logout'),
31
    url(r'^login/$', LoginView.as_view(), name='auth_login'),
32 32
    url(r'^ckeditor/upload/', staff_member_required(ckeditor_views.upload),
33 33
        name='ckeditor_upload'),
34 34
    url(r'^ckeditor/browse/', never_cache(staff_member_required(ckeditor_views.browse)),
corbo/urls_utils.py
16 16

  
17 17
# Decorating URL includes, <https://djangosnippets.org/snippets/2532/>
18 18

  
19
import django
20

  
19 21
from django.contrib.auth.decorators import user_passes_test
20 22
from django.core.exceptions import PermissionDenied
21
from django.core.urlresolvers import RegexURLPattern, RegexURLResolver
22 23

  
23
class DecoratedURLPattern(RegexURLPattern):
24
if django.VERSION < (2, 0, 0):
25
    from django.urls.resolvers import RegexURLPattern as URLPattern
26
    from django.urls.resolvers import RegexURLResolver as URLResolver
27
else:
28
    from django.urls.resolvers import URLPattern, URLResolver
29

  
30

  
31
class DecoratedURLPattern(URLPattern):
24 32
    def resolve(self, *args, **kwargs):
25 33
        result = super(DecoratedURLPattern, self).resolve(*args, **kwargs)
26 34
        if result:
27 35
            result.func = self._decorate_with(result.func)
28 36
        return result
29 37

  
30
class DecoratedRegexURLResolver(RegexURLResolver):
38

  
39
class DecoratedURLResolver(URLResolver):
31 40
    def resolve(self, *args, **kwargs):
32
        result = super(DecoratedRegexURLResolver, self).resolve(*args, **kwargs)
41
        result = super(DecoratedURLResolver, self).resolve(*args, **kwargs)
33 42
        if result:
34 43
            result.func = self._decorate_with(result.func)
35 44
        return result
36 45

  
46

  
37 47
def decorated_includes(func, includes, *args, **kwargs):
38 48
    urlconf_module, app_name, namespace = includes
39 49

  
40 50
    for item in urlconf_module:
41
        if isinstance(item, RegexURLPattern):
51
        if isinstance(item, URLResolver):
52
            item.__class__ = DecoratedURLResolver
53
        else:
42 54
            item.__class__ = DecoratedURLPattern
43
            item._decorate_with = func
44

  
45
        elif isinstance(item, RegexURLResolver):
46
            item.__class__ = DecoratedRegexURLResolver
47
            item._decorate_with = func
55
        item._decorate_with = func
48 56

  
49 57
    return urlconf_module, app_name, namespace
50 58

  
59

  
51 60
def manager_required(function=None, login_url=None):
52 61
    def check_manager(user):
53 62
        if user and user.is_staff:
54 63
            return True
55
        if user and not user.is_anonymous():
64
        if user and not user.is_anonymous:
56 65
            raise PermissionDenied()
57 66
        # As the last resort, show the login form
58 67
        return False
corbo/utils.py
27 27
from django.template import loader
28 28
from django.utils.translation import activate
29 29
from django.core.files.storage import DefaultStorage
30
from django.core.urlresolvers import reverse
30
from django.urls import reverse
31 31
from django.core import signing
32 32
from django.utils.six.moves.urllib import parse as urlparse
33 33

  
corbo/views.py
4 4
from django.contrib import messages
5 5
from django.core import signing
6 6
from django.utils import timezone
7
from django.core.urlresolvers import reverse
7
from django.urls import reverse
8 8
from django.views.generic import CreateView, UpdateView, DeleteView, \
9 9
    ListView, TemplateView, RedirectView, DetailView, FormView
10 10
from django.contrib.syndication.views import Feed
11 11
from django.shortcuts import resolve_url
12
from django.utils.decorators import method_decorator
12 13
from django.utils.encoding import force_text
13 14
from django.utils.feedgenerator import Atom1Feed as DjangoAtom1Feed
14 15
from django.utils.http import quote
......
18 19
from django.contrib import messages
19 20
from django.utils.translation import ugettext_lazy as _
20 21
from django.utils.translation import ngettext
22
from django.views.decorators.cache import never_cache
21 23

  
22 24
from . import models
23 25
from .forms import AnnounceForm, CategoryForm, SubscriptionsImportForm, \
......
30 32
    get_idps = lambda: []
31 33

  
32 34

  
33
def login(request, *args, **kwargs):
34
    if any(get_idps()):
35
        if 'next' not in request.GET:
36
            return HttpResponseRedirect(resolve_url('mellon_login'))
37
        return HttpResponseRedirect(resolve_url('mellon_login') + '?next=' +
38
                                    quote(request.GET.get('next')))
39
    return auth_views.login(request, *args, **kwargs)
35
class LoginView(auth_views.LoginView):
36
    def get(self, request, *args, **kwargs):
37
        if any(get_idps()):
38
            if not 'next' in request.GET:
39
                return HttpResponseRedirect(resolve_url('mellon_login'))
40
            return HttpResponseRedirect(
41
                resolve_url('mellon_login') + '?next=' + quote(request.GET.get('next'))
42
            )
43
        return super(LoginView, self).get(request, *args, **kwargs)
40 44

  
41 45

  
42
def logout(request, next_page=None):
43
    if any(get_idps()):
44
        return HttpResponseRedirect(resolve_url('mellon_logout'))
45
    auth_logout(request)
46
    if next_page is not None:
47
        next_page = resolve_url(next_page)
48
    else:
49
        next_page = '/'
50
    return HttpResponseRedirect(next_page)
46
class LogoutView(auth_views.LogoutView):
47
    @method_decorator(never_cache)
48
    def dispatch(self, request, *args, **kwargs):
49
        if any(get_idps()):
50
            return HttpResponseRedirect(resolve_url('mellon_logout'))
51
        return super(LogoutView, self).dispatch(request, *args, **kwargs)
51 52

  
52 53

  
53 54
class HomepageView(RedirectView):
corbo/widgets.py
83 83

  
84 84
        super(PickerWidgetMixin, self).__init__(attrs, format=self.format)
85 85

  
86
    def render(self, name, value, attrs=None):
86
    def render(self, name, value, attrs=None, renderer=None):
87 87
        final_attrs = self.build_attrs(attrs)
88 88
        rendered_widget = super(PickerWidgetMixin, self).render(name, value, final_attrs)
89 89

  
setup.py
109 109
        'Programming Language :: Python',
110 110
        'Programming Language :: Python :: 2',
111 111
    ],
112
    install_requires=['django>1.7, <1.12',
112
    install_requires=['django>1.7, <2.3',
113 113
        'django-ckeditor<4.5.4',
114
        'djangorestframework>=3.3,<3.7',
114
        'djangorestframework>=3.3,<3.8',
115 115
        'html2text',
116 116
        'gadjo',
117 117
        'emails',
tests/settings.py
1 1
# Add corbo hobo agent
2 2
INSTALLED_APPS = ('corbo.hobo_agent', 'hobo.agent.common') + INSTALLED_APPS
3

  
4
REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ['rest_framework.authentication.BasicAuthentication']
tests/test_announces.py
6 6

  
7 7
from django.core.files.storage import DefaultStorage
8 8
from django.utils import timezone
9
from django.core.urlresolvers import reverse
9
from django.urls import reverse
10 10
from django.conf import settings
11 11
from django.test import override_settings
12 12

  
tests/test_api.py
4 4
from uuid import uuid4
5 5

  
6 6

  
7
from django.core.urlresolvers import reverse
7
from django.urls import reverse
8 8
from django.utils.http import urlencode
9 9
from django.contrib.auth import get_user_model
10 10
from django.utils.text import slugify
......
50 50

  
51 51

  
52 52
def test_get_newsletters(app, categories, announces, user):
53
    resp = app.get(reverse('newsletters'), status=403)
53
    resp = app.get(reverse('newsletters'), status=(401, 403))
54 54
    app.authorization = ('Basic', ('john.doe', 'password'))
55 55
    resp = app.get(reverse('newsletters'))
56 56
    data = resp.json
......
65 65

  
66 66

  
67 67
def test_get_subscriptions(app, categories, announces, user):
68
    resp = app.get(reverse('subscriptions'), status=403)
68
    resp = app.get(reverse('subscriptions'), status=(401, 403))
69 69
    uuid = str(uuid4())
70
    resp = app.get(reverse('subscriptions'), params={'uuid': uuid}, status=403)
70
    resp = app.get(reverse('subscriptions'), params={'uuid': uuid}, status=(401, 403))
71 71
    app.authorization = ('Basic', ('john.doe', 'password'))
72 72

  
73 73
    for identifier, name in channel_choices:
......
105 105
def test_delete_subscriptions(app, categories, announces, user):
106 106
    params = urlencode({'uuid': str(uuid4())})
107 107
    subscriptions_url = reverse('subscriptions') + '?' + params
108
    resp = app.delete(subscriptions_url, status=403)
108
    resp = app.delete(subscriptions_url, status=(401, 403))
109 109
    app.authorization = ('Basic', ('john.doe', 'password'))
110 110
    resp = app.delete(subscriptions_url)
111 111
    if resp.json['data']:
......
119 119
    url = '/api/subscribe/?uuid=%s&email=john@example.net' % uuid
120 120

  
121 121
    # anonymous
122
    resp = app.post_json(url, params=payload, status=403)
122
    resp = app.post_json(url, params=payload, status=(401, 403))
123 123
    assert resp.json['detail'] == 'Authentication credentials were not provided.'
124 124

  
125 125
    # authenticated
tests/test_broadcasting.py
7 7
import random
8 8
import requests
9 9

  
10
from django.core.urlresolvers import reverse
10
from django.urls import reverse
11 11
from django.core import mail, signing
12 12
from django.utils import timezone
13 13
from django.core.files.storage import DefaultStorage
tests/test_data_migrations.py
2 2

  
3 3
import pytest
4 4

  
5
import django
5 6
from django.db import connection
6 7
from django.db.migrations.executor import MigrationExecutor
7 8

  
......
9 10

  
10 11

  
11 12
def test_subscription_sms_identifier_format_migration():
13
    if django.VERSION >= (2, 0, 0):
14
        pytest.skip('NotSupportedError')
12 15
    executor = MigrationExecutor(connection)
13 16
    app = 'corbo'
14 17
    migrate_from = [(app, '0009_auto_20170120_1533')]
tests/test_manager.py
3 3
import os
4 4
import pytest
5 5

  
6
from django.core.urlresolvers import reverse
6
from django.urls import reverse
7 7
from django.contrib.auth.models import User
8 8
from django.test import override_settings
9 9

  
tests/test_subscribers.py
4 4
from webtest import Upload
5 5

  
6 6
from django.utils.text import slugify
7
from django.core.urlresolvers import reverse
7
from django.urls import reverse
8 8
from django.contrib.auth import get_user_model
9 9

  
10 10
from corbo.models import Category, Subscription
tox.ini
1 1
[tox]
2 2
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/corbo/{env:BRANCH_NAME:}
3
envlist = py2-coverage-django111,py3-django111
3
envlist = py2-coverage-django111,py3-django111,py3-django22
4 4

  
5 5
[testenv]
6 6
usedevelop =
......
10 10
  CORBO_SETTINGS_FILE=tests/settings.py
11 11
  coverage: COVERAGE=--junitxml=test_results.xml --cov-report xml --cov-report html --cov=corbo/ --cov-config .coveragerc
12 12
deps =
13
  django>=1.11,<1.12
13
  django111: django>=1.11,<1.12
14
  django22: django>=2.2,<2.3
14 15
  http://git.entrouvert.org/hobo.git/snapshot/hobo-master.tar.gz
15 16
  pytest-cov
16
  pytest-django>=3.1.1,<3.4.6
17
  pytest>=3.0.4
18
  django-webtest<1.9.3
19
  django-ckeditor<4.5.3
20
  djangorestframework>=3.3,<3.7
21
  pylint==1.4.0
22
  astroid==1.3.2
17
  pytest-django
18
  pytest
19
  django-webtest
20
  git+http://git.entrouvert.org/debian/django-ckeditor.git
21
  djangorestframework>=3.3,<3.8
22
  pylint
23
  astroid
23 24
  mock
24 25
commands =
25 26
  py.test {env:COVERAGE:} {posargs:tests/}

Formats disponibles : Unified diff