示例#1
0
def message_search_api():
    g.parser.add_argument('q', type=bounded_str, location='args')
    args = strict_parse_args(g.parser, request.args)
    if request.method == 'GET':
        if not args['q']:
            err_string = ('GET HTTP method must include query'
                          ' url parameter')
            g.log.error(err_string)
            return err(400, err_string)

        search_client = get_search_client(g.namespace.account)
        results = search_client.search_messages(g.db_session, args['q'])
    else:
        data = request.get_json(force=True)
        query = data.get('query')

        validate_search_query(query)

        sort = data.get('sort')
        validate_search_sort(sort)
        try:
            search_engine = NamespaceSearchEngine(g.namespace_public_id)
            results = search_engine.messages.search(query=query,
                                                    sort=sort,
                                                    max_results=args.limit,
                                                    offset=args.offset)
        except SearchEngineError as e:
            g.log.error('Search error: {0}'.format(e))
            return err(501, 'Search error')

    return g.encoder.jsonify(results)
示例#2
0
文件: ns_api.py 项目: htk/sync-engine
def message_search_api():
    g.parser.add_argument('q', type=bounded_str, location='args')
    args = strict_parse_args(g.parser, request.args)
    if request.method == 'GET':
        if not args['q']:
            err_string = ('GET HTTP method must include query'
                          ' url parameter')
            g.log.error(err_string)
            return err(400, err_string)

        search_client = get_search_client(g.namespace.account)
        results = search_client.search_messages(g.db_session, args['q'])
    else:
        data = request.get_json(force=True)
        query = data.get('query')

        validate_search_query(query)

        sort = data.get('sort')
        validate_search_sort(sort)
        try:
            search_engine = NamespaceSearchEngine(g.namespace_public_id)
            results = search_engine.messages.search(query=query,
                                                    sort=sort,
                                                    max_results=args.limit,
                                                    offset=args.offset)
        except SearchEngineError as e:
            g.log.error('Search error: {0}'.format(e))
            return err(501, 'Search error')

    return g.encoder.jsonify(results)
示例#3
0
def thread_api_update(public_id):
    try:
        valid_public_id(public_id)
        thread = g.db_session.query(Thread).filter(
            Thread.public_id == public_id,
            Thread.namespace_id == g.namespace.id).one()
    except NoResultFound:
        raise NotFoundError("Couldn't find thread `{0}` ".format(public_id))
    data = request.get_json(force=True)
    if not set(data).issubset({'add_tags', 'remove_tags', 'version'}):
        raise InputError('Can only add or remove tags from thread.')
    if (data.get('version') is not None and data.get('version') !=
            thread.version):
        raise ConflictError('Thread {} has been updated to version {}'.
                            format(thread.public_id, thread.version))

    removals = data.get('remove_tags', [])

    for tag_identifier in removals:
        tag = g.db_session.query(Tag).filter(
            Tag.namespace_id == g.namespace.id,
            or_(Tag.public_id == tag_identifier,
                Tag.name == tag_identifier)).first()
        if tag is None:
            raise NotFoundError("Couldn't find tag {}".format(tag_identifier))
        if not tag.user_removable:
            raise InputError('Cannot remove read-only tag {}'.
                             format(tag_identifier))

        try:
            thread.remove_tag(tag, execute_action=True)
        except ActionError as e:
            return err(e.error, str(e))

    additions = data.get('add_tags', [])
    for tag_identifier in additions:
        tag = g.db_session.query(Tag).filter(
            Tag.namespace_id == g.namespace.id,
            or_(Tag.public_id == tag_identifier,
                Tag.name == tag_identifier)).first()
        if tag is None:
            raise NotFoundError("Couldn't find tag {}".format(tag_identifier))
        if not tag.user_addable:
            raise InputError('Cannot add read-only tag {}'.
                             format(tag_identifier))

        try:
            thread.apply_tag(tag, execute_action=True)
        except ActionError as e:
            return err(e.error, str(e))

    g.db_session.commit()
    return g.encoder.jsonify(thread)
