def test_list_attachments_in_details(self):
        self.createAttachment(self.object)
        self.user.user_permissions.add(
            Permission.objects.get(codename='read_dummymodel'))
        self.user.user_permissions.add(
            Permission.objects.get(codename='read_attachment'))
        self.client.login(username='******', password='******')
        response = self.client.get(
            '/dummymodel/{pk}/'.format(pk=self.object.pk))

        html = response.content
        self.assertTemplateUsed(response,
                                template_name='paperclip/attachment_list.html')

        self.assertEqual(
            1,
            len(get_attachment_model().objects.attachments_for_object(
                self.object)))

        self.assertNotIn("Submit attachment", html)

        for attachment in get_attachment_model(
        ).objects.attachments_for_object(self.object):
            self.assertIn(attachment.legend, html)
            self.assertIn(attachment.title, html)
            self.assertIn(attachment.attachment_file.url, html)
            self.assertIn('paperclip/fileicons/odt.png', html)
Beispiel #2
0
 def setUpTestData(cls):
     cls.user = User.objects.create_user("foo_user", password="******", last_name="foo lastname",
                                         first_name="foo firstname")
     object = TestObject.objects.create(name="foo object")
     cls.filetype = get_filetype_model().objects.create(type="foo filetype")
     get_attachment_model().objects.create(content_object=object, filetype=cls.filetype,
                                           attachment_file="foo_file.txt", creator=cls.user, author="foo author",
                                           title="foo title", legend="foo legend", starred=True)
     cls.pk = object.pk
Beispiel #3
0
def serve_attachment(request, path):
    """
    Serve media/ for authorized users only, since it can contain sensitive
    information (uploaded documents)
    """
    original_path = re.sub(r'\.\d+x\d+_q\d+(_crop)?\.(jpg|png|jpeg)$', '', path, count=1, flags=re.IGNORECASE)
    attachment = get_object_or_404(get_attachment_model(), attachment_file=original_path)
    obj = attachment.content_object
    if not issubclass(obj._meta.model, mapentity_models.MapEntityMixin):
        raise Http404
    if not obj.is_public():
        if not request.user.is_authenticated:
            raise PermissionDenied
        if not request.user.has_perm(get_attachment_permission('read_attachment')):
            raise PermissionDenied
        if not request.user.has_perm('{}.read_{}'.format(obj._meta.app_label, obj._meta.model_name)):
            raise PermissionDenied

    content_type, encoding = mimetypes.guess_type(path)

    if settings.DEBUG:
        response = static.serve(request, path, settings.MEDIA_ROOT)
    else:
        response = HttpResponse()
        response[app_settings['SENDFILE_HTTP_HEADER']] = os.path.join(settings.MEDIA_URL_SECURE, path)
    response["Content-Type"] = content_type or 'application/octet-stream'
    if encoding:
        response["Content-Encoding"] = encoding
    if app_settings['SERVE_MEDIA_AS_ATTACHMENT']:
        response['Content-Disposition'] = "attachment; filename={0}".format(
            os.path.basename(path))
    return response
 def test_filename_is_used_if_no_title(self):
     data = self.attachmentPostData()
     data['title'] = ''
     self.client.post(add_url_for_obj(self.object), data=data)
     att = get_attachment_model().objects.attachments_for_object(
         self.object).get()
     self.assertTrue('face' in att.attachment_file.name)
Beispiel #5
0
 def setUpTestData(cls):
     cls.user = User.objects.create_user("foo_user",
                                         password="******",
                                         last_name="foo lastname",
                                         first_name="foo firstname")
     object = TestObject.objects.create(name="foo object")
     cls.filetype = get_filetype_model().objects.create(type="foo filetype")
     get_attachment_model().objects.create(content_object=object,
                                           filetype=cls.filetype,
                                           attachment_file="foo_file.txt",
                                           creator=cls.user,
                                           author="foo author",
                                           title="foo title",
                                           legend="foo legend",
                                           starred=True)
     cls.pk = object.pk
Beispiel #6
0
 def test_upload_creates_attachment(self):
     data = self.attachmentPostData()
     self.client.post(add_url_for_obj(self.object), data=data)
     att = get_attachment_model().objects.attachments_for_object(self.object).get()
     self.assertEqual(att.title, data['title'])
     self.assertEqual(att.legend, data['legend'])
     self.assertEqual(att.filetype.pk, data['filetype'])
