예제 #1
0
    def delete(self, account_id, article_id):
        query = Message.query.join(Account).filter(Account.id == account_id)
        if account_id and not article_id:
            if 'article-id' not in request.json:
                abort(404)
            ids = get_article_ids(request.json['article-id'])
            count = len(ids)
            query = query.filter(Message.article_id.in_(ids))
        else:
            query = query.filter(Message.article_id == article_id)
            count = 1
        messages = query.all()

        if len(messages) > 0 and not messages[0].account.writable:
            abort(403, 'Account is not writable')
        if len(messages) != count:
            return make_response(jsonify({'error': 'Message not found'}), 404)
        sync = get_sync(Account.query.get(account_id))
        for msg in messages:
            resp = sync.remote_delete(msg.google_id)
            if resp:
                click.echo('remote update failed')
                abort(resp[0], resp[1]),
            db.session().delete(msg)
        try:
            db.session().commit()
        except exc.SQLAlchemyError as ex:
            abort(500, ex)
        return jsonify({'result': True})
예제 #2
0
파일: thread.py 프로젝트: ricardog/nngmail
 def delete(self, thread_id):
     thread = Thread.query.get(thread_id)
     if not thread:
         return make_response(jsonify({'error': 'Thread not found'}), 404)
     db.session().delete(thread)
     db.session().commit()
     return jsonify({'result': True})
예제 #3
0
파일: account.py 프로젝트: ricardog/nngmail
 def delete(self, account_id):
     account = Account.query.get(account_id)
     if not account:
         return make_response(jsonify({'error': 'Account not found'}), 404)
     try:
         db.session().delete(account)
         db.session().commit()
     except exc.SQLAlchemyError as ex:
         abort(500, ex)
     return jsonify({'result': True})
예제 #4
0
파일: label.py 프로젝트: ricardog/nngmail
 def delete(self, account_id, label_id):
     label = Label.query.get_or_404(label_id)
     if not label.account.writable:
         abort(403, 'Account is not writable')
     try:
         db.session().delete(label)
         db.session().commit()
     except exc.SQLAlchemyError as ex:
         abort(500, ex)
     return jsonify({'result': True})
예제 #5
0
    def update(self, msgs):
        """Update a message in the database.

Only message labels are allowed to change.  We assume all messages are
already in the database.

This function is rather ineffcient.

        """
        if not msgs:
            return
        if '__getitem__' not in dir(msgs):
            msgs = (msgs, )
        session = db.session()
        objs = self.find_by_gid([m['id'] for m in msgs])
        ohash = dict([(o.google_id, o) for o in objs])
        assert len(objs) == len(msgs)
        for msg in msgs:
            obj = ohash[msg['id']]
            if 'labelIds' in msg:
                obj.labels = [self.get_label(lgid) for lgid in msg['labelIds']]
            else:
                obj.labels = []
            obj.modified = datetime.now()
            logger.info('%s: update: (%d, %d) -> %s' %
                        (self.options.nickname, obj.id, obj.article_id,
                         ', '.join(obj.label_names)))
        session.commit()
예제 #6
0
def sync(client):
    config_file = os.path.join(TEST_DIR, 'test-config.yaml')
    try:
        config = yaml.load(open(config_file, mode='rb'))
    except IOError as ex:
        print('Error: reading config file (%s)' % config_file)
        raise ex
    email = '*****@*****.**'
    nickname = 'itineris'
    Account.as_unique(db.session(),
                      email=email,
                      nickname=nickname,
                      writable=False,
                      can_send=False)
    db.session().commit()
    
    sync = GmSync(email, nickname, config)
    yield sync
예제 #7
0
 def __set_kv(self, key, value, upsert=False):
     """Store a key, value tuple in the database."""
     session = db.session()
     kv = self.account.key_value.filter_by(key=key).first()
     if upsert and kv:
         ## Store the history of history_id for debugging purposes
         kv.value = value
     else:
         kv = KeyValue(account=self.account, key=key, value=value)
     session.add(kv)
     session.commit()
예제 #8
0
파일: account.py 프로젝트: ricardog/nngmail
 def put(self, account_id):
     account = Account.query.get(account_id)
     if not account:
         return make_response(
             jsonify({'error': 'Account %d not found' % account_id}), 404)
     if not request.json:
         return make_response(
             jsonify({'error': 'No data on account update'}), 400)
     if ('nickname' not in request.json
             or not isinstance(request.json['nickname'], str)):
         return make_response(
             jsonify({'error': 'Bad account nickname (%s)' % nickname}),
             400)
     account.nickname = request.json['nickname']
     try:
         db.session().commit()
     except exc.IntegrityError as ex:
         return make_response(jsonify({'error': 'update error'}), 409)
     except exc.SQLAlchemyError as ex:
         abort(500, ex)
     return jsonify(account)
예제 #9
0
    def new_label(self, name, gid):
        """Create a new label in the database.

Translate Gmail category labels to something that is easier to read.

        """
        session = db.session()
        label = Label.as_unique(session,
                                name=name,
                                gid=gid,
                                account=self.account)
        session.commit()
        self.label_map[label.gid] = label
        self.label_imap[label.id] = label.gid