示例#4
0
def thread_api_update(public_id):
    try:
        valid_public_id(public_id)
        thread = g.db_session.query(Thread).filter(
            Thread.public_id == public_id,
            Thread.namespace_id == g.namespace.id).one()
    except NoResultFound:
        raise NotFoundError("Couldn't find thread `{0}` ".format(public_id))
    data = request.get_json(force=True)
    if not set(data).issubset({'add_tags', 'remove_tags', 'version'}):
        raise InputError('Can only add or remove tags from thread.')
    if (data.get('version') is not None and data.get('version') !=
            thread.version):
        raise ConflictError('Thread {} has been updated to version {}'.
                            format(thread.public_id, thread.version))

    removals = data.get('remove_tags', [])

    for tag_identifier in removals:
        tag = g.db_session.query(Tag).filter(
            Tag.namespace_id == g.namespace.id,
            or_(Tag.public_id == tag_identifier,
                Tag.name == tag_identifier)).first()
        if tag is None:
            raise NotFoundError("Couldn't find tag {}".format(tag_identifier))
        if not tag.user_removable:
            raise InputError('Cannot remove tag {}'.format(tag_identifier))

        try:
            thread.remove_tag(tag, execute_action=True)
        except ActionError as e:
            return err(e.error, str(e))

    additions = data.get('add_tags', [])
    for tag_identifier in additions:
        tag = g.db_session.query(Tag).filter(
            Tag.namespace_id == g.namespace.id,
            or_(Tag.public_id == tag_identifier,
                Tag.name == tag_identifier)).first()
        if tag is None:
            raise NotFoundError("Couldn't find tag {}".format(tag_identifier))
        if not tag.user_addable:
            raise InputError('Cannot remove tag {}'.format(tag_identifier))

        try:
            thread.apply_tag(tag, execute_action=True)
        except ActionError as e:
            return err(e.error, str(e))

    g.db_session.commit()
    return g.encoder.jsonify(thread)
示例#5
0
文件: ns_api.py 项目: olofster/inbox
def draft_update_api(public_id):
    data = request.get_json(force=True)
    original_draft = get_draft(public_id, data.get('version'), g.namespace.id,
                               g.db_session)

    # TODO(emfree): what if you try to update a draft on a *thread* that's been
    # deleted?

    data = request.get_json(force=True)

    to = get_recipients(data.get('to'), 'to')
    cc = get_recipients(data.get('cc'), 'cc')
    bcc = get_recipients(data.get('bcc'), 'bcc')
    subject = data.get('subject')
    body = data.get('body')
    tags = get_tags(data.get('tags'), g.namespace.id, g.db_session)
    files = get_attachments(data.get('file_ids'), g.namespace.id, g.db_session)

    try:
        draft = sendmail.update_draft(g.db_session, g.namespace.account,
                                      original_draft, to, subject, body, files,
                                      cc, bcc, tags)
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(draft)
示例#6
0
def draft_update_api(public_id):
    data = request.get_json(force=True)
    original_draft = get_draft(public_id, data.get('version'), g.namespace.id,
                               g.db_session)

    # TODO(emfree): what if you try to update a draft on a *thread* that's been
    # deleted?

    data = request.get_json(force=True)

    to = get_recipients(data.get('to'), 'to')
    cc = get_recipients(data.get('cc'), 'cc')
    bcc = get_recipients(data.get('bcc'), 'bcc')
    from_addr = get_recipients(data.get('from_addr'), 'from_addr')
    reply_to = get_recipients(data.get('reply_to'), 'reply_to')

    if from_addr and len(from_addr) > 1:
        raise InputError("from_addr field can have at most one item")
    if reply_to and len(reply_to) > 1:
        raise InputError("reply_to field can have at most one item")

    subject = data.get('subject')
    body = data.get('body')
    tags = get_tags(data.get('tags'), g.namespace.id, g.db_session)
    files = get_attachments(data.get('file_ids'), g.namespace.id, g.db_session)

    try:
        draft = update_draft(g.db_session, g.namespace.account, original_draft,
                             to, subject, body, files, cc, bcc, from_addr,
                             reply_to, tags)
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(draft)
示例#7
0
文件: app.py 项目: wmv/inbox
def account(account_id):
    try:
        account = g.db_session.query(Account).get(account_id)
    except NoResultFound:
        return err(404, 'No account with id `{0}`'.format(account_id))

    if 'action' in request.args:
        action = request.args.get('action', None)
        if action == 'stop':
            if account.sync_enabled:
                account.stop_sync()
                g.db_session.add(account)
                g.db_session.commit()
        elif action == 'start':
            account.start_sync()
            g.db_session.add(account)
            g.db_session.commit()

    if account:
        folders_info = [
            foldersyncstatus.metrics
            for foldersyncstatus in account.foldersyncstatuses
        ]
        sync_status = account.sync_status
    else:
        folders_info = []
        sync_status = {}

    return json.dumps({
        "account": sync_status,
        "folders": folders_info
    },
                      cls=DateTimeJSONEncoder)
示例#8
0
def tag_update_api(public_id):
    try:
        valid_public_id(public_id)
        tag = g.db_session.query(Tag).filter(
            Tag.public_id == public_id,
            Tag.namespace_id == g.namespace.id).one()
    except NoResultFound:
        raise NotFoundError('No tag found')

    data = request.get_json(force=True)
    if not ('name' in data.keys() and isinstance(data['name'], basestring)):
        raise InputError('Malformed tag update request')
    if 'namespace_id' in data.keys():
        ns_id = data['namespace_id']
        valid_public_id(ns_id)
        if ns_id != g.namespace.public_id:
            raise InputError('Cannot change the namespace on a tag.')
    if not tag.user_created:
        raise InputError('Cannot modify tag {}'.format(public_id))
    # Lowercase tag name, regardless of input casing.
    new_name = data['name'].lower()

    if new_name != tag.name:  # short-circuit rename to same value
        if not Tag.name_available(new_name, g.namespace.id, g.db_session):
            return err(409, 'Tag name already used')
        tag.name = new_name
        g.db_session.commit()

    return g.encoder.jsonify(tag)
