Ejemplo n.º 1
0
def upload_file(request):
    """
    POSTing a file upload is very different than any other endpoint in assembl
    API because all of the content will be passed in using a MULTIPART_HEADER,
    with all of data as well as the file (along with its metadata)
    """

    # Testing purposes on front-end
    # raise Exception("Upload file exception occured!")

    db = Document.default_db
    ctx = request.context
    user_id = authenticated_userid(request) or Everyone
    discusison_id = ctx.get_discussion_id()
    discussion = Discussion.get(discusison_id)

    mime = request.POST['mime_type']
    file_name = request.POST['name']

    # Check if the file has previously existed, if so, change the name by appending "(n)"
    # to it's name

    try:
        blob = File(discussion=discussion, mime_type=mime, title=file_name)
        db.add(blob)
        with request.POST['file'].file as f:
            blob.add_file_data(f)
        db.flush()
    except Exception as e:
        raise HTTPServerError(e)

    view = 'default'
    return blob.generic_json(view, user_id, ctx.get_permissions())
Ejemplo n.º 2
0
def mime_type(request):
    url = request.params.get('url', None)
    if not url:
        raise HTTPBadRequest("Missing 'url' parameter")
    parsed = urlparse(url)
    if not parsed or parsed.scheme not in ('http', 'https'):
        raise HTTPBadRequest("Wrong scheme")
    if parsed.netloc.split(":")[0] == config.get('public_hostname'):
        # is it one of our own documents?
        # If so, detect it and shortcut to avoid the pyramid handler calling
        # another pyramid handler, as this exhausts pyramid threads rapidly
        # and can deadlock the whole application
        r = re.match(
            r'^https?://[\w\.]+(?:\:\d+)?/data/.*/documents/(\d+)/data(?:\?.*)?$',
            url)
        if r:
            document_id = r.groups(0)[0]
            from sqlalchemy.sql.functions import func
            mimetype, create_date, file_identity = File.default_db.query(
                File.mime_type, File.creation_date,
                file.file_identity).filter_by(id=int(document_id)).first()
            size = path.getsize(File.path_of(file_identity))
            return Response(body=None,
                            content_type=str(mimetype),
                            content_length=size,
                            last_modified=create_date)
    try:
        result = requests.head(url, timeout=15)
    except requests.ConnectionError:
        return Response(status=503, location=url)

    return Response(content_type=result.headers.get('Content-Type', None),
                    status=result.status_code,
                    location=result.url)
Ejemplo n.º 3
0
def get_file(request):
    # TODO: Add a route that enables the call to have the filename
    # appended to the end. This is so that gmail can read the services
    # Read more here:
    # http://stackoverflow.com/questions/20903967/gmails-new-image-caching-is-breaking-image-links-in-newsletter
    ctx = request.context
    document = ctx._instance
    f = File.get(document.id)
    return Response(body=f.data, content_type=str(f.mime_type))
Ejemplo n.º 4
0
def simple_file(request, discussion, test_session):
    from assembl.models import File
    f = File(discussion=discussion,
             mime_type='image/png',
             title='simple_image.png')

    test_session.add(f)
    f.add_raw_data(os.urandom(256))
    test_session.flush()

    def fin():
        print("finalizer simple_file")
        f.delete_file()
        test_session.delete(f)
        test_session.flush()

    request.addfinalizer(fin)
    return f
Ejemplo n.º 5
0
def simple_file2(request, discussion, test_session):
    from assembl.models import File
    f = File(discussion=discussion,
             mime_type='application/pdf',
             title='mydocument.pdf')

    test_session.add(f)
    f.add_raw_data(os.urandom(256))
    test_session.flush()

    def fin():
        print("finalizer simple_file")
        f.delete_file()
        test_session.delete(f)
        test_session.flush()

    request.addfinalizer(fin)
    return f
Ejemplo n.º 6
0
def get_file_header(request):
    ctx = request.context
    document = ctx._instance
    f = File.get(document.id)
    if f.infected:
        raise HTTPNotAcceptable("Infected with a virus")
    handoff_to_nginx = asbool(config.get('handoff_to_nginx', False))

    return Response(
        content_length=f.size,
        content_type=str(f.mime_type),
        last_modified=f.creation_date,
        expires=datetime.now() + timedelta(days=365),
        accept_ranges="bytes" if handoff_to_nginx else "none",
    )