예제 #10
0
파일: account.py 프로젝트: ricardog/nngmail
 def post(self):
     if not request.json:
         return make_response(jsonify({'error': 'No data'}), 400)
     if ('nickname' not in request.json
             or not isinstance(request.json['nickname'], str)):
         return make_response(jsonify({'error': 'Bad account nickname'}),
                              400)
     if ('email' not in request.json
             or not isinstance(request.json['email'], str)):
         return make_response(jsonify({'error': 'Bad account email'}), 400)
     account = Account(email=request.json['email'],
                       nickname=request.json['nickname'],
                       writable=request.json.get('writable', False),
                       can_send=request.json.get('can-send', False))
     try:
         db.session().add(account)
         db.session().commit()
     except exc.IntegrityError as ex:
         return make_response(jsonify({'error': 'Acount already exists'}),
                              409)
     except exc.SQLAlchemyError as ex:
         abort(500, ex)
     return jsonify(account)
예제 #11
0
    def __init__(self, **kwargs):
        """Initialize a new object using the options passed in."""
        def flatten(d, parent_key='', sep='_'):
            """Flatten hierarchical options by adding '_'."""
            items = []
            for k, v in d.items():
                new_key = parent_key + sep + k if parent_key else k
                if isinstance(v, collections.MutableMapping):
                    items.extend(flatten(v, new_key, sep=sep).items())
                else:
                    items.append((new_key, v))
            return dict(items)

        self.options = self.options.push(flatten(kwargs))
        self.set(account=Account.as_unique(db.session(),
                                           email=self.options.email,
                                           nickname=self.options.nickname,
                                           writable=self.options.writable,
                                           can_send=False))
        db.session.flush()
        self.label_map = {}
        self.label_imap = {}
예제 #12
0
def test_incremental_pull2(client, sync):
    msg = {'from_id': 1,
           'account_id': 1,
           'article_id': 1,
           'google_id': '163e42f92b6526f8',
           'message_id': '<*****@*****.**>',
           'thread_id': 1,
           'from_id': 222,
           'date': datetime.datetime(2018, 6, 9, 11, 55, 11),
           'subject': 'This is a test message',
           'references': '',
           'snippet': 'This is the body of the message',
           'size': 6271}
    sess = db.session()
    mm = Message(**msg)
    sess.add(mm)
    sess.commit()
    # Move history back a few steps so we get some updates.
    sync.sql3.set_history_id(290982)
    sync.pull()
    print("history is %d" % sync.sql3.get_history_id())
    assert sync.sql3.get_history_id() == 291126
예제 #13
0
    def create(self, msgs):
        """Create a new message in the database.

This assumes we already created a placeholder row for the message and
focus instead on extracting the required information from the
representation we get from Gmail.

This function will "create" multiple messages at once for efficiency--it
is called once per batch received from Gmail.

        """
        if '__getitem__' not in dir(msgs):
            msgs = (msgs, )
        msgs = sorted(msgs, key=lambda msg: int(msg['id'], 16))
        gids = [m['id'] for m in msgs]
        session = db.session()
        with session.no_autoflush:
            objs = session.query(Message).\
                filter(and_(Message.google_id.in_(gids),
                            Message.account == self.account)).\
                            order_by(Message.google_id.asc()).all()
            if len(objs) != len(msgs):
                pdb.set_trace()
                pass
            assert len(objs) == len(msgs)

            for obj, msg in zip(objs, msgs):
                assert obj.google_id == msg['id']
                values = self.process_gmail_message(session, obj.id, msg)
                for key, value in values.items():
                    setattr(obj, key, value)
        try:
            session.commit()
        except exc.SQLAlchemyError as ex:
            pdb.set_trace()
            pass
예제 #14
0
 def commit(self):
     """Commit pending session changes to the database."""
     db.session().commit()
예제 #15
0
    def put(self, account_id, article_id):
        def process_message(message, added, removed):
            for label in added:
                if label in message.labels:
                    return message.id
                message.labels.append(label)
            for label in removed:
                if label not in message.labels:
                    return message.id
                message.labels.remove(label)
            return message

        account = Account.query.get_or_404(account_id)
        if not account.writable:
            abort(403, 'Account is not writable')
        if not request.json:
            return make_response(
                jsonify({'error': 'No data for message update'}), 400)
        if ('add_labels' not in request.json
                and 'rm_labels' not in request.json):
            return make_response(
                jsonify({'error': 'Specify add_labels or rm_labels'}), 400)
        added = [
            account.labels.filter_by(name=name).first_or_404()
            for name in request.json.get('add_labels', []) or []
        ]
        removed = [
            account.labels.filter_by(name=name).first_or_404()
            for name in request.json.get('rm_labels', []) or []
        ]
        sync = get_sync(account)
        query = Message.query.filter_by(account_id=account_id)
        if account_id and not article_id:
            if 'article-id' not in request.json:
                abort(404)
            ids = get_article_ids(request.json['article-id'])
            count = len(ids)
            query = query.filter(Message.article_id.in_(ids))
        else:
            count = 1
            query = query.filter(Message.article_id == article_id)
        messages = query.all()
        if len(messages) != count:
            return make_response(jsonify({'error': 'Message not found'}), 404)

        resp = sync.remote_batch_update([m.google_id for m in messages],
                                        [l.gid for l in added],
                                        [l.gid for l in removed])
        if resp:
            click.echo('remote update failed')
            abort(resp[0], resp[1]),
        session = db.session()
        resp = [process_message(m, added, removed) for m in messages]
        try:
            session.commit()
        except exc.IntegrityError as ex:
            return make_response(jsonify({'error': 'update error'}), 409)
        except exc.SQLAlchemyError as ex:
            abort(500, ex)
        failures = tuple(filter(lambda r: isinstance(r, int), resp))
        return jsonify({'failures': failures})