示例#9
0
文件: ns_api.py 项目: apolmig/inbox
def draft_update_api(public_id):
    data = request.get_json(force=True)
    original_draft = get_draft(public_id, data.get('version'), g.namespace.id,
                               g.db_session)

    # TODO(emfree): what if you try to update a draft on a *thread* that's been
    # deleted?

    data = request.get_json(force=True)

    to = get_recipients(data.get('to'), 'to')
    cc = get_recipients(data.get('cc'), 'cc')
    bcc = get_recipients(data.get('bcc'), 'bcc')
    subject = data.get('subject')
    body = data.get('body')
    tags = get_tags(data.get('tags'), g.namespace.id, g.db_session)
    files = get_attachments(data.get('file_ids'), g.namespace.id, g.db_session)

    try:
        draft = sendmail.update_draft(g.db_session, g.namespace.account,
                                      original_draft, to, subject, body,
                                      files, cc, bcc, tags)
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(draft)
示例#10
0
文件: app.py 项目: 0xcd03/inbox
def account(account_id):
    try:
        account = g.db_session.query(Account).get(account_id)
    except NoResultFound:
        return err(404, 'No account with id `{0}`'.format(account_id))

    if 'action' in request.args:
        action = request.args.get('action', None)
        if action == 'stop':
            if account.sync_enabled:
                account.stop_sync()
                g.db_session.add(account)
                g.db_session.commit()
        elif action == 'start':
            account.start_sync()
            g.db_session.add(account)
            g.db_session.commit()

    if account:
        folders_info = [foldersyncstatus.metrics for foldersyncstatus in
                        account.foldersyncstatuses]
        sync_status = account.sync_status
    else:
        folders_info = []
        sync_status = {}

    return json.dumps({"account": sync_status,
                       "folders": folders_info}, cls=DateTimeJSONEncoder)
示例#11
0
def send_draft_copy(account, draft, custom_body, recipient):
    """
    Sends a copy of this draft to the recipient, using the specified body
    rather that the one on the draft object, and not marking the draft as
    sent. Used within multi-send to send messages to individual recipients
    with customized bodies.
    """
    # Create the response to send on success by serlializing the draft. Before
    # serializing, we temporarily swap in the new custom body (which the
    # recipient will get and which should be returned in this response) in
    # place of the existing body (which we still need to retain in the draft
    # for when it's saved to the sent folder). We replace the existing body
    # after serialization is done.
    original_body = draft.body
    draft.body = custom_body
    response_on_success = APIEncoder().jsonify(draft)
    draft.body = original_body

    # Now send the draft to the specified recipient. The send_custom method
    # will write the custom body into the message in place of the one in the
    # draft.
    try:
        sendmail_client = get_sendmail_client(account)
        sendmail_client.send_custom(draft, custom_body, [recipient])
    except SendMailException as exc:
        kwargs = {}
        if exc.failures:
            kwargs['failures'] = exc.failures
        if exc.server_error:
            kwargs['server_error'] = exc.server_error
        return err(exc.http_code, exc.message, **kwargs)

    return response_on_success
示例#12
0
def send_draft_copy(account, draft, custom_body, recipient):
    """
    Sends a copy of this draft to the recipient, using the specified body
    rather that the one on the draft object, and not marking the draft as
    sent. Used within multi-send to send messages to individual recipients
    with customized bodies.
    """
    # Create the response to send on success by serlializing the draft. After
    # serializing, we replace the new custom body (which the recipient will get
    # and which should be returned in this response) in place of the existing
    # body (which we still need to retain in the draft for when it's saved to
    # the sent folder).
    response_on_success = encode(draft)
    response_on_success["body"] = custom_body
    response_on_success = APIEncoder().jsonify(response_on_success)

    # Now send the draft to the specified recipient. The send_custom method
    # will write the custom body into the message in place of the one in the
    # draft.
    try:
        sendmail_client = get_sendmail_client(account)
        sendmail_client.send_custom(draft, custom_body, [recipient])
    except SendMailException as exc:
        kwargs = {}
        if exc.failures:
            kwargs["failures"] = exc.failures
        if exc.server_error:
            kwargs["server_error"] = exc.server_error
        return err(exc.http_code, exc.args[0], **kwargs)

    return response_on_success
