Make uploading new photos work

This commit is contained in:
Oliver Falk
2018-05-08 15:10:26 +02:00
parent 09486d3385
commit a0b15b1f00
5 changed files with 121 additions and 6 deletions

View File

@@ -48,5 +48,8 @@ MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294
SERVER_EMAIL = 'accounts@ivatar.io' SERVER_EMAIL = 'accounts@ivatar.io'
DEFAULT_FROM_EMAIL = SERVER_EMAIL DEFAULT_FROM_EMAIL = SERVER_EMAIL
MAX_NUM_PHOTOS = 5
MAX_PHOTO_SIZE = 10485760 # in bytes
if os.path.isfile(os.path.join(BASE_DIR, 'config_local.py')): if os.path.isfile(os.path.join(BASE_DIR, 'config_local.py')):
from config_local import * # noqa # flake8: noqa # NOQA # pragma: no cover from config_local import * # noqa # flake8: noqa # NOQA # pragma: no cover

View File

@@ -5,10 +5,12 @@ from django.template.loader import render_to_string
from django.core.mail import send_mail from django.core.mail import send_mail
from ivatar import settings from ivatar import settings
from . models import UnconfirmedEmail, ConfirmedEmail from . models import UnconfirmedEmail, ConfirmedEmail, Photo
from ivatar.settings import MAX_LENGTH_EMAIL from ivatar.settings import MAX_LENGTH_EMAIL
from ipware import get_client_ip
class AddEmailForm(forms.Form): class AddEmailForm(forms.Form):
email = forms.EmailField( email = forms.EmailField(
label=_('Email'), label=_('Email'),
@@ -58,3 +60,33 @@ class AddEmailForm(forms.Form):
send_mail(email_subject, email_body, settings.SERVER_EMAIL, send_mail(email_subject, email_body, settings.SERVER_EMAIL,
[unconfirmed.email]) [unconfirmed.email])
return True return True
class UploadPhotoForm(forms.Form):
photo = forms.FileField(
label=_('Photo'),
error_messages={'required': _('You must choose an image to upload.')})
not_porn = forms.BooleanField(
label=_('suitable for all ages (i.e. no offensive content)'),
required=True,
error_messages={
'required':
_('We only host "G-rated" images and so this field must be checked.')
})
can_distribute = forms.BooleanField(
label=_('can be freely copied'),
required=True,
error_messages={
'required':
_('This field must be checked since we need to be able to distribute photos to third parties.')
})
def save(self, request, data):
# Link this file to the user's profile
photo = Photo()
photo.user = request.user
photo.ip_address = get_client_ip(request)
photo.data = data.read()
if not photo.save():
return None
return photo

View File

@@ -0,0 +1,32 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% block title %}{% trans 'Upload a new photo' %} - ivatar{% endblock title %}
{% block header %}<link rel="prefetch" href="{% static 'css/jcrop.css' %}">
<link rel="prefetch" href="{% static '/js/jcrop.js' %}">{% endblock header %}
{% block content %}
<h1>{% trans 'Upload a new photo' %}</h1>
<form enctype="multipart/form-data" action="{% url 'upload_photo' %}" method="post">{% csrf_token %}
{% if email %}<input type="hidden" name="email" value="{{email}}">{% endif %}
{% if openid %}<input type="hidden" name="openid" value="{{openid}}">{% endif %}
{{ form.photo.errors }}
<p class="aligned wide">{{ form.photo.label_tag }} <input id="id_photo" type="file" name="photo" accept="image/*">
<br>{% blocktrans with max_file_size|filesizeformat as max_size %}Maximum file size of {{ max_size }}.{% endblocktrans %}</p>
<ul class="conditions">
<li>{{ form.not_porn.errors }}{{ form.not_porn }} <label for="id_not_porn">{{ form.not_porn.label }}</label></li>
<li>{{ form.can_distribute.errors }}{{ form.can_distribute }} <label for="id_can_distribute">{{ form.can_distribute.label }}</label></li>
</ul>
<p><input type="submit" value="{% trans 'Upload' %}" />
&nbsp;<a id="cancel-link" href="{% url 'profile' %}">{% trans 'Cancel' %}</a></p>
</form>
{% endblock content %}

View File

@@ -5,7 +5,7 @@ from django.views.generic import TemplateView
from . views import CreateView, PasswordSetView, AddEmailView from . views import CreateView, PasswordSetView, AddEmailView
from . views import RemoveUnconfirmedEmailView, ConfirmEmailView from . views import RemoveUnconfirmedEmailView, ConfirmEmailView
from . views import RemoveConfirmedEmailView, AssignPhotoEmailView from . views import RemoveConfirmedEmailView, AssignPhotoEmailView
from . views import ImportPhotoView, RawImageView from . views import ImportPhotoView, RawImageView, DeletePhotoView, UploadPhotoView
from django.contrib.auth.views import login, logout, password_change, password_change_done from django.contrib.auth.views import login, logout, password_change, password_change_done
from django.urls import reverse_lazy from django.urls import reverse_lazy
@@ -18,13 +18,13 @@ urlpatterns = [
path('profile/', TemplateView.as_view(template_name='profile.html'), name='profile'), path('profile/', TemplateView.as_view(template_name='profile.html'), name='profile'),
path('add_email/', AddEmailView.as_view(), name='add_email'), path('add_email/', AddEmailView.as_view(), name='add_email'),
path('add_openid/', TemplateView.as_view(template_name='add_openid.html'), name='add_openid'), path('add_openid/', TemplateView.as_view(template_name='add_openid.html'), name='add_openid'),
path('upload_photo/', TemplateView.as_view(template_name='upload_photo.html'), name='upload_photo'), path('upload_photo/', UploadPhotoView.as_view(), name='upload_photo'),
path('password_set/', PasswordSetView.as_view(), name='password_set'), path('password_set/', PasswordSetView.as_view(), name='password_set'),
url('confirm_email/(?P<verification_key>\w+)', ConfirmEmailView.as_view(), name='confirm_email'), url('confirm_email/(?P<verification_key>\w+)', ConfirmEmailView.as_view(), name='confirm_email'),
url('remove_unconfirmed_email/(?P<email_id>\d+)', RemoveUnconfirmedEmailView.as_view(), name='remove_unconfirmed_email'), url('remove_unconfirmed_email/(?P<email_id>\d+)', RemoveUnconfirmedEmailView.as_view(), name='remove_unconfirmed_email'),
url('remove_confirmed_email/(?P<email_id>\d+)', RemoveConfirmedEmailView.as_view(), name='remove_confirmed_email'), url('remove_confirmed_email/(?P<email_id>\d+)', RemoveConfirmedEmailView.as_view(), name='remove_confirmed_email'),
url('assign_photo_email/(?P<email_id>\d+)', AssignPhotoEmailView.as_view(), name='assign_photo_email'), url('assign_photo_email/(?P<email_id>\d+)', AssignPhotoEmailView.as_view(), name='assign_photo_email'),
url('import_photo/(?P<email_id>\d+)', ImportPhotoView.as_view(), name='import_photo'), url('import_photo/(?P<email_id>\d+)', ImportPhotoView.as_view(), name='import_photo'),
url('delete_photo/(?P<photo_id>\d+)', TemplateView.as_view(template_name='asdf'), name='delete_photo'), url('delete_photo/(?P<pk>\d+)', DeletePhotoView.as_view(), name='delete_photo'),
url('raw_photo/(?P<pk>[-\w]+)', RawImageView.as_view(), name='raw_image'), url('raw_photo/(?P<pk>[-\w]+)', RawImageView.as_view(), name='raw_image'),
] ]

