def press_gallery(request): """If POST, either add to or remove from press gallery. If GET, redirect to the browse page w/ a properly formed press gallery query.""" press_gallery_path = settings.PRESS_GALLERY_PATH if request.method == 'POST': if not request.user.has_perm('gallery.can_review'): raise PermissionDenied photo = models.Photo.objects.get(id=request.POST.get('id')) if photo is None: return handler400(request) if not os.path.exists(press_gallery_path): os.makedirs(press_gallery_path) action = request.POST.get('press_gallery', '').lower() filename = os.path.split(photo.image.name)[-1] press_photo_path = '%s%s' % (press_gallery_path, filename) if action == 'remove': if os.path.exists(press_photo_path): os.remove(press_photo_path) photo.in_press_gallery = False photo.save() request.notifications.add(_('Image removed from press gallery.')) elif action == 'add': shutil.copy(photo.image.file.name, press_photo_path) photo.in_press_gallery = True photo.save() request.notifications.add(_('Image added to press gallery.')) return HttpResponseRedirect(photo.get_absolute_url()) # Redirect to a browse page query if not request.user.has_perm('gallery.can_see_press_gallery'): raise PermissionDenied url = '%s?press_gallery=true' % reverse('bm.gallery.views.browse') return HttpResponseRedirect(url)
def _id_lookup(request, mediatype, fieldname): mediatype_plural = mediatype mediatype = mediatype_deplural.get(mediatype_plural) klass = models.mediatype_map.get(mediatype, {}).get('klass') if not klass: return HttpResponseNotFound() id_ = request.GET.get('id') if not id_: from bm.gallery.views import handler400 return handler400(request) resource = get_object_or_404(klass, **{fieldname: id_}) username = resource.owner.username if request.GET.get('full_image', '').lower() == 'true': extension = resource.image.file.name.split('.')[-1] url = '/g/scaled/%s/%s/%s_full_image.%s' % (mediatype_plural, username, resource.slug, extension) else: url = reverse('bm.gallery.views.media_view', kwargs=dict(mediatype=mediatype_plural, username=username, slug=resource.slug)) if request.GET.get('geturl', '').lower() == 'true': return HttpResponse(url) return HttpResponseRedirect(url)
def media_view(request, mediatype, username, slug, piston=False): log.debug('media_view: %s, %s, %s, %s', mediatype, username, slug, piston) user = get_object_or_404(authmodels.User, username=username) mediatype_plural = mediatype mediatype = mediatype_deplural.get(mediatype_plural) klass = models.mediatype_map.get(mediatype, {}).get('klass') if not klass: return HttpResponseNotFound() filter_args, filter_kwargs = filter_args_from_request(request) resource = get_object_or_404(klass, owner=user, slug=slug) show_set_context = True # default to showing a search context status = request.GET.get('status') # The code below is the meat of the security policy, deciding # whether or not a user can view a particular piece of media. # It's fairly straightforward, I think. Still, edit with care, # lest you end up exposing pages that aren't supposed to be # exposed. log.debug('checking perm for %s', request.user) can_review = request.user.has_perm('gallery.can_review') log.debug('checked perm: %s', can_review) if not status: # if there aren't any other search parameters, don't use a # search context if (not any([arg in request.GET for arg in extra_filter_args]) and not filter_args and not filter_kwargs): show_set_context = False # status isn't specified as a search parameter, default to # only showing approved items, which everyone can see if resource.status == 'approved': filter_kwargs['status'] = 'approved' elif (not can_review and getattr(resource, 'full_image_available', False)): # it's not approved, but the full size image is explicitly # made available so we're allowed to see it; restrict the # query to only this object filter_kwargs['id'] = resource.id else: # object isn't in approved state, no status was specified # in the search parameters, user must either be the owner # or have review privs if (request.user != user and not can_review): raise PermissionDenied if not can_review: # we're a non-privileged user looking at one of our # own images, enforce a query that is limited to # resources we own filter_kwargs['owner'] = user elif not request.user.has_perm('gallery.can_upload'): # status is specified as a search parameter but user isn't a # contributor; not allowed raise PermissionDenied else: # status is specified as search arg; user is a contributor so # we allow it filter_kwargs['status'] = status # however, if the user doesn't have review privs, she'll be # limited to seeing her own images if not can_review: filter_kwargs['owner'] = user # now we create a query set which represents the search context # within which the item exists (i.e. the full set of queried # objects of which the one we are viewing is a single element) if 'mediatype' in request.GET: # mediatype is specified, has to be the current type if request.GET['mediatype'] != mediatype: return handler400(request) query_klass = klass else: # mediatype isn't specified, search all content query_klass = models.MediaBase resource_qs = query_klass.objects.filter(*filter_args, **filter_kwargs) tag = request.GET.get('tag') if tag: resource_qs = tagmodels.TaggedItem.objects.get_by_model(resource_qs, tag) text = request.GET.get('text') if text: resource_qs = apply_searchable_text_filter(resource_qs, text) try: # verify that resource we're looking at is IN the query set resource_qs.get(owner=user, slug=slug) except query_klass.DoesNotExist: # if not, something is weird so we don't allow it raise PermissionDenied except query_klass.MultipleObjectsReturned: # possible edge case where we're searching over all media # types, and two objects of different types have same owner # and slug; check to see if the object is in the result set if resource not in [r.get_child_instance() for r in resource_qs.filter(owner=user, slug=slug)]: raise PermissionDenied # for piston calls, we just want the resource, no template rendering needed. if piston: log.debug('returning piston resource: %s', resource) return resource # we will reverse, but not yet resource_qs = resource_qs.order_by('id') # generate prev and next link URLs query_string = request.META.get('QUERY_STRING') template_map = dict(resource=resource, query_string=query_string, show_set_context=show_set_context, mediatype_plural=mediatype_plural) if show_set_context: # since we go in reverse order, prev is newer prev = resource_qs.filter(id__gt=resource.id) prevurl = None if prev.count(): try: prevurl = prev[0].get_absolute_url() except models.ImageBase.DoesNotExist, models.MediaBase.DoesNotExist: pass # next is older (i.e. lower id) next = resource_qs.filter(id__lt=resource.id).reverse() nexturl = None if next.count(): try: nexturl = next[0].get_absolute_url() except models.ImageBase.DoesNotExist, models.MediaBase.DoesNotExist: pass
def browse(request): """Render the browse page. This page supports a wide variety of query parameters, some of which are restricted to those w/ certain permissions.""" klass = media_klass_from_request(request) filter_args, filter_kwargs = filter_args_from_request(request) press_gallery = request.GET.get('press_gallery', '') press_gallery = press_gallery.lower() == 'true' if press_gallery: if not request.user.has_perm('gallery.can_see_press_gallery'): raise PermissionDenied # for now we only allow photos in the press gallery, not # artifacts or any other types. it's okay if the search query # doesn't specify a type, or if it specifies the photo type, # but we disallow other types of searches. it's a little ugly # to be doing explicit type checking, but expedience demands # it :P if klass is models.MediaBase: klass = models.Photo if klass is not models.Photo: return handler400(request) filter_kwargs['in_press_gallery'] = True status = request.GET.get('status') if not status: filter_kwargs['status'] = 'approved' elif status != 'approved': if not request.user.has_perm('gallery.can_review'): # only reviewers can arbitrarily query based on status; # non-reviewers are restricted to seeing their own # submissions if they search on a status other than # 'approved' if request.user.is_anonymous(): raise PermissionDenied filter_kwargs['owner'] = request.user filter_kwargs['status'] = status else: filter_kwargs['status'] = status full_results = klass.objects.filter(*filter_args, **filter_kwargs) # reverse the order so most recent is first full_results = full_results.order_by('id').reverse() tag = request.GET.get('tag') if tag: full_results = tagmodels.TaggedItem.objects.get_by_model(full_results, tag) text = request.GET.get('text') if text: full_results = apply_searchable_text_filter(full_results, text) paginator = BetterPaginator(full_results, settings.PAGINATION_BATCH_SIZE) try: page = int(request.GET.get('page', '1')) except ValueError: page = 1 try: page_results = paginator.page(page) except (InvalidPage, EmptyPage): page_results = paginator.page(paginator.num_pages) query_string = request.META.get('QUERY_STRING') # remove 'page' from query string so it doesn't get used in the template query_map = parse_qs(query_string) query_map.pop('page', None) query_string = urlencode(query_map, doseq=True) for extra_filter in ('owner', 'tag', 'press_gallery'): if extra_filter in query_map: del(query_map[extra_filter]) qs_no_extra_filters = urlencode(query_map, doseq=True) no_extra_filters_url = reverse('bm.gallery.views.browse') if qs_no_extra_filters: no_extra_filters_url = '%s?%s' % (no_extra_filters_url, qs_no_extra_filters) template_map = {'page_results': page_results, 'total_count': full_results.count(), 'query_string': query_string, 'no_extra_filters_url': no_extra_filters_url, 'paginator': paginator.get_context(page), 'page': page} owner_username = request.GET.get('owner') if owner_username: template_map['owner'] = authmodels.User.objects.get(username=owner_username) if tag: template_map['tag'] = tag if press_gallery: template_map['press_gallery'] = True context = RequestContext(request, template_map) return render_to_response('gallery/browse.html', context)