示例#13
0
def sync_deltas():
    g.parser.add_argument('cursor', type=valid_public_id, location='args',
                          required=True)
    g.parser.add_argument('exclude_types', type=valid_delta_object_types,
                          location='args')
    g.parser.add_argument('include_types', type=valid_delta_object_types,
                          location='args')
    g.parser.add_argument('timeout', type=int,
                          default=LONG_POLL_REQUEST_TIMEOUT, location='args')
    # TODO(emfree): should support `expand` parameter in delta endpoints.
    args = strict_parse_args(g.parser, request.args)
    exclude_types = args.get('exclude_types')
    include_types = args.get('include_types')
    cursor = args['cursor']
    timeout = args['timeout']

    if include_types and exclude_types:
        return err(400, "Invalid Request. Cannot specify both include_types"
                   "and exclude_types")

    if cursor == '0':
        start_pointer = 0
    else:
        try:
            start_pointer, = g.db_session.query(Transaction.id). \
                filter(Transaction.public_id == cursor,
                       Transaction.namespace_id == g.namespace.id).one()
        except NoResultFound:
            raise InputError('Invalid cursor parameter')

    # The client wants us to wait until there are changes
    g.db_session.close()  # hack to close the flask session
    poll_interval = 1

    start_time = time.time()
    while time.time() - start_time < timeout:
        with session_scope() as db_session:
            deltas, _ = delta_sync.format_transactions_after_pointer(
                g.namespace, start_pointer, db_session, args['limit'],
                exclude_types, include_types)

        response = {
            'cursor_start': cursor,
            'deltas': deltas,
        }
        if deltas:
            response['cursor_end'] = deltas[-1]['cursor']
            return g.encoder.jsonify(response)

        # No changes. perhaps wait
        elif '/delta/longpoll' in request.url_rule.rule:
            gevent.sleep(poll_interval)
        else:  # Return immediately
            response['cursor_end'] = cursor
            return g.encoder.jsonify(response)

    # If nothing happens until timeout, just return the end of the cursor
    response['cursor_end'] = cursor
    return g.encoder.jsonify(response)
示例#14
0
def sync_deltas():
    g.parser.add_argument('cursor', type=valid_public_id, location='args',
                          required=True)
    g.parser.add_argument('exclude_types', type=valid_delta_object_types,
                          location='args')
    g.parser.add_argument('include_types', type=valid_delta_object_types,
                          location='args')
    g.parser.add_argument('timeout', type=int,
                          default=LONG_POLL_REQUEST_TIMEOUT, location='args')
    # TODO(emfree): should support `expand` parameter in delta endpoints.
    args = strict_parse_args(g.parser, request.args)
    exclude_types = args.get('exclude_types')
    include_types = args.get('include_types')
    cursor = args['cursor']
    timeout = args['timeout']

    if include_types and exclude_types:
        return err(400, "Invalid Request. Cannot specify both include_types"
                   "and exclude_types")

    if cursor == '0':
        start_pointer = 0
    else:
        try:
            start_pointer, = g.db_session.query(Transaction.id). \
                filter(Transaction.public_id == cursor,
                       Transaction.namespace_id == g.namespace.id).one()
        except NoResultFound:
            raise InputError('Invalid cursor parameter')

    # The client wants us to wait until there are changes
    g.db_session.close()  # hack to close the flask session
    poll_interval = 1

    start_time = time.time()
    while time.time() - start_time < timeout:
        with session_scope() as db_session:
            deltas, _ = delta_sync.format_transactions_after_pointer(
                g.namespace, start_pointer, db_session, args['limit'],
                exclude_types, include_types)

        response = {
            'cursor_start': cursor,
            'deltas': deltas,
        }
        if deltas:
            response['cursor_end'] = deltas[-1]['cursor']
            return g.encoder.jsonify(response)

        # No changes. perhaps wait
        elif '/delta/longpoll' in request.url_rule.rule:
            gevent.sleep(poll_interval)
        else:  # Return immediately
            response['cursor_end'] = cursor
            return g.encoder.jsonify(response)

    # If nothing happens until timeout, just return the end of the cursor
    response['cursor_end'] = cursor
    return g.encoder.jsonify(response)
示例#15
0
def send_draft(account, draft, db_session, schedule_remote_delete):
    """Send the draft with id = `draft_id`."""
    try:
        sendmail_client = get_sendmail_client(account)
        sendmail_client.send(draft)
    except SendMailException as exc:
        if exc.failures:
            return err(exc.http_code, exc.message, failures=exc.failures)
        return err(exc.http_code, exc.message)

    # We want to return success to the API client if the message was sent, even
    # if there are errors in post-send updating. Otherwise the client may think
    # the send has failed. So wrap the rest of the work in try/except.
    try:
        if account.provider == 'icloud':
            # Special case because iCloud doesn't save sent messages.
            schedule_action('save_sent_email', draft, draft.namespace.id,
                            db_session)
        if schedule_remote_delete:
            schedule_action('delete_draft',
                            draft,
                            draft.namespace.id,
                            db_session,
                            inbox_uid=draft.inbox_uid,
                            message_id_header=draft.message_id_header)

        # Update message
        draft.is_sent = True
        draft.is_draft = False
        draft.received_date = datetime.utcnow()

        # Update thread
        sent_tag = account.namespace.tags['sent']
        draft_tag = account.namespace.tags['drafts']
        thread = draft.thread
        thread.apply_tag(sent_tag)
        # Remove the drafts tag from the thread if there are no more drafts.
        if not draft.thread.drafts:
            thread.remove_tag(draft_tag)
        thread.update_from_message(None, draft)
    except Exception as e:
        log.error('Error in post-send processing', error=e, exc_info=True)

    return APIEncoder().jsonify(draft)
