def test_filtering_tags(self): get_document_model().objects.get(id=3).tags.add('test') response = self.get_response(tags='test') content = json.loads(response.content.decode('UTF-8')) document_id_list = self.get_document_id_list(content) self.assertEqual(document_id_list, [3])
def test_filtering_tags(self): get_document_model().objects.get(id=3).tags.add('test') response = self.get_response(tags='test') content = json.loads(response.content.decode('UTF-8')) document_id_list = self.get_document_id_list(content) self.assertEqual(document_id_list, [3])
def test_tags(self): get_document_model().objects.get(id=1).tags.add('hello') get_document_model().objects.get(id=1).tags.add('world') response = self.get_response(1) content = json.loads(response.content.decode('UTF-8')) self.assertIn('tags', content['meta']) self.assertEqual(content['meta']['tags'], ['hello', 'world'])
def test_tags(self): get_document_model().objects.get(id=1).tags.add('hello') get_document_model().objects.get(id=1).tags.add('world') response = self.get_response(1) content = json.loads(response.content.decode('UTF-8')) self.assertIn('tags', content['meta']) self.assertEqual(content['meta']['tags'], ['hello', 'world'])
def test_limit_max_none_gives_no_errors(self): response = self.get_response(limit=1000000) content = json.loads(response.content.decode('UTF-8')) self.assertEqual(response.status_code, 200) self.assertEqual(len(content['documents']), get_document_model().objects.count())
def chooser(request): Document = get_document_model() if permission_policy.user_has_permission(request.user, 'add'): DocumentForm = get_document_form(Document) uploadform = DocumentForm(user=request.user) else: uploadform = None documents = Document.objects.all() # allow hooks to modify the queryset for hook in hooks.get_hooks('construct_document_chooser_queryset'): documents = hook(documents, request) q = None if 'q' in request.GET or 'p' in request.GET or 'collection_id' in request.GET: collection_id = request.GET.get('collection_id') if collection_id: documents = documents.filter(collection=collection_id) searchform = SearchForm(request.GET) if searchform.is_valid(): q = searchform.cleaned_data['q'] documents = documents.search(q) is_searching = True else: documents = documents.order_by('-created_at') is_searching = False # Pagination paginator, documents = paginate(request, documents, per_page=10) return render( request, "wagtaildocs/chooser/results.html", { 'documents': documents, 'query_string': q, 'is_searching': is_searching, }) else: searchform = SearchForm() collections = Collection.objects.all() if len(collections) < 2: collections = None documents = documents.order_by('-created_at') paginator, documents = paginate(request, documents, per_page=10) return render_modal_workflow( request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', { 'documents': documents, 'uploadform': uploadform, 'searchform': searchform, 'collections': collections, 'is_searching': False, })
def get_field_display_value(self, field_name, field=None): """ Return a display value for a field """ # First we check for a 'get_fieldname_display' property/method on # the model, and return the value of that, if present. val_funct = getattr(self.instance, 'get_%s_display' % field_name, None) if val_funct is not None: if callable(val_funct): return val_funct() return val_funct # If we have a real field, we can utilise that to try to display # something more useful if field is not None: try: field_type = field.get_internal_type() if (field_type == 'ForeignKey' and field.related_model == get_image_model()): # The field is an image return self.get_image_field_display(field_name, field) if (field_type == 'ForeignKey' and field.related_model == get_document_model()): # The field is a document return self.get_document_field_display(field_name, field) except AttributeError: pass # Resort to getting the value of 'field_name' from the instance return getattr(self.instance, field_name, self.model_admin.get_empty_value_display(field_name))
def chooser_upload(request): Document = get_document_model() DocumentForm = get_document_form(Document) if request.POST: document = Document(uploaded_by_user=request.user) form = DocumentForm(request.POST, request.FILES, instance=document) if form.is_valid(): form.save() # Reindex the document to make sure all tags are indexed for backend in get_search_backends(): backend.add(document) return render_modal_workflow( request, None, "wagtaildocs/chooser/document_chosen.js", {"document_json": get_document_json(document)} ) else: form = DocumentForm() documents = Document.objects.order_by("title") return render_modal_workflow( request, "wagtaildocs/chooser/chooser.html", "wagtaildocs/chooser/chooser.js", {"documents": documents, "uploadform": form}, )
def test_offset_total_count(self): response = self.get_response(offset=10) content = json.loads(response.content.decode('UTF-8')) # The total count must not be affected by "offset" self.assertEqual(content['meta']['total_count'], get_document_model().objects.count())
def chooser(request): Document = get_document_model() if permission_policy.user_has_permission(request.user, "add"): DocumentForm = get_document_form(Document) uploadform = DocumentForm() else: uploadform = None documents = [] q = None is_searching = False if "q" in request.GET or "p" in request.GET or "collection_id" in request.GET: documents = Document.objects.all() collection_id = request.GET.get("collection_id") if collection_id: documents = documents.filter(collection=collection_id) searchform = SearchForm(request.GET) if searchform.is_valid(): q = searchform.cleaned_data["q"] documents = documents.search(q) is_searching = True else: documents = documents.order_by("-created_at") is_searching = False # Pagination paginator, documents = paginate(request, documents, per_page=10) return render( request, "wagtaildocs/chooser/results.html", {"documents": documents, "query_string": q, "is_searching": is_searching}, ) else: searchform = SearchForm() collections = Collection.objects.all() if len(collections) < 2: collections = None documents = Document.objects.order_by("-created_at") paginator, documents = paginate(request, documents, per_page=10) return render_modal_workflow( request, "wagtaildocs/chooser/chooser.html", "wagtaildocs/chooser/chooser.js", { "documents": documents, "uploadform": uploadform, "searchform": searchform, "collections": collections, "is_searching": False, }, )
def Document(props): document_model = get_document_model() try: doc = document_model.objects.get(id=props['id']) doc_meta = get_document_meta(doc) except (document_model.DoesNotExist, AttributeError): return DOM.create_element( 'a', { 'href': MISSING_RESOURCE_URL, 'class': MISSING_RESOURCE_CLASS + ' file' }, props['children']) icon_element = DOM.create_element(Icon, {'name': doc_meta['extension']}) metadata_element = DOM.create_element('span', {'class': 'icon-text__text'}, props['children'], ' ') size_element = DOM.create_element( 'span', {'class': 'file-size'}, '({ext} {size})'.format(size=doc_meta['size'], ext=doc_meta['extension'].upper())) link_item = DOM.create_element('a', { 'href': doc.url, 'class': 'icon-text' }, icon_element, metadata_element) return DOM.create_element('span', {'class': 'file'}, link_item, size_element)
def document_chosen(request, document_id): document = get_object_or_404(get_document_model(), id=document_id) return render_modal_workflow( request, None, 'wagtaildocs/chooser/document_chosen.js', {'document_json': get_document_json(document)} )
def chooser_upload(request): Document = get_document_model() DocumentForm = get_document_form(Document) if request.method == 'POST': document = Document(uploaded_by_user=request.user) form = DocumentForm(request.POST, request.FILES, instance=document, user=request.user) if form.is_valid(): form.save() # Reindex the document to make sure all tags are indexed search_index.insert_or_update_object(document) return render_modal_workflow( request, None, 'wagtaildocs/chooser/document_chosen.js', {'document_json': get_document_json(document)} ) else: form = DocumentForm(user=request.user) documents = Document.objects.order_by('title') return render_modal_workflow( request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', {'documents': documents, 'uploadform': form} )
def test_basic(self): response = self.get_response() self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-type'], 'application/json') # Will crash if the JSON is invalid content = json.loads(response.content.decode('UTF-8')) # Check that the meta section is there self.assertIn('meta', content) self.assertIsInstance(content['meta'], dict) # Check that the total count is there and correct self.assertIn('total_count', content['meta']) self.assertIsInstance(content['meta']['total_count'], int) self.assertEqual(content['meta']['total_count'], get_document_model().objects.count()) # Check that the documents section is there self.assertIn('documents', content) self.assertIsInstance(content['documents'], list) # Check that each document has a meta section with type and detail_url attributes for document in content['documents']: self.assertIn('meta', document) self.assertIsInstance(document['meta'], dict) self.assertEqual(set(document['meta'].keys()), {'type', 'detail_url'}) # Type should always be wagtaildocs.Document self.assertEqual(document['meta']['type'], 'wagtaildocs.Document') # Check detail_url self.assertEqual(document['meta']['detail_url'], 'http://localhost/api/v1/documents/%d/' % document['id'])
def add(request): Document = get_document_model() DocumentForm = get_document_form(Document) if request.POST: doc = Document(uploaded_by_user=request.user) form = DocumentForm(request.POST, request.FILES, instance=doc) if form.is_valid(): form.save() # Reindex the document to make sure all tags are indexed for backend in get_search_backends(): backend.add(doc) messages.success(request, _("Document '{0}' added.").format(doc.title), buttons=[ messages.button( reverse('wagtaildocs:edit', args=(doc.id, )), _('Edit')) ]) return redirect('wagtaildocs:index') else: messages.error(request, _("The document could not be saved due to errors.")) else: form = DocumentForm() return render(request, "wagtaildocs/documents/add.html", { 'form': form, })
def delete(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) if not permission_policy.user_has_permission_for_instance( request.user, 'delete', doc): return permission_denied(request) if doc.folder: parent_folder = doc.folder else: parent_folder = False if request.method == 'POST': doc.delete() messages.success(request, _("Document '{0}' deleted.").format(doc.title)) response = redirect('wagtaildocs:index') if parent_folder: response['Location'] += '?folder={0}'.format(parent_folder.id) return response return render(request, "wagtaildocs/documents/confirm_delete.html", { 'document': doc, })
def add(request): Document = get_document_model() DocumentForm = get_document_form(Document) if request.POST: doc = Document(uploaded_by_user=request.user) form = DocumentForm(request.POST, request.FILES, instance=doc, user=request.user) if form.is_valid(): form.save() # Reindex the document to make sure all tags are indexed for backend in get_search_backends(): backend.add(doc) messages.success(request, _("Document '{0}' added.").format(doc.title), buttons=[ messages.button(reverse('wagtaildocs:edit', args=(doc.id,)), _('Edit')) ]) return redirect('wagtaildocs:index') else: messages.error(request, _("The document could not be saved due to errors.")) else: form = DocumentForm(user=request.user) return render(request, "wagtaildocs/documents/add.html", { 'form': form, })
def usage(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) paginator, used_by = paginate(request, doc.get_usage()) return render(request, "wagtaildocs/documents/usage.html", {"document": doc, "used_by": used_by})
def test_document_file_deleted_oncommit(self): with transaction.atomic(): document = get_document_model().objects.create(title="Test Image", file=get_test_image_file()) self.assertTrue(document.file.storage.exists(document.file.name)) document.delete() self.assertTrue(document.file.storage.exists(document.file.name)) self.assertFalse(document.file.storage.exists(document.file.name))
def serve(request, document_id, document_filename): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) # We want to ensure that the document filename provided in the URL matches the one associated with the considered # document_id. If not we can't be sure that the document the user wants to access is the one corresponding to the # <document_id, document_filename> pair. if doc.filename != document_filename: raise Http404('This document does not match the given filename.') for fn in hooks.get_hooks('before_serve_document'): result = fn(doc, request) if isinstance(result, HttpResponse): return result # Send document_served signal document_served.send(sender=Document, instance=doc, request=request) try: local_path = doc.file.path except NotImplementedError: local_path = None if local_path: # Use wagtail.utils.sendfile to serve the file; # this provides support for mimetypes, if-modified-since and django-sendfile backends if hasattr(settings, 'SENDFILE_BACKEND'): return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename) else: # Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename, backend=sendfile_streaming_backend.sendfile) else: # We are using a storage backend which does not expose filesystem paths # (e.g. storages.backends.s3boto.S3BotoStorage). # Fall back on pre-sendfile behaviour of reading the file content and serving it # as a StreamingHttpResponse wrapper = FileWrapper(doc.file) response = StreamingHttpResponse( wrapper, content_type='application/octet-stream') response[ 'Content-Disposition'] = 'attachment; filename=%s' % doc.filename # FIXME: storage backends are not guaranteed to implement 'size' response['Content-Length'] = doc.file.size return response
class DocumentsAPIEndpoint(BaseAPIEndpoint): base_serializer_class = DocumentSerializer filter_backends = [FieldsFilter, OrderingFilter, SearchFilter] extra_body_fields = ['title', 'file'] extra_meta_fields = ['tags', 'file'] default_fields = ['title', 'tags'] name = 'documents' model = get_document_model()
def test_document_file_deleted_oncommit(self): with transaction.atomic(): document = get_document_model().objects.create( title="Test Image", file=get_test_image_file()) self.assertTrue(document.file.storage.exists(document.file.name)) document.delete() self.assertTrue(document.file.storage.exists(document.file.name)) self.assertFalse(document.file.storage.exists(document.file.name))
def edit(request, document_id): Document = get_document_model() DocumentForm = get_document_form(Document) doc = get_object_or_404(Document, id=document_id) if not permission_policy.user_has_permission_for_instance(request.user, 'change', doc): return permission_denied(request) if request.method == 'POST': original_file = doc.file form = DocumentForm(request.POST, request.FILES, instance=doc, user=request.user) if form.is_valid(): if 'file' in form.changed_data: # if providing a new document file, delete the old one. # NB Doing this via original_file.delete() clears the file field, # which definitely isn't what we want... original_file.storage.delete(original_file.name) doc = form.save() # Reindex the document to make sure all tags are indexed for backend in get_search_backends(): backend.add(doc) messages.success(request, _("Document '{0}' updated").format(doc.title), buttons=[ messages.button(reverse('wagtaildocs:edit', args=(doc.id,)), _('Edit')) ]) return redirect('wagtaildocs:index') else: messages.error(request, _("The document could not be saved due to errors.")) else: form = DocumentForm(instance=doc, user=request.user) filesize = None # Get file size when there is a file associated with the Document object if doc.file: try: filesize = doc.file.size except OSError: # File doesn't exist pass if not filesize: messages.error( request, _("The file could not be found. Please change the source or delete the document"), buttons=[messages.button(reverse('wagtaildocs:delete', args=(doc.id,)), _('Delete'))] ) return render(request, "wagtaildocs/documents/edit.html", { 'document': doc, 'filesize': filesize, 'form': form, 'user_can_delete': permission_policy.user_has_permission_for_instance( request.user, 'delete', doc ), })
def edit(request, document_id): Document = get_document_model() DocumentForm = get_document_form(Document) doc = get_object_or_404(Document, id=document_id) if not permission_policy.user_has_permission_for_instance(request.user, 'change', doc): return permission_denied(request) if request.POST: original_file = doc.file form = DocumentForm(request.POST, request.FILES, instance=doc, user=request.user) if form.is_valid(): if 'file' in form.changed_data: # if providing a new document file, delete the old one. # NB Doing this via original_file.delete() clears the file field, # which definitely isn't what we want... original_file.storage.delete(original_file.name) doc = form.save() # Reindex the document to make sure all tags are indexed for backend in get_search_backends(): backend.add(doc) messages.success(request, _("Document '{0}' updated").format(doc.title), buttons=[ messages.button(reverse('wagtaildocs:edit', args=(doc.id,)), _('Edit')) ]) return redirect('wagtaildocs:index') else: messages.error(request, _("The document could not be saved due to errors.")) else: form = DocumentForm(instance=doc, user=request.user) filesize = None # Get file size when there is a file associated with the Document object if doc.file: try: filesize = doc.file.size except OSError: # File doesn't exist pass if not filesize: messages.error( request, _("The file could not be found. Please change the source or delete the document"), buttons=[messages.button(reverse('wagtaildocs:delete', args=(doc.id,)), _('Delete'))] ) return render(request, "wagtaildocs/documents/edit.html", { 'document': doc, 'filesize': filesize, 'form': form, 'user_can_delete': permission_policy.user_has_permission_for_instance( request.user, 'delete', doc ), })
def wagtail_docs_preview(request, doc_id, doc_name): Document = get_document_model() doc = get_object_or_404(Document, id=doc_id) # Check if names match if doc.filename != doc_name: raise Http404('This document does not match the given filename.') return HttpResponseRedirect(doc.file.url)
def chooser(request): Document = get_document_model() if permission_policy.user_has_permission(request.user, 'add'): DocumentForm = get_document_form(Document) uploadform = DocumentForm(user=request.user) else: uploadform = None documents = Document.objects.all() # allow hooks to modify the queryset for hook in hooks.get_hooks('construct_document_chooser_queryset'): documents = hook(documents, request) q = None if 'q' in request.GET or 'p' in request.GET or 'collection_id' in request.GET: collection_id = request.GET.get('collection_id') if collection_id: documents = documents.filter(collection=collection_id) searchform = SearchForm(request.GET) if searchform.is_valid(): q = searchform.cleaned_data['q'] documents = documents.search(q) is_searching = True else: documents = documents.order_by('-created_at') is_searching = False # Pagination paginator, documents = paginate(request, documents, per_page=10) return render(request, "wagtaildocs/chooser/results.html", { 'documents': documents, 'query_string': q, 'is_searching': is_searching, }) else: searchform = SearchForm() collections = Collection.objects.all() if len(collections) < 2: collections = None documents = documents.order_by('-created_at') paginator, documents = paginate(request, documents, per_page=10) return render_modal_workflow(request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', { 'documents': documents, 'uploadform': uploadform, 'searchform': searchform, 'collections': collections, 'is_searching': False, })
def index(request): Document = get_document_model() # Get documents (filtered by user permission) documents = permission_policy.instances_user_has_any_permission_for( request.user, ['change', 'delete']) # Ordering if 'ordering' in request.GET and request.GET['ordering'] in [ 'title', '-created_at' ]: ordering = request.GET['ordering'] else: ordering = '-created_at' documents = documents.order_by(ordering) # Search query_string = None if 'q' in request.GET: form = SearchForm(request.GET, placeholder=_("Search documents")) if form.is_valid(): query_string = form.cleaned_data['q'] documents = documents.search(query_string) else: form = SearchForm(placeholder=_("Search documents")) # Pagination paginator, documents = paginate(request, documents) # Create response if request.is_ajax(): return render( request, 'wagtaildocs/documents/results.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), }) else: return render( request, 'wagtaildocs/documents/index.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), 'search_form': form, 'popular_tags': Document.popular_tags(), 'user_can_add': permission_policy.user_has_permission(request.user, 'add'), })
def usage(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) paginator, used_by = paginate(request, doc.get_usage()) return render(request, "wagtaildocs/documents/usage.html", { 'document': doc, 'used_by': used_by })
def serve(request, document_id, document_filename): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) # Send document_served signal document_served.send(sender=Document, instance=doc, request=request) try: local_path = doc.file.path except NotImplementedError: local_path = None if local_path: # Use wagtail.utils.sendfile to serve the file; # this provides support for mimetypes, if-modified-since and django-sendfile backends if hasattr(settings, 'SENDFILE_BACKEND'): return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename) else: # Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename, backend=sendfile_streaming_backend.sendfile) else: # We are using a storage backend which does not expose filesystem paths # (e.g. storages.backends.s3boto.S3BotoStorage). # Fall back on pre-sendfile behaviour of reading the file content and serving it # as a StreamingHttpResponse wrapper = FileWrapper(doc.file) response = StreamingHttpResponse( wrapper, content_type='application/octet-stream') try: response[ 'Content-Disposition'] = 'attachment; filename=%s' % doc.filename except BadHeaderError: # Unicode filenames can fail on Django <1.8, Python 2 due to # https://code.djangoproject.com/ticket/20889 - try with an ASCIIfied version of the name response[ 'Content-Disposition'] = 'attachment; filename=%s' % unidecode( doc.filename) # FIXME: storage backends are not guaranteed to implement 'size' response['Content-Length'] = doc.file.size return response
def test_document_file_deleted(self): ''' this test duplicates `test_image_file_deleted_oncommit` for django 1.8 support and can be removed once django 1.8 is no longer supported ''' with transaction.atomic(): document = get_document_model().objects.create(title="Test Image", file=get_test_image_file()) self.assertTrue(document.file.storage.exists(document.file.name)) document.delete() self.assertFalse(document.file.storage.exists(document.file.name))
def unregister_signal_handlers(): Image = get_image_model() Document = get_document_model() for model in get_page_models(): page_published.disconnect(purge_page_from_cache, sender=model) page_unpublished.disconnect(purge_page_from_cache, sender=model) post_save.disconnect(purge_image_from_cache, sender=Image) post_delete.disconnect(purge_image_from_cache, sender=Image) post_save.disconnect(purge_document_from_cache, sender=Document) post_delete.disconnect(purge_document_from_cache, sender=Document)
def test_document_file_deleted(self): ''' this test duplicates `test_image_file_deleted_oncommit` for django 1.8 support and can be removed once django 1.8 is no longer supported ''' with transaction.atomic(): document = get_document_model().objects.create( title="Test Image", file=get_test_image_file()) self.assertTrue(document.file.storage.exists(document.file.name)) document.delete() self.assertFalse(document.file.storage.exists(document.file.name))
def unregister_signal_handlers(): Image = get_image_model() Document = get_document_model() for model in get_page_models(): page_published.disconnect(purge_page_from_cache, sender=model) page_unpublished.disconnect(purge_page_from_cache, sender=model) post_save.disconnect(purge_image_from_cache, sender=Image) post_delete.disconnect(purge_image_from_cache, sender=Image) post_save.disconnect(purge_document_from_cache, sender=Document) post_delete.disconnect(purge_document_from_cache, sender=Document)
def index(request): Document = get_document_model() # Get documents documents = Document.objects.all() # Ordering if 'ordering' in request.GET and request.GET['ordering'] in [ 'title', '-created_at' ]: ordering = request.GET['ordering'] else: ordering = '-created_at' documents = documents.order_by(ordering) # Permissions if not request.user.has_perm('wagtaildocs.change_document'): # restrict to the user's own documents documents = documents.filter(uploaded_by_user=request.user) # Search query_string = None if 'q' in request.GET: form = SearchForm(request.GET, placeholder=_("Search documents")) if form.is_valid(): query_string = form.cleaned_data['q'] documents = documents.search(query_string) else: form = SearchForm(placeholder=_("Search documents")) # Pagination paginator, documents = paginate(request, documents) # Create response if request.is_ajax(): return render( request, 'wagtaildocs/documents/results.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), }) else: return render( request, 'wagtaildocs/documents/index.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), 'search_form': form, 'popular_tags': Document.popular_tags(), })
def delete(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) if not permission_policy.user_has_permission_for_instance(request.user, "delete", doc): return permission_denied(request) if request.method == "POST": doc.delete() messages.success(request, _("Document '{0}' deleted.").format(doc.title)) return redirect("wagtaildocs:index") return render(request, "wagtaildocs/documents/confirm_delete.html", {"document": doc})
def describe_collection_docs(collection): docs_count = get_document_model().objects.filter(collection=collection).count() if docs_count: url = urlresolvers.reverse('wagtaildocs:index') + ('?collection_id=%d' % collection.id) return { 'count': docs_count, 'count_text': ungettext( "%(count)s document", "%(count)s documents", docs_count ) % {'count': docs_count}, 'url': url, }
def expand_db_attributes(attrs, for_editor): Document = get_document_model() try: doc = Document.objects.get(id=attrs['id']) if for_editor: editor_attrs = 'data-linktype="document" data-id="%d" ' % doc.id else: editor_attrs = '' return '<a %shref="%s">' % (editor_attrs, escape(doc.url)) except Document.DoesNotExist: return "<a>"
def expand_db_attributes(attrs, for_editor): Document = get_document_model() try: doc = Document.objects.get(id=attrs['id']) if for_editor: editor_attrs = 'data-linktype="document" data-id="%d" ' % doc.id else: editor_attrs = '' return '<a %shref="%s">' % (editor_attrs, escape(doc.url)) except Document.DoesNotExist: return "<a>"
def serve(request, document_id, document_filename): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) # Send document_served signal document_served.send(sender=Document, instance=doc, request=request) try: local_path = doc.file.path except NotImplementedError: local_path = None if local_path: # Use wagtail.utils.sendfile to serve the file; # this provides support for mimetypes, if-modified-since and django-sendfile backends if hasattr(settings, 'SENDFILE_BACKEND'): return sendfile(request, local_path, attachment=True, attachment_filename=doc.filename) else: # Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND return sendfile( request, local_path, attachment=True, attachment_filename=doc.filename, backend=sendfile_streaming_backend.sendfile ) else: # We are using a storage backend which does not expose filesystem paths # (e.g. storages.backends.s3boto.S3BotoStorage). # Fall back on pre-sendfile behaviour of reading the file content and serving it # as a StreamingHttpResponse wrapper = FileWrapper(doc.file) response = StreamingHttpResponse(wrapper, content_type='application/octet-stream') try: response['Content-Disposition'] = 'attachment; filename=%s' % doc.filename except BadHeaderError: # Unicode filenames can fail on Django <1.8, Python 2 due to # https://code.djangoproject.com/ticket/20889 - try with an ASCIIfied version of the name response['Content-Disposition'] = 'attachment; filename=%s' % unidecode(doc.filename) # FIXME: storage backends are not guaranteed to implement 'size' response['Content-Length'] = doc.file.size return response
def index(request): Document = get_document_model() # Get documents documents = Document.objects.all() # Ordering if 'ordering' in request.GET and request.GET['ordering'] in ['title', '-created_at']: ordering = request.GET['ordering'] else: ordering = '-created_at' documents = documents.order_by(ordering) # Permissions if not request.user.has_perm('wagtaildocs.change_document'): # restrict to the user's own documents documents = documents.filter(uploaded_by_user=request.user) # Search query_string = None if 'q' in request.GET: form = SearchForm(request.GET, placeholder=_("Search documents")) if form.is_valid(): query_string = form.cleaned_data['q'] documents = documents.search(query_string) else: form = SearchForm(placeholder=_("Search documents")) # Pagination paginator, documents = paginate(request, documents) # Create response if request.is_ajax(): return render(request, 'wagtaildocs/documents/results.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), }) else: return render(request, 'wagtaildocs/documents/index.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), 'search_form': form, 'popular_tags': Document.popular_tags(), })
def delete(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) if not doc.is_editable_by_user(request.user): raise PermissionDenied if request.POST: doc.delete() messages.success(request, _("Document '{0}' deleted.").format(doc.title)) return redirect('wagtaildocs:index') return render(request, "wagtaildocs/documents/confirm_delete.html", { 'document': doc, })
def delete(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) if not doc.is_editable_by_user(request.user): raise PermissionDenied if request.POST: doc.delete() messages.success(request, _("Document '{0}' deleted.").format(doc.title)) return redirect('wagtaildocs:index') return render(request, "wagtaildocs/documents/confirm_delete.html", { 'document': doc, })
def chooser(request): Document = get_document_model() if permission_policy.user_has_permission(request.user, 'add'): DocumentForm = get_document_form(Document) uploadform = DocumentForm() else: uploadform = None documents = [] q = None is_searching = False if 'q' in request.GET or 'p' in request.GET: searchform = SearchForm(request.GET) if searchform.is_valid(): q = searchform.cleaned_data['q'] documents = Document.objects.search(q) is_searching = True else: documents = Document.objects.order_by('-created_at') is_searching = False # Pagination paginator, documents = paginate(request, documents, per_page=10) return render( request, "wagtaildocs/chooser/results.html", { 'documents': documents, 'query_string': q, 'is_searching': is_searching, }) else: searchform = SearchForm() documents = Document.objects.order_by('-created_at') paginator, documents = paginate(request, documents, per_page=10) return render_modal_workflow( request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', { 'documents': documents, 'uploadform': uploadform, 'searchform': searchform, 'is_searching': False, })
def index(request): Document = get_document_model() # Get documents (filtered by user permission) documents = permission_policy.instances_user_has_any_permission_for( request.user, ['change', 'delete'] ) # Ordering if 'ordering' in request.GET and request.GET['ordering'] in ['title', '-created_at']: ordering = request.GET['ordering'] else: ordering = '-created_at' documents = documents.order_by(ordering) # Search query_string = None if 'q' in request.GET: form = SearchForm(request.GET, placeholder=_("Search documents")) if form.is_valid(): query_string = form.cleaned_data['q'] documents = documents.search(query_string) else: form = SearchForm(placeholder=_("Search documents")) # Pagination paginator, documents = paginate(request, documents) # Create response if request.is_ajax(): return render(request, 'wagtaildocs/documents/results.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), }) else: return render(request, 'wagtaildocs/documents/index.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), 'search_form': form, 'popular_tags': Document.popular_tags(), 'user_can_add': permission_policy.user_has_permission(request.user, 'add'), })
def delete(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) if not permission_policy.user_has_permission_for_instance( request.user, 'delete', doc): return permission_denied(request) if request.POST: doc.delete() messages.success(request, _("Document '{0}' deleted.").format(doc.title)) return redirect('wagtaildocs:index') return render(request, "wagtaildocs/documents/confirm_delete.html", { 'document': doc, })
def post(self, request, *args, **kwargs): # Get the document document_id = kwargs.get('document_id') document_cls = get_document_model() try: document = document_cls.objects.get(id=document_id) except document_cls.DoesNotExist: return HttpResponse(status=404) # Check if the user has permission if document.uploaded_by_user == request.user: # Delete the document message = 'File "{document}" has been deleted.'.format( document=document) document.delete() messages.success(request, message) return redirect( self.request.GET.get('next', self.request.META.get('HTTP_REFERER', '/')))
def delete(request, folder_id): Document = get_document_model() DocumentFolder = get_folder_model() folder = get_object_or_404(DocumentFolder, id=folder_id) # Make Sure folder contains no documents documents = Document.objects.filter(folder=folder) if documents.count() > 0: error = True error_text = "Cannot delete folder containing documents" else: error = False error_text = "" # Make sure folder contains no sub folders if not error and DocumentFolder.objects.filter(folder=folder).count() > 0: error = True error_text = "Cannot delete folder containing subfolders" if not error and request.method == 'POST': # POST if confirmation of delete # try find a parent folder parent_folder = folder.get_parent() # Delete folder folder.delete() # Success! Send back to index or document specific folder response = redirect('wagtaildocs:index') if parent_folder: response['Location'] += '?folder={0}'.format(parent_folder.id) return response return render( request, 'wagtaildocs/folder/confirm_delete.html', { 'error': error, 'error_text': error_text, 'folder': folder, #'form': form, })
def chooser(request): Document = get_document_model() if permission_policy.user_has_permission(request.user, 'add'): DocumentForm = get_document_form(Document) uploadform = DocumentForm() else: uploadform = None documents = [] q = None is_searching = False if 'q' in request.GET or 'p' in request.GET: searchform = SearchForm(request.GET) if searchform.is_valid(): q = searchform.cleaned_data['q'] documents = Document.objects.search(q) is_searching = True else: documents = Document.objects.order_by('-created_at') is_searching = False # Pagination paginator, documents = paginate(request, documents, per_page=10) return render(request, "wagtaildocs/chooser/results.html", { 'documents': documents, 'query_string': q, 'is_searching': is_searching, }) else: searchform = SearchForm() documents = Document.objects.order_by('-created_at') paginator, documents = paginate(request, documents, per_page=10) return render_modal_workflow(request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', { 'documents': documents, 'uploadform': uploadform, 'searchform': searchform, 'is_searching': False, })
def search(self): search_query = self.request.GET.get('query', None) if search_query: search_backend = get_search_backend() page_results = Page.objects.live().search(search_query) glossary_results = search_backend.search(search_query, Entry) Document = get_document_model() documents_results = search_backend.search(search_query, Document) # Log the query so Wagtail can suggest promoted results Query.get(search_query).add_hit() return { 'search_query': search_query or '', 'page_results': page_results, 'glossary_results': glossary_results, 'document_results': documents_results, } else: return {}
def delete(request, folder_id): Document = get_document_model() DocumentFolder = get_folder_model() folder = get_object_or_404(DocumentFolder, id=folder_id) # Make Sure folder contains no documents documents = Document.objects.filter(folder = folder) if documents.count() > 0: error = True error_text = "Cannot delete folder containing documents" else: error = False error_text = "" # Make sure folder contains no sub folders if not error and DocumentFolder.objects.filter(folder = folder).count() > 0: error = True error_text = "Cannot delete folder containing subfolders" if not error and request.method == 'POST': # POST if confirmation of delete # try find a parent folder parent_folder = folder.get_parent() # Delete folder folder.delete() # Success! Send back to index or document specific folder response = redirect('wagtaildocs:index') if parent_folder: response['Location'] += '?folder={0}'.format(parent_folder.id) return response return render(request, 'wagtaildocs/folder/confirm_delete.html', { 'error' : error, 'error_text': error_text, 'folder' : folder, #'form': form, })
def test_basic(self): response = self.get_response() self.assertEqual(response.status_code, 200) self.assertEqual(response['Content-type'], 'application/json') # Will crash if the JSON is invalid content = json.loads(response.content.decode('UTF-8')) # Check that the meta section is there self.assertIn('meta', content) self.assertIsInstance(content['meta'], dict) # Check that the total count is there and correct self.assertIn('total_count', content['meta']) self.assertIsInstance(content['meta']['total_count'], int) self.assertEqual(content['meta']['total_count'], get_document_model().objects.count()) # Check that the items section is there self.assertIn('items', content) self.assertIsInstance(content['items'], list) # Check that each document has a meta section with type and detail_url attributes for document in content['items']: self.assertIn('meta', document) self.assertIsInstance(document['meta'], dict) self.assertEqual(set(document['meta'].keys()), {'type', 'detail_url', 'download_url', 'tags'}) # Type should always be wagtaildocs.Document self.assertEqual(document['meta']['type'], 'wagtaildocs.Document') # Check detail_url self.assertEqual( document['meta']['detail_url'], 'http://localhost/api/v2beta/documents/%d/' % document['id']) # Check download_url self.assertTrue(document['meta']['download_url'].startswith( 'http://localhost/documents/%d/' % document['id']))
def convert_links(links): """ Adds a href to the link with the reative path if a document ID or page ID is stored """ updated = False for link in links: linktype = link.get('linktype') object_id = link.get('id') if link.get('href'): continue # Don't update it if the href is already set if linktype == 'document': doc = get_object_or_404(get_document_model(), id=object_id) url = doc.url elif linktype == 'page': page = Page.objects.get(id=object_id) url = page.relative_url(current_site=page.get_site()) else: continue updated = True link['href'] = url return updated
def delete(request, document_id): Document = get_document_model() doc = get_object_or_404(Document, id=document_id) if not permission_policy.user_has_permission_for_instance(request.user, 'delete', doc): return permission_denied(request) if doc.folder: parent_folder = doc.folder else: parent_folder = False if request.method == 'POST': doc.delete() messages.success(request, _("Document '{0}' deleted.").format(doc.title)) response = redirect('wagtaildocs:index') if parent_folder: response['Location'] += '?folder={0}'.format(parent_folder.id) return response return render(request, "wagtaildocs/documents/confirm_delete.html", { 'document': doc, })
def get_field_display_value(self, field_name, field=None): """ Return a display value for a field """ # First we check for a 'get_fieldname_display' property/method on # the model, and return the value of that, if present. val_funct = getattr(self.instance, 'get_%s_display' % field_name, None) if val_funct is not None: if callable(val_funct): return val_funct() return val_funct # If we have a real field, we can utilise that to try to display # something more useful if field is not None: try: field_type = field.get_internal_type() if ( field_type == 'ForeignKey' and field.related_model == get_image_model() ): # The field is an image return self.get_image_field_display(field_name, field) if ( field_type == 'ForeignKey' and field.related_model == get_document_model() ): # The field is a document return self.get_document_field_display(field_name, field) except AttributeError: pass # Resort to getting the value of 'field_name' from the instance return getattr(self.instance, field_name, self.model_admin.get_empty_value_display(field_name))
def get_context(self): return { 'total_docs': get_document_model().objects.count(), }
def test_delete_document_purges(self, purge): get_document_model().objects.get(id=5).delete() purge.assert_any_call('http://api.example.com/api/v2beta/documents/5/')
def index(request): Document = get_document_model() # Get documents (filtered by user permission) documents = permission_policy.instances_user_has_any_permission_for( request.user, ['change', 'delete'] ) # Ordering if 'ordering' in request.GET and request.GET['ordering'] in ['title', '-created_at']: ordering = request.GET['ordering'] else: ordering = '-created_at' documents = documents.order_by(ordering) # Filter by collection current_collection = None collection_id = request.GET.get('collection_id') if collection_id: try: current_collection = Collection.objects.get(id=collection_id) documents = documents.filter(collection=current_collection) except (ValueError, Collection.DoesNotExist): pass # Search query_string = None if 'q' in request.GET: form = SearchForm(request.GET, placeholder=_("Search documents")) if form.is_valid(): query_string = form.cleaned_data['q'] documents = documents.search(query_string) else: form = SearchForm(placeholder=_("Search documents")) # Pagination paginator, documents = paginate(request, documents) collections = permission_policy.collections_user_has_any_permission_for( request.user, ['add', 'change'] ) if len(collections) < 2: collections = None # Create response if request.is_ajax(): return render(request, 'wagtaildocs/documents/results.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), }) else: return render(request, 'wagtaildocs/documents/index.html', { 'ordering': ordering, 'documents': documents, 'query_string': query_string, 'is_searching': bool(query_string), 'search_form': form, 'popular_tags': Document.popular_tags(), 'user_can_add': permission_policy.user_has_permission(request.user, 'add'), 'collections': collections, 'current_collection': current_collection, })