Beispiel #7
0
 def test_add_view(self):
     perm = Permission.objects.get(codename='add_attachment')
     self.user.user_permissions.add(perm)
     self.client.login(username="******", password="******")
     response = self.client.post('/paperclip/add-for/test_app/testobject/{pk}/'.format(pk=self.pk),
                                 {'embed': False, 'filetype': self.filetype.pk, 'next': '/foo-url/'})
     self.assertRedirects(response, "/foo-url/",  fetch_redirect_response=False)
     self.assertQuerysetEqual(get_attachment_model().objects.all(),
                              ('<Attachment: foo_user attached >', '<Attachment: foo_user attached foo_file.txt>'))
    def test_list_attachments_in_details(self):
        self.createAttachment(self.object)
        self.user.user_permissions.add(Permission.objects.get(codename='read_dummymodel'))
        self.user.user_permissions.add(Permission.objects.get(codename='read_attachment'))
        self.client.login(username='******', password='******')
        response = self.client.get('/dummymodel/{pk}/'.format(pk=self.object.pk))

        html = response.content
        self.assertTemplateUsed(response, template_name='paperclip/attachment_list.html')

        self.assertEqual(1, len(get_attachment_model().objects.attachments_for_object(self.object)))

        self.assertNotIn(b"Submit attachment", html)

        for attachment in get_attachment_model().objects.attachments_for_object(self.object):
            self.assertIn(attachment.legend.encode(), html)
            self.assertIn(attachment.title.encode(), html)
            self.assertIn(attachment.attachment_file.url.encode(), html)
            self.assertIn(b'paperclip/fileicons/odt.png', html)
Beispiel #9
0
 def createAttachment(self, obj):
     uploaded = SimpleUploadedFile('file.odt',
                                   b'*' * 128,
                                   content_type='application/vnd.oasis.opendocument.text')
     kwargs = {
         'content_type': ContentType.objects.get_for_model(obj),
         'object_id': obj.pk,
         'filetype': get_filetype_model().objects.create(),
         'creator': self.user,
         'title': "Attachment title",
         'legend': "Attachment legend",
         'attachment_file': uploaded
     }
     return get_attachment_model().objects.create(**kwargs)
Beispiel #10
0
 class Meta:
     model = settings.get_attachment_model()
     if settings.PAPERCLIP_ENABLE_VIDEO and not settings.PAPERCLIP_ENABLE_LINK:
         fields = ('embed', 'attachment_file', 'attachment_video',
                   'filetype', 'author', 'title', 'legend')
     elif settings.PAPERCLIP_ENABLE_VIDEO and settings.PAPERCLIP_ENABLE_LINK:
         fields = ('embed', 'attachment_file', 'attachment_video',
                   'attachment_link', 'filetype', 'author', 'title',
                   'legend')
     elif settings.PAPERCLIP_ENABLE_LINK and not settings.PAPERCLIP_ENABLE_VIDEO:
         fields = ('embed', 'attachment_file', 'attachment_link',
                   'filetype', 'author', 'title', 'legend')
     else:
         fields = ('attachment_file', 'filetype', 'author', 'title',
                   'legend')
Beispiel #11
0
    def handle(self, *args, **options):
        interactive = options['interactive']
        verbosity = int(options.get('verbosity', 1))
        files = get_attachment_model().objects.order_by('attachment_file')
        files = files.values_list('attachment_file', flat=True)
        to_keep = [
            os.path.join(settings.MEDIA_ROOT, path) for f in files
            for path in splits(f)
        ]
        to_keep = list(set(to_keep))
        to_keep.sort(path_cmp)
        to_delete = []
        for root, dirs, files in os.walk(PAPERCLIP_ROOT):
            for basename in chain(files, [d + '/' for d in dirs]):
                f = os.path.join(root, basename)
                if f not in to_keep:
                    to_delete.append(f)
        to_delete.sort(path_cmp)
        if not to_delete and verbosity >= 1:
            self.stdout.write("No obsolete attached file to "
                              "remove from disk.\n")
        if to_delete and interactive:
            self.stdout.write("You have requested to remove obsolete attached "
                              "files from disk.\n\n")
            for f in to_delete:
                self.stdout.write("    {}".format(f))
            confirm = input("""
This will permanently delete these files above!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: """)
            if confirm != 'yes':
                raise CommandError("Removing obsolete attached files "
                                   "cancelled.")
        for path in to_delete:
            if path.endswith('/'):
                os.rmdir(path)
            else:
                os.remove(path)
        if to_delete and verbosity >= 1:
            values = {
                'n': len(to_delete),
                's': "s" if len(to_delete) > 1 else "",
            }
            self.stdout.write("{n} obsolete attached file{s} removed from "
                              "disk.\n".format(**values))
    def render(self, context):
        obj = self.resolve(self.obj, context)
        var_name = self.resolve(self.var_name, context)
        if self.file_type:
            file_type = self.resolve(self.file_type, context)
        else:
            file_type = None

        if file_type:
            method = 'attachments_for_object_only_type'
            args = [obj, file_type]
        else:
            method = 'attachments_for_object'
            args = [obj]

        context[var_name] = getattr(settings.get_attachment_model().objects, method)(*args)
        return ''