示例#16
0
文件: app.py 项目: AmyWeiner/inbox
def _for_account(account_id):
    try:
        account = g.db_session.query(Account).get(account_id)
    except NoResultFound:
        return err(404, 'No account with id `{0}`'.format(account_id))

    folders_info = [foldersyncstatus.metrics for foldersyncstatus in
                    account.foldersyncstatuses]

    return json.dumps(folders_info, cls=DateTimeJSONEncoder)
示例#17
0
def draft_create_api():
    data = request.get_json(force=True)
    try:
        draft = create_draft(data, g.namespace, g.db_session, syncback=True)
        g.db_session.add(draft)
        g.db_session.commit()
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(draft)
示例#18
0
文件: sending.py 项目: apolmig/inbox
def send_draft(account, draft, db_session, schedule_remote_delete):
    """Send the draft with id = `draft_id`."""
    try:
        sendmail_client = get_sendmail_client(account)
        sendmail_client.send(draft)
    except SendMailException as exc:
        if exc.failures:
            return err(exc.http_code, exc.message, failures=exc.failures)
        return err(exc.http_code, exc.message)

    # We want to return success to the API client if the message was sent, even
    # if there are errors in post-send updating. Otherwise the client may think
    # the send has failed. So wrap the rest of the work in try/except.
    try:
        if account.provider == 'icloud':
            # Special case because iCloud doesn't save sent messages.
            schedule_action('save_sent_email', draft, draft.namespace.id,
                            db_session)
        if schedule_remote_delete:
            schedule_action('delete_draft', draft, draft.namespace.id,
                            db_session, inbox_uid=draft.inbox_uid,
                            message_id_header=draft.message_id_header)

        # Update message
        draft.is_sent = True
        draft.is_draft = False
        draft.received_date = datetime.utcnow()

        # Update thread
        sent_tag = account.namespace.tags['sent']
        draft_tag = account.namespace.tags['drafts']
        thread = draft.thread
        thread.apply_tag(sent_tag)
        # Remove the drafts tag from the thread if there are no more drafts.
        if not draft.thread.drafts:
            thread.remove_tag(draft_tag)
        thread.update_from_message(None, draft)
    except Exception as e:
        log.error('Error in post-send processing', error=e, exc_info=True)

    return APIEncoder().jsonify(draft)
示例#19
0
文件: app.py 项目: AmyWeiner/inbox
def for_account(account_id):
    try:
        account = g.db_session.query(Account).get(account_id)
    except NoResultFound:
        return err(404, 'No account with id `{0}`'.format(account_id))

    acct_info = account.sync_status

    template = 'for_account.html' if account.provider != 'eas' else \
        'for_eas_account.html'

    return render_template(template, account=acct_info)
示例#20
0
def draft_delete_api(public_id):
    data = request.get_json(force=True)
    # Validate draft id, version, etc.
    draft = get_draft(public_id, data.get('version'), g.namespace.id,
                      g.db_session)

    try:
        result = delete_draft(g.db_session, g.namespace.account, draft)
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(result)
示例#21
0
def stream_changes():
    g.parser.add_argument('timeout', type=float, location='args')
    g.parser.add_argument('cursor',
                          type=valid_public_id,
                          location='args',
                          required=True)
    g.parser.add_argument('exclude_types',
                          type=valid_delta_object_types,
                          location='args')
    g.parser.add_argument('include_types',
                          type=valid_delta_object_types,
                          location='args')
    args = strict_parse_args(g.parser, request.args)
    timeout = args['timeout'] or 1800
    transaction_pointer = None
    cursor = args['cursor']
    exclude_types = args.get('exclude_types')
    include_types = args.get('include_types')

    if include_types and exclude_types:
        return err(
            400, "Invalid Request. Cannot specify both include_types"
            "and exclude_types")

    if cursor == '0':
        transaction_pointer = 0
    else:
        query_result = g.db_session.query(Transaction.id).filter(
            Transaction.namespace_id == g.namespace.id,
            Transaction.public_id == cursor).first()
        if query_result is None:
            raise InputError('Invalid cursor {}'.format(args['cursor']))
        transaction_pointer = query_result[0]

    # Hack to not keep a database session open for the entire (long) request
    # duration.
    g.db_session.expunge(g.namespace)
    g.db_session.close()
    # TODO make transaction log support the `expand` feature
    generator = delta_sync.streaming_change_generator(
        g.namespace,
        transaction_pointer=transaction_pointer,
        poll_interval=1,
        timeout=timeout,
        exclude_types=exclude_types,
        include_types=include_types)
    return Response(generator, mimetype='text/event-stream')