Ejemplo n.º 7
0
def get_file_header(request):
    ctx = request.context
    document = ctx._instance
    f = File.get(document.id)
    if f.infected:
        raise HTTPNotAcceptable("Infected with a virus")
    handoff_to_nginx = asbool(config.get('handoff_to_nginx', False))

    return Response(
        content_length=f.size,
        content_type=str(f.mime_type),
        last_modified=f.creation_date,
        expires=datetime.now()+timedelta(days=365),
        accept_ranges="bytes" if handoff_to_nginx else "none",
    )
Ejemplo n.º 8
0
def upload_file(request):
    """
    POSTing a file upload is very different than any other endpoint in assembl
    API because all of the content will be passed in using a MULTIPART_HEADER,
    with all of data as well as the file (along with its metadata)
    """

    # Testing purposes on front-end
    # raise Exception("Upload file exception occured!")

    db = Document.default_db
    ctx = request.context
    user_id = request.authenticated_userid or Everyone
    discusison_id = ctx.get_discussion_id()
    discussion = Discussion.get(discusison_id)
    permissions = get_permissions(user_id, discusison_id)

    mime = request.POST['mime_type']
    file_name = request.POST['name']

    # Check if the file has previously existed, if so, change the name by appending "(n)"
    # to it's name

    try:
        blob = File(discussion=discussion,
                    mime_type=mime,
                    title=file_name)
        db.add(blob)
        with request.POST['file'].file as f:
            blob.add_file_data(f)
        db.flush()
    except Exception as e:
        raise HTTPServerError(e)

    view = 'default'
    return blob.generic_json(view, user_id, permissions)
Ejemplo n.º 9
0
def get_file(request):
    # TODO: Add a route that enables the call to have the filename
    # appended to the end. This is so that gmail can read the services
    # Read more here:
    # http://stackoverflow.com/questions/20903967/gmails-new-image-caching-is-breaking-image-links-in-newsletter
    ctx = request.context
    document = ctx._instance
    f = File.get(document.id)
    if f.infected:
        raise HTTPNotAcceptable("Infected with a virus")
    escaped_double_quotes_filename = (f.title
        .replace(u'"', u'\\"')
        .encode('iso-8859-1', 'replace'))
    url_quoted_utf8_filename = url_quote(f.title.encode('utf-8'))
    handoff_to_nginx = asbool(config.get('handoff_to_nginx', False))
    if handoff_to_nginx:
        kwargs = dict(body='')
    else:
        if 'Range' in request.headers:
            raise HTTPRequestRangeNotSatisfiable()
        fs = open(f.path, 'rb')
        app_iter = None
        environ = request.environ
        if 'wsgi.file_wrapper' in environ:
            app_iter = environ['wsgi.file_wrapper'](fs, _BLOCK_SIZE)
        if app_iter is None:
            app_iter = FileIter(fs, _BLOCK_SIZE)
        kwargs=dict(app_iter=app_iter)

    r = Response(
        content_length=f.size,
        content_type=str(f.mime_type),
        last_modified=f.creation_date,
        expires=datetime.now()+timedelta(days=365),
        accept_ranges="bytes" if handoff_to_nginx else "none",
        content_disposition=
            'attachment; filename="%s"; filename*=utf-8\'\'%s' # RFC 6266
            % (escaped_double_quotes_filename, url_quoted_utf8_filename),
        **kwargs
    )
    if handoff_to_nginx:
        r.headers[b'X-Accel-Redirect'] = f.handoff_url
    return r
Ejemplo n.º 10
0
def get_file(request):
    # TODO: Add a route that enables the call to have the filename
    # appended to the end. This is so that gmail can read the services
    # Read more here:
    # http://stackoverflow.com/questions/20903967/gmails-new-image-caching-is-breaking-image-links-in-newsletter
    if request.method == 'HEAD':
        # GET view_config captures HEAD...
        return get_file_header(request)
    ctx = request.context
    document = ctx._instance
    f = File.get(document.id)
    if f.infected:
        raise HTTPNotAcceptable("Infected with a virus")
    handoff_to_nginx = asbool(config.get('handoff_to_nginx', False))
    if handoff_to_nginx:
        kwargs = dict(body='')
    else:
        if 'Range' in request.headers:
            raise HTTPRequestRangeNotSatisfiable()
        fs = f.file_stream
        app_iter = None
        environ = request.environ
        if 'wsgi.file_wrapper' in environ and f.path:
            app_iter = environ['wsgi.file_wrapper'](fs, _BLOCK_SIZE)
        if app_iter is None:
            app_iter = FileIter(fs, _BLOCK_SIZE)
        kwargs = dict(app_iter=app_iter)

    r = Response(
        content_length=f.file_size,
        content_type=str(f.mime_type),
        last_modified=f.creation_date,
        expires=datetime.now() + timedelta(days=365),
        accept_ranges="bytes" if handoff_to_nginx else "none",
        content_disposition=disposition(f.title),  # RFC 6266
        **kwargs
    )
    if handoff_to_nginx:
        r.headers[b'X-Accel-Redirect'] = f.handoff_url
    return r