Beispiel #13
0
    def render(self, context):
        obj = self.resolve(self.obj, context)
        var_name = self.resolve(self.var_name, context)
        if self.file_type:
            file_type = self.resolve(self.file_type, context)
        else:
            file_type = None

        if file_type:
            method = 'attachments_for_object_only_type'
            args = [obj, file_type]
        else:
            method = 'attachments_for_object'
            args = [obj]

        context[var_name] = getattr(settings.get_attachment_model().objects, method)(*args)
        return ''
Beispiel #14
0
 def test_add_view(self):
     perm = Permission.objects.get(codename='add_attachment')
     self.user.user_permissions.add(perm)
     self.client.login(username="******", password="******")
     response = self.client.post(
         '/paperclip/add-for/test_app/testobject/{pk}/'.format(pk=self.pk),
         {
             'embed': False,
             'filetype': self.filetype.pk,
             'next': '/foo-url/'
         })
     self.assertRedirects(response,
                          "/foo-url/",
                          fetch_redirect_response=False)
     self.assertQuerysetEqual(
         get_attachment_model().objects.all(),
         ('<Attachment: foo_user attached >',
          '<Attachment: foo_user attached foo_file.txt>'))
    def handle(self, *args, **options):
        interactive = options['interactive']
        verbosity = int(options.get('verbosity', 1))
        files = get_attachment_model().objects.order_by('attachment_file')
        files = files.values_list('attachment_file', flat=True)
        to_keep = [os.path.join(settings.MEDIA_ROOT, path)
                   for f in files for path in splits(f)]
        to_keep = list(set(to_keep))
        to_keep.sort(path_cmp)
        to_delete = []
        for root, dirs, files in os.walk(PAPERCLIP_ROOT):
            for basename in chain(files, [d + '/' for d in dirs]):
                f = os.path.join(root, basename)
                if f not in to_keep:
                    to_delete.append(f)
        to_delete.sort(path_cmp)
        if not to_delete and verbosity >= 1:
            self.stdout.write("No obsolete attached file to "
                              "remove from disk.\n")
        if to_delete and interactive:
            self.stdout.write("You have requested to remove obsolete attached "
                              "files from disk.\n\n")
            for f in to_delete:
                self .stdout.write("    {}".format(f))
            confirm = input("""
This will permanently delete these files above!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: """)
            if confirm != 'yes':
                raise CommandError("Removing obsolete attached files "
                                   "cancelled.")
        for path in to_delete:
            if path.endswith('/'):
                os.rmdir(path)
            else:
                os.remove(path)
        if to_delete and verbosity >= 1:
            values = {
                'n': len(to_delete),
                's': "s" if len(to_delete) > 1 else "",
            }
            self.stdout.write("{n} obsolete attached file{s} removed from "
                              "disk.\n".format(**values))
Beispiel #16
0
def update_attachment(request,
                      attachment_pk,
                      attachment_form=AttachmentForm,
                      extra_context=None):
    attachment = get_object_or_404(settings.get_attachment_model(),
                                   pk=attachment_pk)
    obj = attachment.content_object
    if request.method == 'POST':
        form = attachment_form(request,
                               request.POST,
                               request.FILES,
                               instance=attachment,
                               object=obj)
    else:
        form = attachment_form(request, instance=attachment, object=obj)
    return _handle_attachment_form(request, obj, form,
                                   _('Update attachment %s'),
                                   _('Your attachment was updated.'),
                                   extra_context)
Beispiel #17
0
def star_attachment(request, attachment_pk):
    g = get_object_or_404(settings.get_attachment_model(), pk=attachment_pk)
    g.starred = request.GET.get('unstar') is None
    g.save()
    if g.starred:
        change_message = _('Star attachment %s')
    else:
        change_message = _('Unstar attachment %s')
    if settings.PAPERCLIP_ACTION_HISTORY_ENABLED:
        LogEntry.objects.log_action(
            user_id=request.user.pk,
            content_type_id=g.content_type.id,
            object_id=g.object_id,
            object_repr=force_text(g.content_object),
            action_flag=CHANGE,
            change_message=change_message % g.title,
        )
    reply = {'status': 'ok', 'starred': g.starred}
    return JsonResponse(reply)