示例#22
0
def send_raw_mime(account, db_session, msg):
    # Prepare a response so that we can immediately return it on success, and
    # not potentially have queries fail after sending.
    response_on_success = APIEncoder().jsonify(msg)
    try:
        sendmail_client = get_sendmail_client(account)
        sendmail_client.send_raw(msg)

    except SendMailException as exc:
        kwargs = {}
        if exc.failures:
            kwargs['failures'] = exc.failures
        if exc.server_error:
            kwargs['server_error'] = exc.server_error
        return err(exc.http_code, exc.message, **kwargs)

    return response_on_success
示例#23
0
文件: ns_api.py 项目: apolmig/inbox
def message_search_api():
    args = strict_parse_args(g.parser, request.args)
    data = request.get_json(force=True)
    query = data.get('query')

    validate_search_query(query)

    try:
        search_engine = NamespaceSearchEngine(g.namespace_public_id)
        results = search_engine.messages.search(query=query,
                                                max_results=args.limit,
                                                offset=args.offset)
    except SearchEngineError as e:
        g.log.error('Search error: {0}'.format(e))
        return err(501, 'Search error')

    return g.encoder.jsonify(results)
示例#24
0
文件: ns_api.py 项目: olofster/inbox
def message_search_api():
    args = strict_parse_args(g.parser, request.args)
    data = request.get_json(force=True)
    query = data.get('query')

    validate_search_query(query)

    try:
        search_engine = NamespaceSearchEngine(g.namespace_public_id)
        results = search_engine.messages.search(query=query,
                                                max_results=args.limit,
                                                offset=args.offset)
    except SearchEngineError as e:
        g.log.error('Search error: {0}'.format(e))
        return err(501, 'Search error')

    return g.encoder.jsonify(results)
示例#25
0
文件: ns_api.py 项目: apolmig/inbox
def tag_create_api():
    data = request.get_json(force=True)
    if not ('name' in data.keys() and isinstance(data['name'], basestring)):
        raise InputError('Malformed tag request')
    if 'namespace_id' in data.keys():
        ns_id = data['namespace_id']
        valid_public_id(ns_id)
        if ns_id != g.namespace.id:
            raise InputError('Cannot change the namespace on a tag.')
    # Lowercase tag name, regardless of input casing.
    tag_name = data['name'].lower()
    if not Tag.name_available(tag_name, g.namespace.id, g.db_session):
        return err(409, 'Tag name not available')
    if len(tag_name) > MAX_INDEXABLE_LENGTH:
        raise InputError('Tag name is too long.')

    tag = Tag(name=tag_name, namespace=g.namespace, user_created=True)
    g.db_session.commit()
    return g.encoder.jsonify(tag)
示例#26
0
def auth():
    """ Check for account ID on all non-root URLS """
    if request.path in ('/accounts', '/accounts/', '/', '/n', '/n/') \
            or request.path.startswith('/w/'):
        return

    if request.path.startswith('/n/'):
        ns_parts = filter(None, request.path.split('/'))
        namespace_public_id = ns_parts[1]
        valid_public_id(namespace_public_id)

        with global_session_scope() as db_session:
            try:
                namespace = db_session.query(Namespace) \
                    .filter(Namespace.public_id == namespace_public_id).one()
                g.namespace_id = namespace.id
            except NoResultFound:
                return err(404, "Unknown namespace ID")

    else:
        if not request.authorization or not request.authorization.username:
            return make_response(("Could not verify access credential.", 401, {
                'WWW-Authenticate':
                'Basic realm="API '
                'Access Token Required"'
            }))

        namespace_public_id = request.authorization.username

        with global_session_scope() as db_session:
            try:
                valid_public_id(namespace_public_id)
                namespace = db_session.query(Namespace) \
                    .filter(Namespace.public_id == namespace_public_id).one()
                g.namespace_id = namespace.id
                g.account_id = namespace.account.id
            except NoResultFound:
                return make_response(
                    ("Could not verify access credential.", 401, {
                        'WWW-Authenticate':
                        'Basic realm="API '
                        'Access Token Required"'
                    }))
