From 5d125ea8e4bfcec4fc2050f420a89dd9fd727c39 Mon Sep 17 00:00:00 2001 From: Alexander Burdeiny Date: Thu, 23 Jun 2016 13:25:20 +0300 Subject: [PATCH] =?UTF-8?q?1384:=20=D0=AD=D1=82=D0=B0=D0=BF=20=E2=84=964?= =?UTF-8?q?=20-=20=D0=98=D0=BC=D1=8F=20URLa=20=D0=B2=D1=8B=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fabfile.py | 14 ++++++- functions/custom_views.py | 26 ++++++++++++ functions/http.py | 30 +++++++++++++ redirects/admin.py | 25 ++++++++++- redirects/admin_urls.py | 9 +++- redirects/forms.py | 36 ++++++++++++++++ .../admin/conference/conference_list.html | 33 +++++++++------ .../admin/exposition/exposition_list.html | 34 +++++++++------ .../admin/redirects/newurlforobject.html | 42 +++++++++++++++++++ 9 files changed, 219 insertions(+), 30 deletions(-) create mode 100644 functions/http.py create mode 100644 templates/admin/redirects/newurlforobject.html diff --git a/fabfile.py b/fabfile.py index 4db2df27..c0cbc327 100644 --- a/fabfile.py +++ b/fabfile.py @@ -129,9 +129,21 @@ def c_fix(): call_state('start', only='apache2') -def stage4(): +def stage4_firstrun(): with cd(REMOTE_HOME_DIR): run('git fetch') run('git checkout stage4') run('git checkout -- proj/settings.py') pull(with_configs=True) + run('python manage.py syncdb') + + +def stage4(): + with cd(REMOTE_HOME_DIR): + run('python manage.py syncdb') + + +def ticket1395(): + # stage4 + with cd(REMOTE_HOME_DIR): + run('python manage.py accounts_check_url') diff --git a/functions/custom_views.py b/functions/custom_views.py index 5521f0ec..28231fb1 100644 --- a/functions/custom_views.py +++ b/functions/custom_views.py @@ -474,3 +474,29 @@ class BlockedFilterMixin(object): def get_queryset(self): qs = super(BlockedFilterMixin, self).get_queryset() return qs.filter(blocked=False) + + +class AjaxableResponseMixin(object): + """ + Mixin to add AJAX support to a form. + Must be used with an object-based FormView (e.g. CreateView) + """ + def form_invalid(self, form): + response = super(AjaxableResponseMixin, self).form_invalid(form) + if self.request.is_ajax(): + return JsonResponse(form.errors, status=400) + else: + return response + + def form_valid(self, form): + # We make sure to call the parent's form_valid() method because + # it might do some processing (in the case of CreateView, it will + # call form.save() for example). + response = super(AjaxableResponseMixin, self).form_valid(form) + if self.request.is_ajax(): + data = { + 'pk': self.object.pk, + } + return JsonResponse(data) + else: + return response diff --git a/functions/http.py b/functions/http.py new file mode 100644 index 00000000..255710c1 --- /dev/null +++ b/functions/http.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +import json + +from django.core.serializers.json import DjangoJSONEncoder +from django.http import HttpResponse + + +class JsonResponse(HttpResponse): + """ + An HTTP response class that consumes data to be serialized to JSON. + :param data: Data to be dumped into json. By default only ``dict`` objects + are allowed to be passed due to a security flaw before EcmaScript 5. See + the ``safe`` parameter for more information. + :param encoder: Should be an json encoder class. Defaults to + ``django.core.serializers.json.DjangoJSONEncoder``. + :param safe: Controls if only ``dict`` objects may be serialized. Defaults + to ``True``. + :param json_dumps_params: A dictionary of kwargs passed to json.dumps(). + """ + + def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, + json_dumps_params=None, **kwargs): + if safe and not isinstance(data, dict): + raise TypeError('In order to allow non-dict objects to be ' + 'serialized set the safe parameter to False') + if json_dumps_params is None: + json_dumps_params = {} + kwargs.setdefault('content_type', 'application/json') + data = json.dumps(data, cls=encoder, **json_dumps_params) + super(JsonResponse, self).__init__(content=data, **kwargs) diff --git a/redirects/admin.py b/redirects/admin.py index b12f3c50..8a6510c3 100644 --- a/redirects/admin.py +++ b/redirects/admin.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- from django.contrib.redirects.models import Redirect -from django.views.generic import CreateView, DeleteView, ListView, UpdateView from django.core.urlresolvers import reverse_lazy +from django.views.generic import CreateView, DeleteView, ListView, UpdateView +from functions.custom_views import AjaxableResponseMixin +from functions.form_check import translit_with_separator +from functions.http import JsonResponse -from .forms import RedirectForm +from .forms import RedirectForm, NewUrlForObjectForm ############################################################################### @@ -35,3 +38,21 @@ class RedirectDelete(RedirectMixin, DeleteView): def get(self, request, *args, **kwargs): return self.post(request, *args, **kwargs) + +class NewUrlForObject(AjaxableResponseMixin, UpdateView): + template_name = 'admin/redirects/newurlforobject.html' + context_object_name = 'object' + form_class = NewUrlForObjectForm + slug_field = 'url' + + def get_initial(self): + new_url = translit_with_separator(self.object.name.strip()).lower() + return { + 'old_url': self.object.url, + 'new_url': new_url, + 'old_path': self.object.get_permanent_url(), + 'new_path': '%s%s/' % (self.object.get_catalog_url(), new_url), + } + + def get_success_url(self): + return self.object.get_permanent_url() diff --git a/redirects/admin_urls.py b/redirects/admin_urls.py index 50c5f027..556da96d 100644 --- a/redirects/admin_urls.py +++ b/redirects/admin_urls.py @@ -1,11 +1,18 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url from .admin import * - +from conference.models import Conference +from exposition.models import Exposition urlpatterns = patterns('redirects.admin', + # Redirects url(r'^$', RedirectList.as_view(), name='redirects-list'), url(r'^add/$', RedirectCreate.as_view(), name='redirects-add'), url(r'^(?P\d+)/edit/$', RedirectUpdate.as_view(), name='redirects-edit'), url(r'^(?P\d+)/delete/$', RedirectDelete.as_view(), name='redirects-delete'), + + # Generate new url for objects (conference/exposition) + url(r'^expo/(?P.*)/$', NewUrlForObject.as_view(model=Exposition), name='redirects-add-expo'), + url(r'^conf/(?P.*)/$', NewUrlForObject.as_view(model=Conference), name='redirects-add-conf'), + ) diff --git a/redirects/forms.py b/redirects/forms.py index 56d78e6c..2463bf23 100644 --- a/redirects/forms.py +++ b/redirects/forms.py @@ -18,3 +18,39 @@ class RedirectForm(forms.ModelForm): if commit: obj.save() return obj + + +class NewUrlForObjectForm(forms.Form): + verbose = _(u'Обновление URL и cоздание редиректа') + + old_url = forms.CharField(label=_(u'Текущая ссылка')) + new_url = forms.CharField(label=_(u'Новая ссылка')) + + def __init__(self, *args, **kwargs): + self.instance = kwargs.pop('instance', None) + super(NewUrlForObjectForm, self).__init__(*args, **kwargs) + + @property + def exist(self): + return Redirect.objects.filter(old_path=self.instance.get_permanent_url()).exists() + + def clean_new_url(self): + if self.cleaned_data['new_url'] == self.cleaned_data['old_url']: + raise forms.ValidationError( + _(u'Старый и новый URL совпадают.'), + code='invalid' + ) + return self.cleaned_data['new_url'] + + def save(self): + old_path = self.instance.get_permanent_url() + self.instance.url = self.cleaned_data['new_url'] + self.instance.save() + obj, created = Redirect.objects.get_or_create( + old_path=old_path, + defaults={ + 'new_path': self.instance.get_permanent_url(), + 'site_id': settings.SITE_ID, + }) + return self.instance + diff --git a/templates/admin/conference/conference_list.html b/templates/admin/conference/conference_list.html index a88ab8f8..76c43f35 100644 --- a/templates/admin/conference/conference_list.html +++ b/templates/admin/conference/conference_list.html @@ -1,7 +1,7 @@ {% extends 'admin_list.html' %} {% load static %} - +{% load i18n %} {% block styles %} @@ -18,13 +18,13 @@ td a{
-