Beispiel #18
0
def update_attachment(request, attachment_pk,
                      attachment_form=AttachmentForm,
                      extra_context=None):
    attachment = get_object_or_404(settings.get_attachment_model(), pk=attachment_pk)
    obj = attachment.content_object
    if request.method == 'POST':
        form = attachment_form(
            request, request.POST, request.FILES,
            instance=attachment,
            object=obj)
    else:
        form = attachment_form(
            request,
            instance=attachment,
            object=obj)
    return _handle_attachment_form(request, obj, form,
                                   _('Update attachment %s'),
                                   _('Your attachment was updated.'),
                                   extra_context)
Beispiel #19
0
def get_attachments(request, app_label, model_name, pk):

    try:
        ct = ContentType.objects.get_by_natural_key(app_label, model_name)
    except ContentType.DoesNotExist:
        raise Http404
    attachments = settings.get_attachment_model().objects.filter(
        content_type=ct, object_id=pk)
    reply = [{
        'id': attachment.id,
        'title': attachment.title,
        'legend': attachment.legend,
        'url': attachment.attachment_file.url,
        'type': attachment.filetype.type,
        'author': attachment.author,
        'filename': attachment.filename,
        'mimetype': attachment.mimetype,
        'is_image': attachment.is_image,
        'starred': attachment.starred,
    } for attachment in attachments]
    return JsonResponse(reply)
Beispiel #20
0
def delete_attachment(request, attachment_pk):
    g = get_object_or_404(settings.get_attachment_model(), pk=attachment_pk)
    can_delete = (request.user.has_perm('paperclip.delete_attachment_others')
                  or request.user == g.creator)
    if can_delete:
        g.delete()
        if settings.PAPERCLIP_ACTION_HISTORY_ENABLED:
            LogEntry.objects.log_action(
                user_id=request.user.pk,
                content_type_id=g.content_type.id,
                object_id=g.object_id,
                object_repr=force_text(g.content_object),
                action_flag=CHANGE,
                change_message=_('Remove attachment %s') % g.title,
            )
        messages.success(request, _('Your attachment was deleted.'))
    else:
        error_msg = _('You are not allowed to delete this attachment.')
        messages.error(request, error_msg)
    next_url = request.GET.get('next', '/')
    return HttpResponseRedirect(next_url)
Beispiel #21
0
def star_attachment(request, attachment_pk):
    g = get_object_or_404(settings.get_attachment_model(), pk=attachment_pk)
    g.starred = request.GET.get('unstar') is None
    g.save()
    if g.starred:
        change_message = _('Star attachment %s')
    else:
        change_message = _('Unstar attachment %s')
    if settings.PAPERCLIP_ACTION_HISTORY_ENABLED:
        LogEntry.objects.log_action(
            user_id=request.user.pk,
            content_type_id=g.content_type.id,
            object_id=g.object_id,
            object_repr=force_text(g.content_object),
            action_flag=CHANGE,
            change_message=change_message % g.title,
        )
    reply = {
        'status': 'ok',
        'starred': g.starred
    }
    return JsonResponse(reply)
Beispiel #22
0
def delete_attachment(request, attachment_pk):
    g = get_object_or_404(settings.get_attachment_model(), pk=attachment_pk)
    can_delete = (
        request.user.has_perm(settings.get_attachment_permission('delete_attachment_others')) or
        request.user == g.creator)
    if can_delete:
        g.delete()
        if settings.PAPERCLIP_ACTION_HISTORY_ENABLED:
            LogEntry.objects.log_action(
                user_id=request.user.pk,
                content_type_id=g.content_type.id,
                object_id=g.object_id,
                object_repr=force_text(g.content_object),
                action_flag=CHANGE,
                change_message=_('Remove attachment %s') % g.title,
            )
        messages.success(request, _('Your attachment was deleted.'))
    else:
        error_msg = _('You are not allowed to delete this attachment.')
        messages.error(request, error_msg)
    next_url = request.GET.get('next', '/')
    return HttpResponseRedirect(next_url)