示例#27
0
文件: ns_api.py 项目: olofster/inbox
def tag_create_api():
    data = request.get_json(force=True)
    if not ('name' in data.keys() and isinstance(data['name'], basestring)):
        raise InputError('Malformed tag request')
    if 'namespace_id' in data.keys():
        ns_id = data['namespace_id']
        valid_public_id(ns_id)
        if ns_id != g.namespace.id:
            raise InputError('Cannot change the namespace on a tag.')
    # Lowercase tag name, regardless of input casing.
    tag_name = data['name'].lower()
    if not Tag.name_available(tag_name, g.namespace.id, g.db_session):
        return err(409, 'Tag name not available')
    if len(tag_name) > MAX_INDEXABLE_LENGTH:
        raise InputError('Tag name is too long.')

    tag = Tag(name=tag_name, namespace=g.namespace, user_created=True)
    g.db_session.commit()
    return g.encoder.jsonify(tag)
示例#28
0
def send_draft(account, draft, db_session):
    """Send the draft with id = `draft_id`."""
    # Update message state and prepare a response so that we can immediately
    # return it on success, and not potentially have queries fail after
    # sending. Note that changes are flushed here, but committed in the API's
    # after_request handler only on 200 OK (hence only if sending succeeds).
    update_draft_on_send(account, draft, db_session)
    response_on_success = APIEncoder().jsonify(draft)
    try:
        sendmail_client = get_sendmail_client(account)
        sendmail_client.send(draft)
    except SendMailException as exc:
        kwargs = {}
        if exc.failures:
            kwargs['failures'] = exc.failures
        if exc.server_error:
            kwargs['server_error'] = exc.server_error
        return err(exc.http_code, exc.message, **kwargs)

    return response_on_success
示例#29
0
文件: srv.py 项目: rf-/sync-engine
def auth():
    """ Check for account ID on all non-root URLS """
    if request.path in ("/accounts", "/accounts/", "/", "/n", "/n/") or request.path.startswith("/w/"):
        return

    if request.path.startswith("/n/"):
        ns_parts = filter(None, request.path.split("/"))
        namespace_public_id = ns_parts[1]
        valid_public_id(namespace_public_id)

        with session_scope() as db_session:
            try:
                namespace = db_session.query(Namespace).filter(Namespace.public_id == namespace_public_id).one()
                g.namespace_public_id = namespace.public_id
            except NoResultFound:
                return err(404, "Unknown namespace ID")

    else:
        if not request.authorization or not request.authorization.username:
            return make_response(
                (
                    "Could not verify access credential.",
                    401,
                    {"WWW-Authenticate": 'Basic realm="API ' 'Access Token Required"'},
                )
            )

        g.namespace_public_id = request.authorization.username

        with session_scope() as db_session:
            try:
                valid_public_id(g.namespace_public_id)
                namespace = db_session.query(Namespace).filter(Namespace.public_id == g.namespace_public_id).one()
            except NoResultFound:
                return make_response(
                    (
                        "Could not verify access credential.",
                        401,
                        {"WWW-Authenticate": 'Basic realm="API ' 'Access Token Required"'},
                    )
                )
示例#30
0
文件: ns_api.py 项目: olofster/inbox
def draft_create_api():
    data = request.get_json(force=True)

    to = get_recipients(data.get('to'), 'to')
    cc = get_recipients(data.get('cc'), 'cc')
    bcc = get_recipients(data.get('bcc'), 'bcc')
    subject = data.get('subject')
    body = data.get('body')
    tags = get_tags(data.get('tags'), g.namespace.id, g.db_session)
    files = get_attachments(data.get('file_ids'), g.namespace.id, g.db_session)
    replyto_thread = get_thread(data.get('thread_id'), g.namespace.id,
                                g.db_session)

    try:
        draft = sendmail.create_draft(g.db_session, g.namespace.account, to,
                                      subject, body, files, cc, bcc, tags,
                                      replyto_thread)
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(draft)
示例#31
0
文件: ns_api.py 项目: olofster/inbox
def calendar_create_api():
    data = request.get_json(force=True)

    if 'name' not in data:
        raise InputError("Calendar must have a name.")

    name = data['name']

    existing = g.db_session.query(Calendar).filter(
        Calendar.name == name,
        Calendar.namespace_id == g.namespace.id).first()

    if existing:
        return err(409,
                   "A calendar already exists with name '{}'.".format(name))

    description = data.get('description', None)

    cal_create = events.crud.create_calendar
    new_calendar = cal_create(g.namespace, g.db_session, name, description)
    return g.encoder.jsonify(new_calendar)
示例#32
0
文件: ns_api.py 项目: apolmig/inbox
def calendar_create_api():
    data = request.get_json(force=True)

    if 'name' not in data:
        raise InputError("Calendar must have a name.")

    name = data['name']

    existing = g.db_session.query(Calendar).filter(
        Calendar.name == name,
        Calendar.namespace_id == g.namespace.id).first()

    if existing:
        return err(409, "A calendar already exists with name '{}'.".
                   format(name))

    description = data.get('description', None)

    cal_create = events.crud.create_calendar
    new_calendar = cal_create(g.namespace, g.db_session, name, description)
    return g.encoder.jsonify(new_calendar)
