Exemple #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])
Exemple #2
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'])
Exemple #3
0
    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())
Exemple #4
0
def add(request):
    Document = get_document_model()
    DocumentForm = get_document_form(Document)

    if request.method == '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
            search_index.insert_or_update_object(doc)

            messages.success(request,
                             _("Document '{0}' added.").format(doc.title),
                             buttons=[
                                 messages.button(
                                     reverse('tuiuiudocs:edit',
                                             args=(doc.id, )), _('Edit'))
                             ])
            return redirect('tuiuiudocs:index')
        else:
            messages.error(request,
                           _("The document could not be saved due to errors."))
    else:
        form = DocumentForm(user=request.user)

    return render(request, "tuiuiudocs/documents/add.html", {
        'form': form,
    })
Exemple #5
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, "tuiuiudocs/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, 'tuiuiudocs/chooser/chooser.html',
            'tuiuiudocs/chooser/chooser.js', {
                'documents': documents,
                'uploadform': uploadform,
                'searchform': searchform,
                'collections': collections,
                'is_searching': False,
            })
Exemple #6
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, 'tuiuiudocs/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, 'tuiuiudocs/chooser/chooser.html',
                                 'tuiuiudocs/chooser/chooser.js', {
                                     'documents': documents,
                                     'uploadform': form
                                 })
Exemple #7
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, "tuiuiudocs/documents/usage.html", {
        'document': doc,
        'used_by': used_by
    })
Exemple #8
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)
Exemple #9
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>"
Exemple #10
0
def describe_collection_docs(collection):
    docs_count = get_document_model().objects.filter(
        collection=collection).count()
    if docs_count:
        url = urlresolvers.reverse('tuiuiudocs: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,
        }
Exemple #11
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('tuiuiudocs:index')

    return render(request, "tuiuiudocs/documents/confirm_delete.html", {
        'document': doc,
    })
Exemple #12
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 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 tuiuiudocs.Document
            self.assertEqual(document['meta']['type'], 'tuiuiudocs.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']))
Exemple #13
0
 def get_context(self):
     return {
         'total_docs': get_document_model().objects.count(),
     }
Exemple #14
0
class DocumentsAPIEndpoint(BaseAPIEndpoint):
    base_serializer_class = DocumentSerializer
    filter_backends = [FieldsFilter, OrderingFilter, SearchFilter]
    extra_api_fields = ['title', 'tags']
    name = 'documents'
    model = get_document_model()
Exemple #15
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 tuiuiu.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
Exemple #16
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/')
Exemple #17
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
            search_index.insert_or_update_object(doc)

            messages.success(request,
                             _("Document '{0}' updated").format(doc.title),
                             buttons=[
                                 messages.button(
                                     reverse('tuiuiudocs:edit',
                                             args=(doc.id, )), _('Edit'))
                             ])
            return redirect('tuiuiudocs: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('tuiuiudocs:delete', args=(doc.id, )),
                                _('Delete'))
            ])

    return render(
        request, "tuiuiudocs/documents/edit.html", {
            'document':
            doc,
            'filesize':
            filesize,
            'form':
            form,
            'user_can_delete':
            permission_policy.user_has_permission_for_instance(
                request.user, 'delete', doc),
        })
Exemple #18
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, 'tuiuiudocs/documents/results.html', {
                'ordering': ordering,
                'documents': documents,
                'query_string': query_string,
                'is_searching': bool(query_string),
            })
    else:
        return render(
            request, 'tuiuiudocs/documents/index.html', {
                'ordering':
                ordering,
                'documents':
                documents,
                'query_string':
                query_string,
                'is_searching':
                bool(query_string),
                'search_form':
                form,
                'popular_tags':
                popular_tags_for_model(Document),
                'user_can_add':
                permission_policy.user_has_permission(request.user, 'add'),
                'collections':
                collections,
                'current_collection':
                current_collection,
            })
Exemple #19
0
def document_chosen(request, document_id):
    document = get_object_or_404(get_document_model(), id=document_id)

    return render_modal_workflow(
        request, None, 'tuiuiudocs/chooser/document_chosen.js',
        {'document_json': get_document_json(document)})
Exemple #20
0
from __future__ import absolute_import, unicode_literals

from tuiuiu.tuiuiucore.permission_policies.collections import CollectionOwnershipPermissionPolicy
from tuiuiu.tuiuiudocs.models import Document, get_document_model

permission_policy = CollectionOwnershipPermissionPolicy(
    get_document_model(),
    auth_model=Document,
    owner_field_name='uploaded_by_user'
)
Exemple #21
0
 def target_model(self):
     from tuiuiu.tuiuiudocs.models import get_document_model
     return get_document_model()
Exemple #22
0
 def __init__(self, **kwargs):
     super(AdminDocumentChooser, self).__init__(**kwargs)
     self.document_model = get_document_model()