Beispiel #1
0
    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'])
Beispiel #4
0
    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,
            })
Beispiel #7
0
    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))
Beispiel #8
0
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())
Beispiel #10
0
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,
        },
    )
Beispiel #11
0
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)
Beispiel #12
0
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)}
    )
Beispiel #13
0
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}
    )
Beispiel #14
0
    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'])
Beispiel #15
0
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,
    })
Beispiel #16
0
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,
    })
Beispiel #17
0
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,
    })
Beispiel #18
0
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})
Beispiel #19
0
 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))
Beispiel #20
0
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
Beispiel #21
0
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()
Beispiel #22
0
 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))
Beispiel #23
0
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
        ),
    })
Beispiel #24
0
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
        ),
    })
Beispiel #25
0
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)
Beispiel #26
0
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,
        })
Beispiel #27
0
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'),
            })
Beispiel #28
0
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
    })
Beispiel #29
0
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
Beispiel #30
0
 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)
Beispiel #32
0
 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))
Beispiel #33
0
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)
Beispiel #34
0
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(),
            })
Beispiel #35
0
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})
Beispiel #36
0
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,
        }
Beispiel #37
0
    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>"
Beispiel #38
0
    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>"
Beispiel #39
0
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
Beispiel #40
0
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(),
        })
Beispiel #41
0
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,
    })
Beispiel #42
0
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,
    })
Beispiel #43
0
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,
        })
Beispiel #44
0
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'),
        })
Beispiel #45
0
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,
    })
Beispiel #46
0
 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,
        })
Beispiel #48
0
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,
    })
Beispiel #49
0
    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,
    })
Beispiel #54
0
    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))
Beispiel #55
0
 def get_context(self):
     return {
         'total_docs': get_document_model().objects.count(),
     }
Beispiel #56
0
    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/')
Beispiel #57
0
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,
        })