示例#33
0
def auth():
    """ Check for account ID on all non-root URLS """
    if request.path in ('/accounts', '/accounts/', '/', '/n', '/n/') \
                       or request.path.startswith('/w/'):
        return

    if request.path.startswith('/n/'):
        ns_parts = filter(None, request.path.split('/'))
        namespace_public_id = ns_parts[1]
        valid_public_id(namespace_public_id)

        with global_session_scope() as db_session:
            try:
                namespace = db_session.query(Namespace) \
                    .filter(Namespace.public_id == namespace_public_id).one()
                g.namespace_id = namespace.id
            except NoResultFound:
                return err(404, "Unknown namespace ID")

    else:
        if not request.authorization or not request.authorization.username:
            return make_response((
                "Could not verify access credential.", 401,
                {'WWW-Authenticate': 'Basic realm="API '
                 'Access Token Required"'}))

        namespace_public_id = request.authorization.username

        with global_session_scope() as db_session:
            try:
                valid_public_id(namespace_public_id)
                namespace = db_session.query(Namespace) \
                    .filter(Namespace.public_id == namespace_public_id).one()
                g.namespace_id = namespace.id
                g.account_id = namespace.account.id
            except NoResultFound:
                return make_response((
                    "Could not verify access credential.", 401,
                    {'WWW-Authenticate': 'Basic realm="API '
                     'Access Token Required"'}))
示例#34
0
def stream_changes():
    g.parser.add_argument('timeout', type=float, location='args')
    g.parser.add_argument('cursor', type=valid_public_id, location='args',
                          required=True)
    g.parser.add_argument('exclude_types', type=valid_delta_object_types,
                          location='args')
    g.parser.add_argument('include_types', type=valid_delta_object_types,
                          location='args')
    args = strict_parse_args(g.parser, request.args)
    timeout = args['timeout'] or 1800
    transaction_pointer = None
    cursor = args['cursor']
    exclude_types = args.get('exclude_types')
    include_types = args.get('include_types')

    if include_types and exclude_types:
        return err(400, "Invalid Request. Cannot specify both include_types"
                   "and exclude_types")

    if cursor == '0':
        transaction_pointer = 0
    else:
        query_result = g.db_session.query(Transaction.id).filter(
            Transaction.namespace_id == g.namespace.id,
            Transaction.public_id == cursor).first()
        if query_result is None:
            raise InputError('Invalid cursor {}'.format(args['cursor']))
        transaction_pointer = query_result[0]

    # Hack to not keep a database session open for the entire (long) request
    # duration.
    g.db_session.expunge(g.namespace)
    g.db_session.close()
    # TODO make transaction log support the `expand` feature
    generator = delta_sync.streaming_change_generator(
        g.namespace, transaction_pointer=transaction_pointer,
        poll_interval=1, timeout=timeout, exclude_types=exclude_types,
        include_types=include_types)
    return Response(generator, mimetype='text/event-stream')
示例#35
0
文件: ns_api.py 项目: apolmig/inbox
def draft_create_api():
    data = request.get_json(force=True)

    to = get_recipients(data.get('to'), 'to')
    cc = get_recipients(data.get('cc'), 'cc')
    bcc = get_recipients(data.get('bcc'), 'bcc')
    subject = data.get('subject')
    body = data.get('body')
    tags = get_tags(data.get('tags'), g.namespace.id, g.db_session)
    files = get_attachments(data.get('file_ids'), g.namespace.id,
                            g.db_session)
    replyto_thread = get_thread(data.get('thread_id'), g.namespace.id,
                                g.db_session)

    try:
        draft = sendmail.create_draft(g.db_session, g.namespace.account, to,
                                      subject, body, files, cc, bcc,
                                      tags, replyto_thread)
    except ActionError as e:
        return err(e.error, str(e))

    return g.encoder.jsonify(draft)
示例#36
0
文件: app.py 项目: Inanny/inbox
def account(account_id):
    try:
        account = g.db_session.query(Account).get(account_id)
    except NoResultFound:
        return err(404, 'No account with id `{0}`'.format(account_id))

    if 'action' in request.args:
        root_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                 '..', '..')
        bin_path = os.path.abspath(os.path.join(root_path, 'bin'))
        inbox_sync = os.path.join(bin_path, 'inbox-sync')

        action = request.args.get('action', None)
        if action == 'stop':
            if account.sync_enabled:
                print "stopping: ", account_id
                account.stop_sync()
        elif action == 'start':
            print "starting: ", account_id
            account.start_sync(platform.node())

    if account:
        folders_info = [
            foldersyncstatus.metrics
            for foldersyncstatus in account.foldersyncstatuses
        ]
        sync_status = account.sync_status
    else:
        folders_info = []
        sync_status = {}

    return json.dumps({
        "account": sync_status,
        "folders": folders_info
    },
                      cls=DateTimeJSONEncoder)