Beispiel #23
0
def get_attachments(request, app_label, model_name, pk):

    try:
        ct = ContentType.objects.get_by_natural_key(app_label, model_name)
    except ContentType.DoesNotExist:
        raise Http404
    attachments = settings.get_attachment_model().objects.filter(content_type=ct, object_id=pk)
    reply = [
        {
            'id': attachment.id,
            'title': attachment.title,
            'legend': attachment.legend,
            'url': attachment.attachment_file.url,
            'type': attachment.filetype.type,
            'author': attachment.author,
            'filename': attachment.filename,
            'mimetype': attachment.mimetype,
            'is_image': attachment.is_image,
            'starred': attachment.starred,
        }
        for attachment in attachments
    ]
    return JsonResponse(reply)
 def test_title_gives_name_to_file(self):
     data = self.attachmentPostData()
     self.client.post(add_url_for_obj(self.object), data=data)
     att = get_attachment_model().objects.attachments_for_object(self.object).get()
     self.assertTrue('a-title' in att.attachment_file.name)
Beispiel #25
0
def create_mapentity_model_permissions(model):
    """
    Create all the necessary permissions for the specified model.

    And give all the required permission to the ``internal_user``, used
    for screenshotting and document conversion.

    :notes:

        Could have been implemented a metaclass on `MapEntityMixin`. We chose
        this approach to avoid problems with inheritance of permissions on
        abstract models.

        See:
            * https://code.djangoproject.com/ticket/10686
            * http://stackoverflow.com/a/727956/141895
    """
    if not issubclass(model, mapentity_models.MapEntityMixin):
        return

    db = DEFAULT_DB_ALIAS

    internal_user = get_internal_user()
    perms_manager = Permission.objects.using(db)

    permissions = set()
    for view_kind in mapentity_models.ENTITY_KINDS:
        perm = model.get_entity_kind_permission(view_kind)
        codename = auth.get_permission_codename(perm, model._meta)
        name = "Can %s %s" % (perm, model._meta.verbose_name_raw)
        permissions.add((codename, _(name)))

    ctype = ContentType.objects.db_manager(db).get_for_model(model)
    for (codename, name) in permissions:
        p, created = perms_manager.get_or_create(codename=codename,
                                                 content_type=ctype)
        if created:
            p.name = name[:50]
            p.save()
            logger.info("Permission '%s' created." % codename)

    for view_kind in (mapentity_models.ENTITY_LIST,
                      mapentity_models.ENTITY_DOCUMENT):
        perm = model.get_entity_kind_permission(view_kind)
        codename = auth.get_permission_codename(perm, model._meta)

        internal_user_permission = internal_user.user_permissions.filter(codename=codename,
                                                                         content_type=ctype)

        if not internal_user_permission.exists():
            permission = perms_manager.get(codename=codename, content_type=ctype)
            internal_user.user_permissions.add(permission)
            logger.info("Added permission %s to internal user %s" % (codename,
                                                                     internal_user))

    attachmenttype = ContentType.objects.db_manager(db).get_for_model(get_attachment_model())
    read_perm = dict(codename='read_attachment', content_type=attachmenttype)
    if not internal_user.user_permissions.filter(**read_perm).exists():
        permission = perms_manager.get(**read_perm)
        internal_user.user_permissions.add(permission)
        logger.info("Added permission %s to internal user %s" % (permission.codename,
                                                                 internal_user))
 def test_filename_is_used_if_no_title(self):
     data = self.attachmentPostData()
     data['title'] = ''
     self.client.post(add_url_for_obj(self.object), data=data)
     att = get_attachment_model().objects.attachments_for_object(self.object).get()
     self.assertTrue('face' in att.attachment_file.name)
Beispiel #27
0
from django.contrib import admin
from paperclip import settings
from paperclip.admin import AttachmentInlines
from .models import TestObject

admin.site.register(settings.get_filetype_model())
admin.site.register(settings.get_attachment_model())


@admin.register(TestObject)
class TestObjectAdmin(admin.ModelAdmin):
    inlines = [AttachmentInlines]
 def test_title_gives_name_to_file(self):
     data = self.attachmentPostData()
     self.client.post(add_url_for_obj(self.object), data=data)
     att = get_attachment_model().objects.attachments_for_object(
         self.object).get()
     self.assertTrue('a-title' in att.attachment_file.name)
Beispiel #29
0
from django.contrib import admin
from paperclip import settings
from paperclip.admin import AttachmentInlines
from .models import TestObject


admin.site.register(settings.get_filetype_model())
admin.site.register(settings.get_attachment_model())


@admin.register(TestObject)
class TestObjectAdmin(admin.ModelAdmin):
    inlines = [AttachmentInlines]
Beispiel #30
0
class AttachmentInlines(GenericStackedInline):
    model = settings.get_attachment_model()
    extra = 1