bgneal@695
|
1 """Views for the user_photos application."""
|
bgneal@722
|
2 import json
|
bgneal@722
|
3
|
bgneal@695
|
4 from django.conf import settings
|
bgneal@704
|
5 from django.contrib.auth import get_user_model
|
bgneal@695
|
6 from django.contrib.auth.decorators import login_required
|
bgneal@722
|
7 from django.http import (HttpResponse, HttpResponseForbidden,
|
bgneal@971
|
8 HttpResponseNotAllowed, JsonResponse)
|
bgneal@704
|
9 from django.shortcuts import render, redirect, get_object_or_404
|
bgneal@1158
|
10 from django.views.generic import DetailView
|
bgneal@704
|
11 from django.views.generic import ListView
|
bgneal@710
|
12 from django.views.decorators.http import require_POST
|
bgneal@704
|
13 from django.utils.decorators import method_decorator
|
bgneal@710
|
14 from django.contrib import messages
|
bgneal@695
|
15
|
bgneal@971
|
16 from user_photos.forms import HotLinkImageForm, UploadForm
|
bgneal@704
|
17 from user_photos.models import Photo
|
bgneal@718
|
18 from user_photos.s3 import delete_photos
|
bgneal@695
|
19
|
bgneal@695
|
20
|
bgneal@695
|
21 @login_required
|
bgneal@695
|
22 def upload(request):
|
bgneal@695
|
23 """This view function receives an uploaded image file from a user.
|
bgneal@695
|
24 The photo will be resized if necessary and a thumbnail image will be
|
bgneal@695
|
25 created. The image and thumbnail will then be uploaded to the Amazon
|
bgneal@695
|
26 S3 service for storage.
|
bgneal@695
|
27
|
bgneal@695
|
28 """
|
bgneal@695
|
29 form = None
|
bgneal@696
|
30 uploads_enabled = settings.USER_PHOTOS_ENABLED
|
bgneal@695
|
31
|
bgneal@695
|
32 if uploads_enabled:
|
bgneal@695
|
33 if request.method == 'POST':
|
bgneal@696
|
34 form = UploadForm(request.POST, request.FILES, user=request.user)
|
bgneal@695
|
35 if form.is_valid():
|
bgneal@696
|
36 photo = form.save()
|
bgneal@696
|
37 return redirect(photo)
|
bgneal@695
|
38 else:
|
bgneal@696
|
39 form = UploadForm(user=request.user)
|
bgneal@695
|
40
|
bgneal@695
|
41 return render(request, 'user_photos/upload_form.html', {
|
bgneal@695
|
42 'enabled': uploads_enabled,
|
bgneal@695
|
43 'form': form,
|
bgneal@1158
|
44 'V3_DESIGN': True,
|
bgneal@695
|
45 },
|
bgneal@695
|
46 status=200 if uploads_enabled else 503)
|
bgneal@704
|
47
|
bgneal@704
|
48
|
bgneal@722
|
49 def upload_ajax(request):
|
bgneal@722
|
50 """This view is the ajax version of the upload function, above.
|
bgneal@722
|
51
|
bgneal@722
|
52 We return a JSON object response to the client with the following name
|
bgneal@722
|
53 & value pairs:
|
bgneal@722
|
54 'success' : false for failure and true for success
|
bgneal@722
|
55 'msg' : string error message if success is false
|
bgneal@722
|
56 'url' : the image URL as a string if success
|
bgneal@722
|
57
|
bgneal@722
|
58 If a non-200 status code is returned the response will simply be a text
|
bgneal@722
|
59 string error message.
|
bgneal@722
|
60
|
bgneal@722
|
61 """
|
bgneal@722
|
62 if not request.user.is_authenticated():
|
bgneal@724
|
63 return HttpResponseForbidden('Please login to use this service')
|
bgneal@722
|
64 if not request.is_ajax() or request.method != 'POST':
|
bgneal@724
|
65 return HttpResponseNotAllowed('This method is not allowed')
|
bgneal@722
|
66
|
bgneal@722
|
67 ret = {'success': False, 'msg': '', 'url': ''}
|
bgneal@722
|
68 if settings.USER_PHOTOS_ENABLED:
|
bgneal@722
|
69 form = UploadForm(request.POST, request.FILES, user=request.user)
|
bgneal@722
|
70 if form.is_valid():
|
bgneal@722
|
71 photo = form.save()
|
bgneal@722
|
72 ret['success'] = True
|
bgneal@722
|
73 ret['url'] = photo.url
|
bgneal@722
|
74 else:
|
bgneal@722
|
75 # gather form error messages
|
bgneal@722
|
76 errors = []
|
bgneal@722
|
77 non_field_errors = form.non_field_errors().as_text()
|
bgneal@722
|
78 if non_field_errors:
|
bgneal@722
|
79 errors.append(non_field_errors)
|
bgneal@722
|
80 for field_errors in form.errors.values():
|
bgneal@722
|
81 errors.append(field_errors.as_text())
|
bgneal@722
|
82 ret['msg'] = '\n'.join(errors)
|
bgneal@722
|
83 else:
|
bgneal@722
|
84 ret['msg'] = 'Photo uploads are temporarily disabled'
|
bgneal@722
|
85
|
bgneal@722
|
86 return HttpResponse(json.dumps(ret), content_type='application/json')
|
bgneal@722
|
87
|
bgneal@722
|
88
|
bgneal@1096
|
89 def upload_ajax_v3(request):
|
bgneal@1096
|
90 """This view is the V3 ajax version of the upload function, above.
|
bgneal@1096
|
91
|
bgneal@1096
|
92 We return a JSON object response to the client with the following name
|
bgneal@1096
|
93 & value pairs:
|
bgneal@1096
|
94 'msg' : string error message if success is false
|
bgneal@1096
|
95 'url' : the image URL as a string if success
|
bgneal@1096
|
96 """
|
bgneal@1096
|
97 ret = {'error_msg': '', 'url': ''}
|
bgneal@1096
|
98 status_code = 400
|
bgneal@1096
|
99
|
bgneal@1096
|
100 if not request.user.is_authenticated():
|
bgneal@1096
|
101 ret['error_msg'] = 'Please login to use this service'
|
bgneal@1096
|
102 return JsonResponse(ret, status=403)
|
bgneal@1096
|
103 if not request.is_ajax() or request.method != 'POST':
|
bgneal@1096
|
104 ret['error_msg'] = 'This method is not allowed'
|
bgneal@1096
|
105 return JsonResponse(ret, status=405)
|
bgneal@1096
|
106
|
bgneal@1096
|
107 if settings.USER_PHOTOS_ENABLED:
|
bgneal@1096
|
108 form = UploadForm(request.POST, request.FILES, user=request.user)
|
bgneal@1096
|
109 if form.is_valid():
|
bgneal@1096
|
110 try:
|
bgneal@1096
|
111 photo = form.save()
|
bgneal@1096
|
112 ret['url'] = photo.url
|
bgneal@1096
|
113 status_code = 200
|
bgneal@1096
|
114 except Exception as ex:
|
bgneal@1096
|
115 ret['error_msg'] = str(ex)
|
bgneal@1096
|
116 status_code = 500
|
bgneal@1096
|
117 else:
|
bgneal@1096
|
118 # gather form error messages
|
bgneal@1096
|
119 errors = []
|
bgneal@1096
|
120 non_field_errors = form.non_field_errors().as_text()
|
bgneal@1096
|
121 if non_field_errors:
|
bgneal@1096
|
122 errors.append(non_field_errors)
|
bgneal@1096
|
123 for field_errors in form.errors.values():
|
bgneal@1096
|
124 errors.append(field_errors.as_text())
|
bgneal@1096
|
125 ret['msg'] = '\n'.join(errors)
|
bgneal@1096
|
126 else:
|
bgneal@1096
|
127 ret['msg'] = 'Photo uploads are temporarily disabled'
|
bgneal@1096
|
128 status_code = 403
|
bgneal@1096
|
129
|
bgneal@1096
|
130 return JsonResponse(ret, status=status_code)
|
bgneal@1096
|
131
|
bgneal@1096
|
132
|
bgneal@704
|
133 class GalleryView(ListView):
|
bgneal@704
|
134 """A ListView for displaying a user's photos"""
|
bgneal@704
|
135
|
bgneal@704
|
136 template_name = 'user_photos/gallery.html'
|
bgneal@704
|
137 context_object_name = 'photos'
|
bgneal@704
|
138 paginate_by = 50
|
bgneal@704
|
139 allow_empty = True
|
bgneal@704
|
140
|
bgneal@704
|
141 def get_queryset(self):
|
bgneal@704
|
142 self.gallery_owner = get_object_or_404(get_user_model(),
|
bgneal@704
|
143 username=self.kwargs['username'])
|
bgneal@704
|
144 return Photo.objects.filter(user=self.gallery_owner).order_by('-upload_date')
|
bgneal@704
|
145
|
bgneal@704
|
146 def get_context_data(self, **kwargs):
|
bgneal@704
|
147 context = super(GalleryView, self).get_context_data(**kwargs)
|
bgneal@704
|
148 context['gallery_owner'] = self.gallery_owner
|
bgneal@1158
|
149 context['V3_DESIGN'] = True
|
bgneal@1158
|
150 context['page'] = context['page_obj']
|
bgneal@704
|
151 return context
|
bgneal@704
|
152
|
bgneal@704
|
153 @method_decorator(login_required)
|
bgneal@704
|
154 def dispatch(self, *args, **kwargs):
|
bgneal@704
|
155 return super(GalleryView, self).dispatch(*args, **kwargs)
|
bgneal@710
|
156
|
bgneal@710
|
157
|
bgneal@1158
|
158 class PhotoView(DetailView):
|
bgneal@1158
|
159 """A DetailView for displaying a user's photo"""
|
bgneal@1158
|
160
|
bgneal@1158
|
161 model = Photo
|
bgneal@1158
|
162
|
bgneal@1158
|
163 def get_context_data(self, **kwargs):
|
bgneal@1158
|
164 context = super(PhotoView, self).get_context_data(**kwargs)
|
bgneal@1158
|
165 context['V3_DESIGN'] = True
|
bgneal@1158
|
166 return context
|
bgneal@1158
|
167
|
bgneal@1158
|
168
|
bgneal@710
|
169 @login_required
|
bgneal@710
|
170 @require_POST
|
bgneal@710
|
171 def delete(request):
|
bgneal@718
|
172 """A view function to allow a user to delete their own photos."""
|
bgneal@718
|
173
|
bgneal@718
|
174 ret_view, username = 'user_photos-gallery', request.user.username
|
bgneal@718
|
175
|
bgneal@718
|
176 if not settings.USER_PHOTOS_ENABLED:
|
bgneal@718
|
177 messages.error(request, "This function is disabled temporarily")
|
bgneal@718
|
178 return redirect(ret_view, username)
|
bgneal@718
|
179
|
bgneal@710
|
180 photo_ids = []
|
bgneal@710
|
181 for photo_id in request.POST.getlist('photo_id'):
|
bgneal@710
|
182 try:
|
bgneal@710
|
183 n = int(photo_id)
|
bgneal@710
|
184 except ValueError:
|
bgneal@710
|
185 continue
|
bgneal@710
|
186 photo_ids.append(n)
|
bgneal@710
|
187
|
bgneal@710
|
188 count = 0
|
bgneal@710
|
189 if photo_ids:
|
bgneal@710
|
190 qs = Photo.objects.filter(user=request.user, pk__in=photo_ids)
|
bgneal@718
|
191 count = len(qs)
|
bgneal@718
|
192 if count:
|
bgneal@718
|
193 delete_photos(qs)
|
bgneal@718
|
194 qs.delete()
|
bgneal@710
|
195
|
bgneal@718
|
196 msg = "{} photo{} deleted".format(count, '' if count == 1 else 's')
|
bgneal@718
|
197 messages.add_message(request,
|
bgneal@718
|
198 messages.SUCCESS if count > 0 else messages.WARNING,
|
bgneal@718
|
199 msg)
|
bgneal@710
|
200
|
bgneal@718
|
201 return redirect(ret_view, username)
|
bgneal@971
|
202
|
bgneal@971
|
203
|
bgneal@971
|
204 def hotlink_image(request):
|
bgneal@971
|
205 """This view is responsible for accepting an image URL from a user and
|
bgneal@971
|
206 converting it to a URL pointing into our S3 bucket if necessary.
|
bgneal@971
|
207
|
bgneal@971
|
208 We return a JSON object response to the client with the following name
|
bgneal@971
|
209 & value pairs:
|
bgneal@971
|
210 'error_msg': string error message if an error occurred
|
bgneal@971
|
211 'url': the image URL as a string if success
|
bgneal@971
|
212 """
|
bgneal@971
|
213 ret = {'error_msg': '', 'url': ''}
|
bgneal@971
|
214 status_code = 400
|
bgneal@971
|
215
|
bgneal@971
|
216 if not request.user.is_authenticated():
|
bgneal@971
|
217 ret['error_msg'] = 'Please login to use this service'
|
bgneal@972
|
218 return JsonResponse(ret, status=403)
|
bgneal@971
|
219 if not request.is_ajax() or request.method != 'POST':
|
bgneal@971
|
220 ret['error_msg'] = 'This method is not allowed'
|
bgneal@972
|
221 return JsonResponse(ret, status=405)
|
bgneal@971
|
222
|
bgneal@971
|
223 if settings.USER_PHOTOS_ENABLED:
|
bgneal@972
|
224 form = HotLinkImageForm(request.POST, user=request.user)
|
bgneal@971
|
225 if form.is_valid():
|
bgneal@971
|
226 try:
|
bgneal@971
|
227 ret['url'] = form.save()
|
bgneal@971
|
228 status_code = 200
|
bgneal@971
|
229 except Exception as ex:
|
bgneal@971
|
230 ret['error_msg'] = str(ex)
|
bgneal@971
|
231 status_code = 500
|
bgneal@971
|
232 else:
|
bgneal@971
|
233 # gather form error messages
|
bgneal@971
|
234 errors = []
|
bgneal@971
|
235 non_field_errors = form.non_field_errors().as_text()
|
bgneal@971
|
236 if non_field_errors:
|
bgneal@971
|
237 errors.append(non_field_errors)
|
bgneal@971
|
238 for field_errors in form.errors.values():
|
bgneal@971
|
239 errors.append(field_errors.as_text())
|
bgneal@971
|
240 ret['error_msg'] = '\n'.join(errors)
|
bgneal@971
|
241 else:
|
bgneal@971
|
242 ret['error_msg'] = 'Image linking is temporarily disabled'
|
bgneal@971
|
243 status_code = 403
|
bgneal@971
|
244
|
bgneal@971
|
245 return JsonResponse(ret, status=status_code)
|