diff --git a/assets/index.js b/assets/index.js index b047eb3..eb6b5ec 100644 --- a/assets/index.js +++ b/assets/index.js @@ -416,6 +416,59 @@ function loadAllPhotos(portfIds) { + + + + + + +// Live image upload --------------------------------------- + + +var $liveImageUploadContainer = $('.-live-image-upload-container').first() + +var $avatarImage = $liveImageUploadContainer.find('.-avatar-image').first() +var $liveImageUpload = $liveImageUploadContainer.find('.-live-image-upload').first() +var $liveImageId = $liveImageUploadContainer.find('.-live-image-id').first() +var $liveImageDelete = $liveImageUploadContainer.find('.-live-image-delete').first() +var stubImageUrl = $liveImageUploadContainer.data('stubImageUrl') + +$liveImageUpload.fileupload({ + dataType: 'json', + + done: function($evt, data) { + var image = data.result.files[0] + + $avatarImage.attr('src', image.thumbnailUrl) + $liveImageId.val(image.id) + + $liveImageDelete.data('url', image.deleteUrl) + $liveImageDelete.css('display', 'block') + } +}) + +$liveImageDelete.on('click', function($evt) { + var $that = $(this) + + $.post($that.data('url')).then(function(res) { + if (res.status == 'success') { + $avatarImage.attr('src', stubImageUrl) + $liveImageId.val('') + $that.css('display', 'none') + } + }) +}) + + + + + + + + + + + // Helpers --------------------------------------------- diff --git a/common/admin.py b/common/admin.py index 5bda06c..47229b9 100644 --- a/common/admin.py +++ b/common/admin.py @@ -3,7 +3,15 @@ from django.contrib import admin from mptt.admin import MPTTModelAdmin import pydash as _; _.map = _.map_; _.filter = _.filter_ -from .models import Location, MainPage, Settings, PrintOrder, PrintDocuments, Tooltip +from .models import ( + LiveImageUpload, + Location, + MainPage, + PrintDocuments, + PrintOrder, + Settings, + Tooltip, +) class LocationAdmin(MPTTModelAdmin): @@ -59,6 +67,7 @@ class TooltipAdmin(admin.ModelAdmin): form = TooltipAdminForm +admin.site.register(LiveImageUpload) admin.site.register(Location, LocationAdmin) admin.site.register(MainPage, MainPageAdmin) admin.site.register(PrintDocuments) diff --git a/common/mixins.py b/common/mixins.py new file mode 100644 index 0000000..3d4fd79 --- /dev/null +++ b/common/mixins.py @@ -0,0 +1,9 @@ +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt +from django.views.generic import View + + +class NoCsrfMixin(View): + @method_decorator(csrf_exempt) + def dispatch(self, request, *args, **kwargs): + return super().dispatch(request, *args, **kwargs) diff --git a/common/models.py b/common/models.py index cba295b..90ca520 100644 --- a/common/models.py +++ b/common/models.py @@ -112,7 +112,8 @@ class LiveImageUpload(models.Model): created_at = models.DateTimeField(default=timezone.now) class Meta: - verbose_name = 'LiveImageUpload' + verbose_name = 'Живая загрузка изображений' + verbose_name_plural = 'Живая загрузка изображений' def __str__(self): return self.file.url diff --git a/common/views.py b/common/views.py index 93a641f..ca08433 100644 --- a/common/views.py +++ b/common/views.py @@ -1,12 +1,12 @@ from django.contrib import messages +from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import Group +from django.core.exceptions import PermissionDenied 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 registration.backends.default.views import RegistrationView import json @@ -16,6 +16,7 @@ from .forms import PrintOrderForm, CustomRegistrationForm from .models import PrintDocuments, PrintOrder, Settings, LiveImageUpload from archilance import util from archilance.mixins import BaseMixin +from common.mixins import NoCsrfMixin from users.models import ContractorResume @@ -81,100 +82,36 @@ class PrintDocumentCreate(BaseMixin, View): -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 LiveImageUploadCreateView(NoCsrfMixin, LoginRequiredMixin, View): + def post(self, request, *args, **kwargs): + image = request.FILES.get('image') + + if not image: + return JsonResponse({'files': [{'error': 'No image provided'}]}) + + live_img = LiveImageUpload.objects.create(file=image) + + return JsonResponse({'files': [{ + 'id': live_img.pk, + 'name': live_img.file.name, + 'size': live_img.file.size, + 'url': live_img.file.url, + 'thumbnailUrl': live_img.file.url, + 'deleteUrl': reverse('common:live-image-upload-delete', kwargs={'pk': live_img.pk}), + 'deleteType': 'POST', + }]}) + + +class LiveImageUploadDeleteView(NoCsrfMixin, LoginRequiredMixin, View): + def post(self, request, *args, **kwargs): + live_img = util.get_or_none(LiveImageUpload, pk=kwargs.get('pk')) + + if live_img: + live_img.file.delete() + live_img.delete() + return JsonResponse({'status': 'success'}) + else: + return JsonResponse({'status': 'failure'}) class CustomRegistrationView(RegistrationView): diff --git a/users/forms.py b/users/forms.py index 39d8d00..725310b 100644 --- a/users/forms.py +++ b/users/forms.py @@ -3,7 +3,7 @@ import itertools import pydash as _; _.map = _.map_; _.filter = _.filter_ from .models import User, UserFinancialInfo, Team, ContractorResume, ContractorResumeFiles, GENDERS -from common.models import Location +from common.models import Location, LiveImageUpload from projects.models import Project, Realty, BuildingClassfication, ConstructionType from specializations.models import Specialization @@ -36,7 +36,6 @@ class ContractorResumeFilesForm(forms.ModelForm): ) - class UserProfileEditForm(forms.ModelForm): gender = forms.ChoiceField( choices=GENDERS, @@ -44,11 +43,15 @@ class UserProfileEditForm(forms.ModelForm): required=False, ) + live_image = forms.ModelChoiceField( + queryset=LiveImageUpload.objects.all(), + required=False, + ) + class Meta: model = User fields = ( - # 'avatar', #........................... 'contractor_specializations', 'cro', 'date_of_birth', @@ -73,11 +76,15 @@ class UserProfileEditForm(forms.ModelForm): class UserProfileBasicInfoEditForm(forms.ModelForm): + live_image = forms.ModelChoiceField( + queryset=LiveImageUpload.objects.all(), + required=False, + ) + class Meta: model = User fields = ( - 'avatar', 'contractor_specializations', 'first_name', 'last_name', diff --git a/users/templates/user_financial_info_edit.html b/users/templates/user_financial_info_edit.html index 51f1721..fa3f314 100644 --- a/users/templates/user_financial_info_edit.html +++ b/users/templates/user_financial_info_edit.html @@ -3,6 +3,19 @@ {% load thumbnail %} +{% block head_css %} + +{% endblock %} + {% block content %} {% include 'partials/header.html' %} @@ -19,25 +32,34 @@
+ ФИО
@@ -52,7 +74,7 @@Специализации
ФИО
@@ -171,19 +187,3 @@