Ejemplo n.º 11
0
def mime_type(request):
    url = request.params.get('url', None)
    if not url:
        raise HTTPBadRequest("Missing 'url' parameter")
    parsed = urlparse(url)
    if not parsed or parsed.scheme not in ('http', 'https'):
        raise HTTPBadRequest("Wrong scheme")
    if parsed.netloc.split(":")[0] == config.get('public_hostname'):
        # is it one of our own documents?
        # If so, detect it and shortcut to avoid the pyramid handler calling
        # another pyramid handler, as this exhausts pyramid threads rapidly
        # and can deadlock the whole application
        r = re.match(
            r'^https?://[\w\.]+(?:\:\d+)?/data/.*/documents/(\d+)/data(?:\?.*)?$',
            url)
        if r:
            document_id = r.groups(0)[0]
            from sqlalchemy.sql.functions import func
            mimetype, create_date, file_identity = File.default_db.query(
                File.mime_type, File.creation_date, file.file_identity
                ).filter_by(id=int(document_id)).first()
            size = path.getsize(File.path_of(file_identity))
            return Response(
                body=None, content_type=str(mimetype),
                content_length=size, last_modified=create_date)
    try:
        result = requests.head(url, timeout=15)
    except requests.ConnectionError:
        return Response(
            status=503,
            location=url)

    return Response(
        content_type=result.headers.get('Content-Type', None),
        status=result.status_code,
        location=result.url)
Ejemplo n.º 12
0
def discussion(request, test_session, participant2_user, default_preferences):
    """An empty Discussion fixture with default preferences"""
    from assembl.models import Discussion, DiscussionAttachment, File, LangString, AttachmentPurpose
#    from assembl.lib.migration import create_default_discussion_data
    with test_session.no_autoflush:
        d = Discussion(
            topic=u"Jack Layton", slug="jacklayton2",
            subscribe_to_notifications_on_signup=False,
            creation_date=datetime.datetime.utcnow(),
            creator=None,
            session=test_session)
        d.discussion_locales = ['en', 'fr', 'de']
        d.legal_notice = LangString.create(
            u"We need to input the optical HDD sensor!", "en")
        tac = LangString.create(
            u"You can't quantify the driver without quantifying the 1080p JSON protocol!", "en")
        tac.add_value(
            u"Vous ne pouvez pas mesurer le driver sans mesurer le protocole JSON en 1080p", u"fr")
        d.terms_and_conditions = tac

        title = LangString.create(
            u"Faut-il manger des bananes ?", u"fr")
        title.add_value(
            u"Should we eat bananas?", u"en")
        d.title = title

        subtitle = LangString.create(
            u"Dis-moi ce que tu manges et je te dirai qui tu es", u"fr")
        subtitle.add_value(
            u"Tell me what you eat and I will tell you who you are", u"en")
        d.subtitle = subtitle

        button_label = LangString.create(
            u"Discuter des bananes", u"fr")
        button_label.add_value(
            u"Discuss bananas", u"en")
        d.button_label = button_label

        # add a privacy policy attachment to the discussion
        document = File(
            discussion=d,
            mime_type='image/png',
            title='simple_image.png'
        )
        test_session.add(document)
        document.add_raw_data(os.urandom(256))
        test_session.add(document)
        attachment = DiscussionAttachment(
            discussion=d,
            document=document,
            creator_id=participant2_user.id,
            title='A privacy policy attachment',
            attachmentPurpose=AttachmentPurpose.PRIVACY_POLICY_ATTACHMENT.value
        )

        test_session.add(attachment)
        test_session.add(d)
        # create_default_discussion_data(d)
        # Don't create default discussion data (permissions, sections) here
        # because it takes too much time to run all tests.
        # If you need sections or permissions in your tests, execute
        # create_default_discussion_data, create_default_discussion_sections
        # or create_default_permissions in your specific test or
        # use discussion_with_default_data fixture.
        # If you do permissions tests, be aware that the admin user
        # having R_SYSADMIN is actually a special case, see
        # auth/utils.py:get_permissions, it doesn't use discussion permissions
        # at all. So you need discussion permissions if you test with the
        # unauthenticated user Everyone or a user not having the R_SYSADMIN role.
    test_session.flush()

    def fin():
        print("finalizer discussion")
        discussion = d
        if inspect(discussion).detached:
            # How did this happen?
            discussion = test_session.query(Discussion).get(d.id)
        test_session.delete(attachment)
        test_session.delete(document)
        test_session.delete(discussion.table_of_contents)
        test_session.delete(discussion.root_idea)
        test_session.delete(discussion.next_synthesis)
        preferences = discussion.preferences
        discussion.preferences = None
        discussion.preferences_id = None
        for ut in discussion.user_templates:
            for ns in ut.notification_subscriptions:
                ns.delete()
            ut.delete()
        test_session.delete(preferences)
        test_session.delete(discussion)
        test_session.flush()
    request.addfinalizer(fin)
    return d