Фильтры

+

{% trans "Фильтры" %}

{{ form }} - +
@@ -32,7 +32,7 @@ td a{
-

Список конференций

+

{% trans "Список конференций" %}

{# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} diff --git a/templates/admin/exposition/exposition_list.html b/templates/admin/exposition/exposition_list.html index 15d884ab..a90a9561 100644 --- a/templates/admin/exposition/exposition_list.html +++ b/templates/admin/exposition/exposition_list.html @@ -1,4 +1,5 @@ {% extends 'admin_list.html' %} +{% load i18n %} {% block styles %} @@ -16,20 +17,20 @@ td a{
-

Фильтры

+

{% trans "Фильтры" %}

{{ form }} - +
-

Список выставок

+

{% trans "Список выставок" %}

{# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} diff --git a/templates/admin/redirects/newurlforobject.html b/templates/admin/redirects/newurlforobject.html new file mode 100644 index 00000000..cba611ae --- /dev/null +++ b/templates/admin/redirects/newurlforobject.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block body %} +
{% csrf_token %} +
+
+
+

{{ form.verbose }}

+
+ +
+ + {% for field in form %} +
+ +
{{ field }} + {{ field.errors }} +
+
+ {% endfor %} + + {% if form.exist %} +
+ {% blocktrans with url=object.get_permanent_url %} + Редирект по с такого URL {{ url }} уже сущесвтует. +
В случае сохранения будет перезаписан. + {% endblocktrans %} +
+ {% endif %} + +
+
+
+ +
+ + +
+
+{% endblock %}