import secrets from django.views import View from django.views.generic.list import ListView from django.views.generic.detail import DetailView from django.contrib.auth.mixins import UserPassesTestMixin from django.urls import reverse from django.shortcuts import ( render, redirect, get_object_or_404 ) from .forms import ( ImageUploadForm, GalleryCreatingForm, AccessCodeForm, VisitorNameForm ) from .models import ( Image, Visitor, Gallery ) class VisitorSessionMixin(View): def get_visitor(self): if self.request.session: if 'visitor_session' in self.request.session: if Visitor.objects.filter(session_id=self.request.session['visitor_session']).exists(): return Visitor.objects.get(session_id=self.request.session['visitor_session']) else: visitor = Visitor.objects.create() self.request.session['visitor_session'] = visitor.session_id return visitor else: return None def can_access_image(self, image): if image.private: return self.get_visitor() == image.uploaded_by or self.get_visitor() in image.visible_to.all() else: return True def can_access_gallery(self, gallery): if gallery.private: return self.get_visitor() == gallery.created_by or self.get_visitor() in gallery.visitors.all() else: return True def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['visitor'] = self.get_visitor() return context class ImageUploadView(VisitorSessionMixin, View): def get(self, request): form = ImageUploadForm() return render( request, 'upload_image/upload.html', { 'form': form, 'visitor': self.get_visitor() } ) def post(self, request): form = ImageUploadForm( request.POST, request.FILES ) if form.is_valid(): image = form.save(commit=False) if image.private: image.access_code = secrets.token_hex(16) image.uploaded_by = self.get_visitor() image.save() return redirect( reverse('home') ) else: form = ImageUploadForm() return render( request, 'upload_image/upload.html', { 'form': form, 'visitor': self.get_visitor() } ) class PublicImageListView(ListView): model = Image paginate_by = 20 context_object_name = 'images' template_name = 'list_images/image_list.html' def get_queryset(self): return Image.objects.all().filter(private=False).order_by('-uploaded_when')[:10] class MyImagesListView(VisitorSessionMixin, View): def get(self, request): visitor = self.get_visitor() uploaded_images = Image.objects.all().filter( uploaded_by=self.get_visitor() ) shared_images = Image.objects.all().filter( visible_to__in=(visitor, ) ) return render( request, 'image/my_images.html', { 'uploaded_images': uploaded_images, 'shared_images': shared_images, 'visitor': self.get_visitor() } ) class GalleryCreateView(VisitorSessionMixin, View): def get(self, request): form = GalleryCreatingForm() return render( request, 'gallery/create_gallery.html', { 'form': form, 'visitor': self.get_visitor() } ) def post(self, request): form = GalleryCreatingForm( request.POST, request.FILES ) if form.is_valid(): gallery = form.save(commit=False) if gallery.private: gallery.access_code = secrets.token_hex(16) gallery.created_by = self.get_visitor() gallery.save() for image in request.FILES.getlist('images'): imageObject = Image.objects.create( image_file=image, uploaded_by=gallery.created_by, private=gallery.private, access_code=gallery.access_code ) imageObject.galleries.add(gallery) imageObject.save() gallery.save() return redirect( reverse('home') ) else: form = ImageUploadForm() return render( request, 'upload_image/upload.html', { 'form': form, 'visitor': self.get_visitor() } ) class MyGalleriesListView(VisitorSessionMixin, View): def get(self, request): visitor = self.get_visitor() created_galleries = Gallery.objects.all().filter( created_by=self.get_visitor() ) invited_galleries = Gallery.objects.all().filter( visitors__in=(visitor, ) ) return render( request, 'gallery/my_galleries.html', { 'created_galleries': created_galleries, 'invited_galleries': invited_galleries, 'visitor': self.get_visitor() } ) class GalleryDetailView(VisitorSessionMixin, UserPassesTestMixin, DetailView): model = Gallery template_name = 'gallery/gallery_detail.html' context_object_name = 'gallery' def test_func(self): return self.can_access_gallery( self.get_object() ) def handle_no_permission(self): return redirect( reverse( 'gallery_gain_access', kwargs={ 'gallery_id': self.get_object().id } ) ) class ImageDetailView(VisitorSessionMixin, UserPassesTestMixin, DetailView): model = Image template_name = 'image/image_detail.html' context_object_name = 'image' def test_func(self): return self.can_access_image( self.get_object() ) def handle_no_permission(self): return redirect( reverse('home') ) class GainAccessToGalleryView(VisitorSessionMixin, View): def _redirect_to_gallery(self, gallery): return redirect( reverse( 'gallery', kwargs={ 'pk': gallery.id } ) ) def get(self, request, gallery_id): gallery = get_object_or_404( Gallery, id=gallery_id ) if self.can_access_gallery(gallery): return self._redirect_to_gallery(gallery) else: return render( self.request, 'gallery/gallery_no_access.html', { 'form': AccessCodeForm(), 'visitor': self.get_visitor() } ) def post(self, request, gallery_id): gallery = get_object_or_404( Gallery, id=gallery_id ) if self.can_access_gallery(gallery): return self._redirect_to_gallery(gallery) else: form = AccessCodeForm( request.POST ) if form.is_valid(): access_code = form.cleaned_data['access_code'] if access_code == gallery.access_code: gallery.visitors.add(self.get_visitor()) gallery.save() self.get_visitor().save() return self._redirect_to_gallery(gallery) return render( self.request, 'gallery/gallery_no_access.html', { 'form': AccessCodeForm(), 'visitor': self.get_visitor() } ) class RevokeAccessToGallery(VisitorSessionMixin, View): def get(self, request, gallery_id, visitor_id): gallery = get_object_or_404(Gallery, id=gallery_id) visitor = self.get_visitor() if visitor == gallery.created_by: visitor_to_remove = get_object_or_404(Visitor, id=visitor_id) if visitor_to_remove in gallery.visitors.all(): gallery.visitors.remove(visitor_to_remove) gallery.access_code = secrets.token_hex(16) gallery.save() return redirect( reverse( 'gallery', kwargs={ 'pk': gallery.id } ) ) class VisitorSettingsView(VisitorSessionMixin, View): def get(self, request): name_form = VisitorNameForm( initial={ 'name': self.get_visitor().name } ) return render( request, 'visitor/visitor_settings.html', { 'name_form': name_form, 'visitor': self.get_visitor() } ) def post(self, request): name_form = VisitorNameForm( request.POST ) if name_form.is_valid(): visitor = self.get_visitor() visitor.name = name_form.cleaned_data['name'] visitor.save() name_form = VisitorNameForm( initial={ 'name': self.get_visitor().name } ) return render( request, 'visitor/visitor_settings.html', { 'name_form': name_form, 'visitor': self.get_visitor() } )