Ejemplo n.º 13
0
def discussion(request, test_session, participant2_user, default_preferences):
    """An empty Discussion fixture with default preferences"""
    from assembl.models import Discussion, DiscussionAttachment, File, LangString, AttachmentPurpose
#    from assembl.lib.migration import create_default_discussion_data
    with test_session.no_autoflush:
        d = Discussion(
            topic=u"Jack Layton", slug="jacklayton2",
            subscribe_to_notifications_on_signup=False,
            creator=None,
            session=test_session)
        d.discussion_locales = ['en', 'fr', 'de']
        d.legal_notice = LangString.create(
            u"We need to input the optical HDD sensor!", "en")
        tac = LangString.create(
            u"You can't quantify the driver without quantifying the 1080p JSON protocol!", "en")
        tac.add_value(
            u"Vous ne pouvez pas mesurer le driver sans mesurer le protocole JSON en 1080p", u"fr")
        d.terms_and_conditions = tac

        title = LangString.create(
            u"Faut-il manger des bananes ?", u"fr")
        title.add_value(
            u"Should we eat bananas?", u"en")
        d.title = title

        subtitle = LangString.create(
            u"Dis-moi ce que tu manges et je te dirai qui tu es", u"fr")
        subtitle.add_value(
            u"Tell me what you eat and I will tell you who you are", u"en")
        d.subtitle = subtitle

        button_label = LangString.create(
            u"Discuter des bananes", u"fr")
        button_label.add_value(
            u"Discuss bananas", u"en")
        d.button_label = button_label

        # add a privacy policy attachment to the discussion
        document = File(
            discussion=d,
            mime_type='image/png',
            title='simple_image.png'
        )
        test_session.add(document)
        document.add_raw_data(os.urandom(256))
        test_session.add(document)
        attachment = DiscussionAttachment(
            discussion=d,
            document=document,
            creator_id=participant2_user.id,
            title='A privacy policy attachment',
            attachmentPurpose=AttachmentPurpose.PRIVACY_POLICY_ATTACHMENT.value
        )

        test_session.add(attachment)
        test_session.add(d)
        # create_default_discussion_data(d)
        # Don't create default discussion data (permissions, sections) here
        # because it takes too much time to run all tests.
        # If you need sections or permissions in your tests, execute
        # create_default_discussion_data, create_default_discussion_sections
        # or create_default_permissions in your specific test or
        # use discussion_with_default_data fixture.
        # If you do permissions tests, be aware that the admin user
        # having R_SYSADMIN is actually a special case, see
        # auth/utils.py:get_permissions, it doesn't use discussion permissions
        # at all. So you need discussion permissions if you test with the
        # unauthenticated user Everyone or a user not having the R_SYSADMIN role.
    test_session.flush()

    def fin():
        print "finalizer discussion"
        discussion = d
        if inspect(discussion).detached:
            # How did this happen?
            discussion = test_session.query(Discussion).get(d.id)
        test_session.delete(attachment)
        test_session.delete(document)
        test_session.delete(discussion.table_of_contents)
        test_session.delete(discussion.root_idea)
        test_session.delete(discussion.next_synthesis)
        preferences = discussion.preferences
        discussion.preferences = None
        discussion.preferences_id = None
        for ut in discussion.user_templates:
            for ns in ut.notification_subscriptions:
                ns.delete()
            ut.delete()
        test_session.delete(preferences)
        test_session.delete(discussion)
        test_session.flush()
    request.addfinalizer(fin)
    return d