mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-11 18:56:23 +00:00
Make uploading new photos work
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
32
ivatar/ivataraccount/templates/upload_photo.html
Normal file
32
ivatar/ivataraccount/templates/upload_photo.html
Normal 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' %}" />
|
||||||
|
<a id="cancel-link" href="{% url 'profile' %}">{% trans 'Cancel' %}</a></p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
@@ -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'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user