From 619202555ae9169042fe55ace63e061589abdd32 Mon Sep 17 00:00:00 2001 From: ArturBaybulatov Date: Mon, 5 Sep 2016 10:27:38 +0300 Subject: [PATCH 1/2] Fixes --- templates/partials/base.html | 1 + users/templates/user_profile_edit.html | 15 ++++++++++++++- wallets/migrations/0015_auto_20160902_1904.py | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 wallets/migrations/0015_auto_20160902_1904.py diff --git a/templates/partials/base.html b/templates/partials/base.html index a003b54..fd0ee30 100644 --- a/templates/partials/base.html +++ b/templates/partials/base.html @@ -68,6 +68,7 @@ + diff --git a/users/templates/user_profile_edit.html b/users/templates/user_profile_edit.html index 68a31b4..f54acd1 100644 --- a/users/templates/user_profile_edit.html +++ b/users/templates/user_profile_edit.html @@ -33,7 +33,7 @@ @@ -165,3 +165,16 @@ {% endblock %} + +{% block js_block %} + +{% endblock %} diff --git a/wallets/migrations/0015_auto_20160902_1904.py b/wallets/migrations/0015_auto_20160902_1904.py new file mode 100644 index 0000000..06d38fe --- /dev/null +++ b/wallets/migrations/0015_auto_20160902_1904.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-02 16:04 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallets', '0014_payfromscore'), + ] + + operations = [ + migrations.AlterModelOptions( + name='payfromscore', + options={'ordering': ('-created_at',), 'verbose_name': 'Оплата со счета', 'verbose_name_plural': 'Оплата со счета'}, + ), + ] From c9a83c0b05437a3411fa88422c23b03bc7a837dd Mon Sep 17 00:00:00 2001 From: ArturBaybulatov Date: Mon, 5 Sep 2016 21:31:03 +0300 Subject: [PATCH 2/2] Fixes --- archilance/settings/base.py | 15 +- archilance/urls.py | 4 + archilance/util.py | 11 ++ common/forms.py | 25 +++ common/migrations/0013_liveimageupload.py | 27 ++++ common/models.py | 11 ++ common/urls.py | 5 + common/views.py | 153 +++++++++++++++++- projects/models.py | 5 +- templates/partials/base.html | 2 +- templates/registration/registration_form.html | 37 +++-- users/forms.py | 2 +- users/signals.py | 25 ++- users/templates/user_profile_edit.html | 41 +++-- 14 files changed, 295 insertions(+), 68 deletions(-) create mode 100644 common/migrations/0013_liveimageupload.py diff --git a/archilance/settings/base.py b/archilance/settings/base.py index 61049ad..8e645a1 100644 --- a/archilance/settings/base.py +++ b/archilance/settings/base.py @@ -1,4 +1,3 @@ -from django.core.files.storage import FileSystemStorage import os @@ -318,16 +317,4 @@ else: WAGTAIL_SITE_NAME = 'PROEKTON' -REGISTRATION_FORM = 'registration.forms.RegistrationFormTermsOfService' - - -# class ASCIIFileSystemStorage(FileSystemStorage): -# def get_valid_name(self, name): -# symbols = (u"абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", -# u"abvgdeejzijklmnoprstufhzcss_y_euaABVGDEEJZIJKLMNOPRSTUFHZCSS_Y_EUA") -# -# tr = {ord(a):ord(b) for a, b in zip(*symbols)} -# name = name.translate(tr) -# return super().get_valid_name(name) -# -# DEFAULT_FILE_STORAGE = ASCIIFileSystemStorage +DEFAULT_FILE_STORAGE = 'archilance.util.ASCIIFileSystemStorage' diff --git a/archilance/urls.py b/archilance/urls.py index c50d9fd..8dcf2d2 100644 --- a/archilance/urls.py +++ b/archilance/urls.py @@ -6,6 +6,7 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.views.generic import TemplateView from .views import HomeTemplateView, TestChatTemplateView, TestView +from common.views import CustomRegistrationView from wallets.views import TmpCheckOrderView, TmpPaymentAvisoView from wagtail.wagtailadmin import urls as wagtailadmin_urls @@ -26,7 +27,10 @@ urlpatterns = [ url(r'^users/', include('users.urls')), url(r'^common/', include('common.urls')), url(r'^password/', include('password_reset.urls')), + + url(r'^users/register/$', CustomRegistrationView.as_view(), name='registration_register'), url(r'^users/', include('registration.backends.default.urls')), + url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), url(r'^cms/', include(wagtailadmin_urls)), diff --git a/archilance/util.py b/archilance/util.py index d063c88..a77321a 100644 --- a/archilance/util.py +++ b/archilance/util.py @@ -1,5 +1,6 @@ from django.core import validators from django.core.exceptions import ObjectDoesNotExist +from django.core.files.storage import FileSystemStorage from django.shortcuts import _get_queryset from django.utils import timezone from pprint import pprint, pformat @@ -151,3 +152,13 @@ def morph(number, words): # # for i in range(0, 30): # print(i, morph(i, words)) + + +class ASCIIFileSystemStorage(FileSystemStorage): + def get_valid_name(self, name): + symbols = (u"абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", + u"abvgdeejzijklmnoprstufhzcss_y_euaABVGDEEJZIJKLMNOPRSTUFHZCSS_Y_EUA") + + tr = {ord(a):ord(b) for a, b in zip(*symbols)} + name = name.translate(tr) + return super().get_valid_name(name) diff --git a/common/forms.py b/common/forms.py index 80b0cc3..a523979 100644 --- a/common/forms.py +++ b/common/forms.py @@ -1,4 +1,7 @@ from django import forms +from registration.forms import RegistrationFormTermsOfService +import pydash as _; _.map = _.map_; _.filter = _.filter_ + from .models import PrintOrder, PrintDocuments @@ -26,3 +29,25 @@ class PrintOrderForm(forms.ModelForm): super().__init__(*args, **kwargs) if self.instance.pk: self.fields['files'].queryset = self.instance.files + + +class CustomRegistrationForm(RegistrationFormTermsOfService): + USER_TYPES = ( + ('', 'Выберите роль'), + ('customer', 'Заказчик'), + ('contractor', 'Исполнитель'), + ) + + user_type = forms.ChoiceField(choices=USER_TYPES) + + def __init__(self, *args, **kwargs): + self.request = kwargs.pop('request') + super().__init__(*args, **kwargs) + + if self.request.GET.get('type') == 'customer': + self.fields['user_type'].initial = 'customer' + elif self.request.GET.get('type') == 'contractor': + self.fields['user_type'].initial = 'contractor' + + attrs = self.fields['user_type'].widget.attrs + attrs['class'] = _.join(_.compact((attrs.get('class'), 'selectpicker3')), ' ') diff --git a/common/migrations/0013_liveimageupload.py b/common/migrations/0013_liveimageupload.py new file mode 100644 index 0000000..e66769d --- /dev/null +++ b/common/migrations/0013_liveimageupload.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-09-05 11:55 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0012_auto_20160901_2007'), + ] + + operations = [ + migrations.CreateModel( + name='LiveImageUpload', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file', models.ImageField(upload_to='live-image-upload/')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now)), + ], + options={ + 'verbose_name': 'LiveImageUpload', + }, + ), + ] diff --git a/common/models.py b/common/models.py index 5cba652..cba295b 100644 --- a/common/models.py +++ b/common/models.py @@ -105,3 +105,14 @@ class Tooltip(models.Model): def __str__(self): return self.name + + +class LiveImageUpload(models.Model): + file = models.ImageField(upload_to='live-image-upload/') + created_at = models.DateTimeField(default=timezone.now) + + class Meta: + verbose_name = 'LiveImageUpload' + + def __str__(self): + return self.file.url diff --git a/common/urls.py b/common/urls.py index 10e2318..f4dd1c9 100644 --- a/common/urls.py +++ b/common/urls.py @@ -3,6 +3,8 @@ from django.conf import urls from .views import ( PrintDocumentCreate, PrintOrderDetailView, + LiveImageUploadCreateView, + LiveImageUploadDeleteView, ) app_name = 'common' @@ -10,4 +12,7 @@ app_name = 'common' urlpatterns = [ urls.url(r'^printdocument/create/$', PrintDocumentCreate.as_view(), name='create'), urls.url(r'^printorder/(?P\d+)/$', PrintOrderDetailView.as_view(), name='print-order-detail'), + + urls.url(r'^live-image-upload/create/$', LiveImageUploadCreateView.as_view(), name='live-image-upload-create'), + urls.url(r'^live-image-upload/(?P\d+)/delete/$', LiveImageUploadDeleteView.as_view(), name='live-image-upload-delete'), ] diff --git a/common/views.py b/common/views.py index 1729bb3..93a641f 100644 --- a/common/views.py +++ b/common/views.py @@ -1,12 +1,22 @@ -from django.shortcuts import render, redirect from django.contrib import messages +from django.contrib.auth.models import Group from django.core.mail import send_mail, EmailMultiAlternatives +from django.core.urlresolvers import reverse, reverse_lazy +from django.http import JsonResponse +from django.shortcuts import render, redirect from django.template.loader import get_template, render_to_string +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt from django.views.generic import View, DetailView -from archilance.mixins import BaseMixin +from registration.backends.default.views import RegistrationView +import json +import jsonschema -from .forms import PrintOrderForm -from .models import PrintDocuments, PrintOrder, Settings +from .forms import PrintOrderForm, CustomRegistrationForm +from .models import PrintDocuments, PrintOrder, Settings, LiveImageUpload +from archilance import util +from archilance.mixins import BaseMixin +from users.models import ContractorResume class PrintOrderDetailView(DetailView): @@ -68,3 +78,138 @@ class PrintDocumentCreate(BaseMixin, View): context = self.get_context_data(**kwargs) context.update({'form': form}) return render(request, self.template_name, context) + + + +class LiveImageUploadCreateView(View): + @method_decorator(csrf_exempt) + def dispatch(self, request, *args, **kwargs): + return super().dispatch(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + # try: data = json.loads(request.body.decode('utf-8')) + # except: data = {} + # + # crop = data.get('crop') + # image_id = data.get('imageId') + # + # if crop and image_id: + # old_pic = util.get_or_none(models.TmpAdvertPicture, pk=image_id) + # + # if old_pic: + # try: img = pil.Image.open(old_pic.file) + # except IOError: return http.JsonResponse({'files': [{'error': "Couldn't open an image"}]}) + # + # format = img.format + # + # # exif = img._getexif() + # # + # # if exif: + # # orientation_exif_tag = 274 + # # rotated_img = img.rotate({3: 180, 6: 270, 8: 90}[exif[orientation_exif_tag]]) + # + # rotation = -crop.get('rotate') + # + # if rotation: + # img = img.rotate(rotation, expand=True) + # + # x, y = crop.get('x'), crop.get('y') + # x2, y2 = x + crop.get('width'), y + crop.get('height') + # + # cropped_img = img.crop((x, y, x2, y2)) # Left, upper, right, lower + # + # with io.BytesIO() as f: + # cropped_img.save(f, format=format) + # pic = models.TmpAdvertPicture.objects.create() + # pic.file.save(old_pic.file.name, ContentFile(f.getvalue())) + # pic.save() + # + # old_pic.file.delete() + # old_pic.delete() + # else: + # return http.JsonResponse({'files': [{'error': 'No image found'}]}) + # else: + # image = request.FILES.get('_images') + # + # if image: + # pic = models.TmpAdvertPicture.objects.create(file=image) + # else: + # return http.JsonResponse({'files': [{'error': 'No image provided'}]}) + + + #------------------------------------------------ + + print('###########################################') + print('Uploading a file...') + print('###########################################') + + image = request.FILES.get('image') + + if image: + img = LiveImageUpload.objects.create(file=image) + else: + return JsonResponse({'files': [{'error': 'No image provided'}]}) + + return JsonResponse({'files': [{ + 'id': img.pk, + 'name': img.file.name, + 'size': img.file.size, + 'url': img.file.url, + 'thumbnailUrl': img.file.url, + 'deleteUrl': reverse('common:live-image-upload-delete', kwargs={'pk': img.pk}), + 'deleteType': 'POST', + }]}) + + +class LiveImageUploadDeleteView(View): + @method_decorator(csrf_exempt) + def dispatch(self, request, *args, **kwargs): + return super().dispatch(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + img = util.get_or_none(LiveImageUpload, pk=kwargs.get('pk')) + + if img: + img.file.delete() + img.delete() + return JsonResponse({'success': True}) + else: + return JsonResponse({'success': False}) + + +class CustomRegistrationView(RegistrationView): + form_class = CustomRegistrationForm + template_name = 'registration/registration_form.html' + success_url = reverse_lazy('registration_complete') + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs['request'] = self.request + return kwargs + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + if self.request.GET.get('type') in ('customer', 'contractor'): + context['hide_user_type'] = True + + return context + + def register(self, form): + user = super().register(form) + + if form.cleaned_data.get('customer'): + group = Group.objects.get(name='Заказчики') + elif form.cleaned_data.get('contractor'): + group = Group.objects.get(name='Исполнители') + else: + group = None + + if group: + user.groups.add(group) + + user.contractor_resume = ContractorResume.objects.create(text='') + + user.save() + + return user diff --git a/projects/models.py b/projects/models.py index 5136c1e..f7f23e4 100644 --- a/projects/models.py +++ b/projects/models.py @@ -147,7 +147,10 @@ class Answer(models.Model): author = GenericForeignKey('content_type', 'object_id') def get_first_message(self): - return self.messages.first().text + message = self.messages.first() + + if message: + return message.text def __str__(self): return "{author}'s answer ({id})".format(author=type(self.author).__name__, id=self.pk) diff --git a/templates/partials/base.html b/templates/partials/base.html index 3e6abc6..92f9846 100644 --- a/templates/partials/base.html +++ b/templates/partials/base.html @@ -93,7 +93,7 @@ var sock = new WebSocket(url); var intervalId; sock.onopen = function () { - console.log("Start connect"); + //console.log("Start connect"); intervalId = setInterval(function () { sock.send('{"dummy": 1}'); }, 15000); diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html index 0177e0e..b7e096f 100644 --- a/templates/registration/registration_form.html +++ b/templates/registration/registration_form.html @@ -8,22 +8,27 @@
{% csrf_token %} - {{ form.non_field_errors }} -
- {% if request.GET.type == 'customer' %} - - {% elif request.GET.type == 'contractor' %} - - {% else %} -
- -
- {% endif %} -
+ {{ form.non_field_errors }} + + {% if not hide_user_type %} +
+{# {% if request.GET.type == 'customer' %}#} +{# #} +{# {% elif request.GET.type == 'contractor' %}#} +{# #} +{# {% else %}#} +{# #} +{# {% endif %}#} + + {{ form.user_type }} + {{ form.user_type.errors }} +
+ {% endif %} +
diff --git a/users/forms.py b/users/forms.py index 7917c68..39d8d00 100644 --- a/users/forms.py +++ b/users/forms.py @@ -48,7 +48,7 @@ class UserProfileEditForm(forms.ModelForm): model = User fields = ( - 'avatar', + # 'avatar', #........................... 'contractor_specializations', 'cro', 'date_of_birth', diff --git a/users/signals.py b/users/signals.py index e78c6ef..62ad97b 100644 --- a/users/signals.py +++ b/users/signals.py @@ -3,18 +3,13 @@ from django.contrib.auth.models import Group from registration.signals import user_registered from users.models import ContractorResume -@receiver(user_registered) -def user_registered_callback(sender, user, request, **kwargs): - # import code; code.interact(local=dict(globals(), **locals())) - group_name = request.POST['group_id'] or 'Исполнители' - g = Group.objects.get(name=group_name) - g.user_set.add(user) - if group_name == 'Исполнители': - resume = ContractorResume.objects.create(text='') - user.contractor_resume = resume - user.save() - - - - - +# @receiver(user_registered) +# def user_registered_callback(sender, user, request, **kwargs): +# # import code; code.interact(local=dict(globals(), **locals())) +# group_name = request.POST['group_id'] or 'Исполнители' +# g = Group.objects.get(name=group_name) +# g.user_set.add(user) +# if group_name == 'Исполнители': +# resume = ContractorResume.objects.create(text='') +# user.contractor_resume = resume +# user.save() diff --git a/users/templates/user_profile_edit.html b/users/templates/user_profile_edit.html index f54acd1..4d3e5f1 100644 --- a/users/templates/user_profile_edit.html +++ b/users/templates/user_profile_edit.html @@ -19,24 +19,30 @@
-
+
- {% if form.avatar.value %} - {% thumbnail form.avatar.value "235x224" crop="center" as im %} - profile-image + {% if request.user.avatar %} + {% thumbnail request.user.avatar "235x224" crop="center" as avatar %} + profile-image {% endthumbnail %} {% else %} - profile-image + profile-image {% endif %}
- + +{# #} +{# #} +{#
#} +{# #} +{#
#}
@@ -168,12 +174,15 @@ {% block js_block %}