View File

@@ -14,9 +14,11 @@ from django.utils.translation import ugettext_lazy as _
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse_lazy, reverse from django.urls import reverse_lazy, reverse
from . forms import AddEmailForm from . forms import AddEmailForm, UploadPhotoForm
from . models import UnconfirmedEmail, ConfirmedEmail, Photo from . models import UnconfirmedEmail, ConfirmedEmail, Photo
from ivatar.settings import MAX_NUM_PHOTOS, MAX_PHOTO_SIZE
import io import io
from ipware import get_client_ip from ipware import get_client_ip
@@ -125,7 +127,7 @@ class ConfirmEmailView(SuccessMessageMixin, TemplateView):
confirmed.set_photo(confirmed.user.photos.get()) confirmed.set_photo(confirmed.user.photos.get())
kwargs['photos'] = [ external_photos ] kwargs['photos'] = [ external_photos ]
kwargs['email_id'] = confirmed_id kwargs['email_id'] = confirmed_id
return super(ConfirmEmailView, self).get(*args, **kwargs) return super().get(*args, **kwargs)
class RemoveConfirmedEmailView(SuccessMessageMixin, View): class RemoveConfirmedEmailView(SuccessMessageMixin, View):
@@ -185,3 +187,49 @@ class RawImageView(DetailView):
return HttpResponse( return HttpResponse(
io.BytesIO(photo.data), io.BytesIO(photo.data),
content_type='image/%s' % photo.format) content_type='image/%s' % photo.format)
class DeletePhotoView(SuccessMessageMixin, DetailView):
model = Photo
success_message = _('Photo deleted successfully')
success_url = reverse_lazy('profile')
def get(self, *args, **kwargs):
try:
photo = self.model.objects.get(pk=kwargs['pk'], user=self.request.user)
photo.delete()
except:
messages.error(self.request, _('No such image or no permission to delete it'))
return super().get(*args, **kwargs)
class UploadPhotoView(SuccessMessageMixin, FormView):
model = Photo
template_name = 'upload_photo.html'
form_class = UploadPhotoForm
success_message = _('uploaded successfully')
success_url = reverse_lazy('profile')
def post(self, *args, **kwargs):
num_photos = self.request.user.photo_set.count()
if num_photos >= MAX_NUM_PHOTOS:
messages.error(self.request, _('Maximum number of photos (%i) reached' % MAX_NUM_PHOTOS))
return HttpResponseRedirect(reverse_lazy('profile'))
return super().post(*args, **kwargs)
def form_valid(self, form, *args, **kwargs):
photo_data = self.request.FILES['photo']
if photo_data.size > MAX_PHOTO_SIZE:
messsages.error(self.request, _('Image to big'))
return HttpResponseRedirect(reverse_lazy('profile'))
try:
photo = form.save(self.request, photo_data)
except IOError as e:
print('Error in IO: %s' % e)
messages.error(self.request, _('IO error'))
return HttpResponseRedirect(reverse_lazy('profile'))
if not photo:
messages.error(self.request, _('Invalid Format'))
return HttpResponseRedirect(reverse_lazy('profile'))
return super().form_valid(*args, **kwargs)