コード例 #1
0
ファイル: gmail.py プロジェクト: htk/sync-engine
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)
        remote_label_names = {l.display_name.rstrip()[:MAX_LABEL_NAME_LENGTH] for l in raw_folders}

        assert "all" in {f.role for f in raw_folders}, "Account {} has no detected All Mail folder".format(
            account.email_address
        )

        local_labels = {l.name: l for l in db_session.query(Label).filter(Label.account_id == self.account_id).all()}

        # Delete labels no longer present on the remote.
        # Note that the label with canonical_name='all' cannot be deleted;
        # remote_label_names will always contain an entry corresponding to it.
        discard = set(local_labels) - set(remote_label_names)
        for name in discard:
            log.info("Label deleted from remote", account_id=self.account_id, name=name)
            db_session.delete(local_labels[name])

        # Create new labels, folders
        for raw_folder in raw_folders:
            Label.find_or_create(db_session, account, raw_folder.display_name, raw_folder.role)

            if raw_folder.role in ("all", "spam", "trash"):
                folder = Folder.find_or_create(db_session, account, raw_folder.display_name, raw_folder.role)
                if folder.name != raw_folder.display_name:
                    log.info(
                        "Folder name changed on remote",
                        account_id=self.account_id,
                        role=raw_folder.role,
                        new_name=raw_folder.display_name,
                        name=folder.name,
                    )
                    folder.name = raw_folder.display_name

        # Ensure sync_should_run is True for the folders we want to sync (for
        # Gmail, that's just all folders, since we created them above if
        # they didn't exist.)
        for folder in account.folders:
            if folder.imapsyncstatus:
                folder.imapsyncstatus.sync_should_run = True
        db_session.commit()
コード例 #2
0
ファイル: gmail.py プロジェクト: steffenmllr/sync-engine
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)

        # Create new labels, folders
        for raw_folder in raw_folders:
            if raw_folder.role == 'starred':
                # The starred state of messages is tracked separately
                # (we set Message.is_starred from the '\\Flagged' flag)
                continue

            Label.find_or_create(db_session, account,
                                 raw_folder.display_name, raw_folder.role)

            if raw_folder.role in ('all', 'spam', 'trash'):
                folder = Folder.find_or_create(db_session, account,
                                               raw_folder.display_name,
                                               raw_folder.role)
                if folder.name != raw_folder.display_name:
                    log.info('Folder name changed on remote',
                             account_id=self.account_id,
                             role=raw_folder.role,
                             new_name=raw_folder.display_name,
                             name=folder.name)
                    folder.name = raw_folder.display_name

        # Ensure sync_should_run is True for the folders we want to sync (for
        # Gmail, that's just all folders, since we created them above if
        # they didn't exist.)
        for folder in account.folders:
            if folder.imapsyncstatus:
                folder.imapsyncstatus.sync_should_run = True
        db_session.commit()
コード例 #3
0
def populate_labels(uid, account, db_session):
    from inbox.models import Label

    existing_labels = {(l.name, l.canonical_name): l for l in account.labels}
    uid.is_draft = "\\Draft" in uid.g_labels
    uid.is_starred = "\\Starred" in uid.g_labels

    category_map = {
        "\\Inbox": "inbox",
        "\\Important": "important",
        "\\Sent": "sent"
    }

    remote_labels = set()
    for label_string in uid.g_labels:
        if label_string in ("\\Draft", "\\Starred"):
            continue
        elif label_string in category_map:
            remote_labels.add(
                (category_map[label_string], category_map[label_string]))
        else:
            remote_labels.add((label_string, None))

    for key in remote_labels:
        if key not in existing_labels:
            label = Label.find_or_create(db_session, account, key[0], key[1])
            uid.labels.add(label)
            account.labels.append(label)
        else:
            uid.labels.add(existing_labels[key])
コード例 #4
0
def populate_labels(uid, account, db_session):
    from inbox.models import Label

    existing_labels = {(l.name, l.canonical_name): l for l in account.labels}
    uid.is_draft = "\\Draft" in uid.g_labels
    uid.is_starred = "\\Starred" in uid.g_labels

    category_map = {"\\Inbox": "inbox", "\\Important": "important", "\\Sent": "sent"}

    remote_labels = set()
    for label_string in uid.g_labels:
        if label_string in ("\\Draft", "\\Starred"):
            continue
        elif label_string in category_map:
            remote_labels.add((category_map[label_string], category_map[label_string]))
        else:
            remote_labels.add((label_string, None))

    for key in remote_labels:
        if key not in existing_labels:
            label = Label.find_or_create(db_session, account, key[0], key[1])
            uid.labels.add(label)
            account.labels.append(label)
        else:
            uid.labels.add(existing_labels[key])
コード例 #5
0
def test_not_deleting_canonical_folders(empty_db, default_account):
    # Create a label w/ no messages attached.
    label = Label.find_or_create(empty_db.session, default_account,
                                 '[Gmail]/Tous les messages')
    label.canonical_name = 'all'
    empty_db.session.commit()

    monitor = GmailSyncMonitor(default_account)

    folder_names_and_roles = {
        ('[Gmail]/Corbeille', 'trash'),
        ('[Gmail]/Spam', 'spam'),
        ('Recettes', None),
    }

    raw_folders = [RawFolder(*args) for args in folder_names_and_roles]
    monitor.save_folder_names(empty_db.session, raw_folders)

    label = empty_db.session.query(Label).get(label.id)
    assert label.deleted_at is None
コード例 #6
0
def test_not_deleting_canonical_folders(empty_db, default_account):
    # Create a label w/ no messages attached.
    label = Label.find_or_create(empty_db.session, default_account,
                                 '[Gmail]/Tous les messages')
    label.canonical_name = 'all'
    empty_db.session.commit()

    monitor = GmailSyncMonitor(default_account)

    folder_names_and_roles = {
        ('[Gmail]/Corbeille', 'trash'),
        ('[Gmail]/Spam', 'spam'),
        ('Recettes', None),
    }

    raw_folders = [RawFolder(*args) for args in folder_names_and_roles]
    monitor.save_folder_names(empty_db.session, raw_folders)

    label = empty_db.session.query(Label).get(label.id)
    assert label.deleted_at is None
コード例 #7
0
ファイル: gmail.py プロジェクト: TribeMedia/sync-engine
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)

        # Create new labels, folders
        for raw_folder in raw_folders:
            if raw_folder.role == 'starred':
                # The starred state of messages is tracked separately
                # (we set Message.is_starred from the '\\Flagged' flag)
                continue

            Label.find_or_create(db_session, account,
                                 raw_folder.display_name, raw_folder.role)

            if raw_folder.role in ('all', 'spam', 'trash'):
                folder = db_session.query(Folder). \
                        filter(Folder.account_id == account.id,
                                Folder.canonical_name == raw_folder.role). \
                        first()
                if folder:
                    if folder.name != raw_folder.display_name:
                        log.info('Folder name changed on remote',
                                 account_id=self.account_id,
                                 role=raw_folder.role,
                                 new_name=raw_folder.display_name,
                                 name=folder.name)
                        folder.name = raw_folder.display_name

                    if folder.category:
                        if folder.category.display_name != \
                                raw_folder.display_name:
                            folder.category.display_name = raw_folder.display_name
                    else:
                        log.info('Creating category for folder',
                                 account_id=self.account_id,
                                 folder_name=folder.name)
                        folder.category = Category.find_or_create(
                            db_session, namespace_id=account.namespace.id,
                            name=raw_folder.role,
                            display_name=raw_folder.display_name,
                            type_='folder')
                else:
                    Folder.find_or_create(db_session, account,
                                          raw_folder.display_name,
                                          raw_folder.role)

        # Ensure sync_should_run is True for the folders we want to sync (for
        # Gmail, that's just all folders, since we created them above if
        # they didn't exist.)
        for folder in account.folders:
            if folder.imapsyncstatus:
                folder.imapsyncstatus.sync_should_run = True
        db_session.commit()
コード例 #8
0
def label(db, default_account):
    from inbox.models import Label
    return Label.find_or_create(db.session, default_account, 'Inbox', 'inbox')
コード例 #9
0
ファイル: base.py プロジェクト: gisho/sync-engine
def label(db, default_account):
    from inbox.models import Label
    return Label.find_or_create(db.session, default_account,
                                 'Inbox', 'inbox')
コード例 #10
0
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)

        old_labels = {
            label
            for label in db_session.query(Label).filter(
                Label.account_id == self.account_id, Label.deleted_at == None)
        }

        new_labels = set()

        # Create new labels, folders
        for raw_folder in raw_folders:
            if raw_folder.role == 'starred':
                # The starred state of messages is tracked separately
                # (we set Message.is_starred from the '\\Flagged' flag)
                continue

            label = Label.find_or_create(db_session, account,
                                         raw_folder.display_name,
                                         raw_folder.role)
            new_labels.add(label)

            if label.deleted_at is not None:
                # This is a label which was previously marked as deleted
                # but which mysteriously reappeared. Unmark it.
                log.info('Deleted label recreated on remote',
                         name=raw_folder.display_name)
                label.deleted_at = None
                label.category.deleted_at = None

            if raw_folder.role in ('all', 'spam', 'trash'):
                folder = db_session.query(Folder).filter(
                    Folder.account_id == account.id,
                    Folder.canonical_name == raw_folder.role).first()
                if folder:
                    if folder.name != raw_folder.display_name:
                        log.info('Folder name changed on remote',
                                 account_id=self.account_id,
                                 role=raw_folder.role,
                                 new_name=raw_folder.display_name,
                                 name=folder.name)
                        folder.name = raw_folder.display_name

                    if folder.category:
                        if folder.category.display_name != \
                                raw_folder.display_name:
                            folder.category.display_name = raw_folder.display_name  # noqa
                    else:
                        log.info('Creating category for folder',
                                 account_id=self.account_id,
                                 folder_name=folder.name)
                        folder.category = Category.find_or_create(
                            db_session,
                            namespace_id=account.namespace.id,
                            name=raw_folder.role,
                            display_name=raw_folder.display_name,
                            type_='folder')
                else:
                    Folder.find_or_create(db_session, account,
                                          raw_folder.display_name,
                                          raw_folder.role)

        # Ensure sync_should_run is True for the folders we want to sync (for
        # Gmail, that's just all folders, since we created them above if
        # they didn't exist.)
        for folder in account.folders:
            if folder.imapsyncstatus:
                folder.imapsyncstatus.sync_should_run = True

        # Go through the labels which have been "deleted" (i.e: they don't
        # show up when running LIST) and mark them as such.
        # We can't delete labels directly because Gmail allows users to hide
        # folders --- we need to check that there's no messages still
        # associated with the label.
        deleted_labels = old_labels - new_labels
        for deleted_label in deleted_labels:
            deleted_label.deleted_at = datetime.now()
            cat = deleted_label.category
            cat.deleted_at = datetime.now()

        db_session.commit()
コード例 #11
0
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)
        remote_label_names = {
            l.display_name.rstrip()[:MAX_LABEL_NAME_LENGTH]
            for l in raw_folders
        }

        assert 'all' in {f.role for f in raw_folders},\
            'Account {} has no detected All Mail folder'.\
            format(account.email_address)

        local_labels = {
            l.name: l
            for l in db_session.query(Label).filter(
                Label.account_id == self.account_id).all()
        }

        # Delete labels no longer present on the remote.
        # Note that the label with canonical_name='all' cannot be deleted;
        # remote_label_names will always contain an entry corresponding to it.
        discard = set(local_labels) - set(remote_label_names)
        for name in discard:
            log.info('Label deleted from remote',
                     account_id=self.account_id,
                     name=name)
            db_session.delete(local_labels[name])

        # Create new labels, folders
        for raw_folder in raw_folders:
            Label.find_or_create(db_session, account, raw_folder.display_name,
                                 raw_folder.role)

            if raw_folder.role in ('all', 'spam', 'trash'):
                folder = Folder.find_or_create(db_session, account,
                                               raw_folder.display_name,
                                               raw_folder.role)
                if folder.name != raw_folder.display_name:
                    log.info('Folder name changed on remote',
                             account_id=self.account_id,
                             role=raw_folder.role,
                             new_name=raw_folder.display_name,
                             name=folder.name)
                    folder.name = raw_folder.display_name

        # Ensure sync_should_run is True for the folders we want to sync (for
        # Gmail, that's just all folders, since we created them above if
        # they didn't exist.)
        for folder in account.folders:
            if folder.imapsyncstatus:
                folder.imapsyncstatus.sync_should_run = True
        db_session.commit()
コード例 #12
0
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)

        current_labels = set()
        old_labels = {label for label in db_session.query(Label).filter(
            Label.account_id == self.account_id,
            Label.deleted_at == None)}  # noqa

        # Is it the first time we've been syncing folders?
        # It's important to know this because we don't want to
        # be refreshing the labels for every message at the very
        # beginning of the initial sync.
        first_time_syncing_folders = len(old_labels) == 0

        # Create new labels, folders
        for raw_folder in raw_folders:
            if raw_folder.role == 'starred':
                # The starred state of messages is tracked separately
                # (we set Message.is_starred from the '\\Flagged' flag)
                continue

            if raw_folder.role in ('all', 'spam', 'trash'):
                self.handle_raw_folder_change(db_session, account, raw_folder)

            label = Label.find_or_create(db_session, account,
                                         raw_folder.display_name,
                                         raw_folder.role)
            if label.deleted_at is not None:
                # This is a label which was previously marked as deleted
                # but which mysteriously reappeared. Unmark it.
                log.info('Deleted label recreated on remote',
                         name=raw_folder.display_name)
                label.deleted_at = None
                label.category.deleted_at = None

            current_labels.add(label)

        new_labels = current_labels - old_labels
        db_session.commit()

        if not first_time_syncing_folders:
            # Try to see if a label has been renamed.
            for label in new_labels:
                db_session.refresh(label)
                db_session.expunge(label)

                rename_handler = LabelRenameHandler(
                     account_id=self.account_id,
                     namespace_id=self.namespace_id,
                     label_name=label.name,
                     semaphore=self.label_rename_semaphore)

                rename_handler.start()

        self.set_sync_should_run_bit(account)

        deleted_labels = old_labels - current_labels
        self.mark_deleted_labels(db_session, deleted_labels)

        db_session.commit()
コード例 #13
0
ファイル: gmail.py プロジェクト: nagyistge/nylas-sync-engine
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)

        current_labels = set()
        old_labels = {label for label in db_session.query(Label).filter(
            Label.account_id == self.account_id,
            Label.deleted_at == None)}  # noqa

        # Is it the first time we've been syncing folders?
        # It's important to know this because we don't want to
        # be refreshing the labels for every message at the very
        # beginning of the initial sync.
        first_time_syncing_folders = len(old_labels) == 0

        # Create new labels, folders
        for raw_folder in raw_folders:
            if raw_folder.role == 'starred':
                # The starred state of messages is tracked separately
                # (we set Message.is_starred from the '\\Flagged' flag)
                continue

            if raw_folder.role in ('all', 'spam', 'trash'):
                self.handle_raw_folder_change(db_session, account, raw_folder)

            label = Label.find_or_create(db_session, account,
                                         raw_folder.display_name,
                                         raw_folder.role)
            if label.deleted_at is not None:
                # This is a label which was previously marked as deleted
                # but which mysteriously reappeared. Unmark it.
                log.info('Deleted label recreated on remote',
                         name=raw_folder.display_name)
                label.deleted_at = None
                label.category.deleted_at = EPOCH

            current_labels.add(label)

        new_labels = current_labels - old_labels
        db_session.commit()

        if not first_time_syncing_folders:
            # Try to see if a label has been renamed.
            for label in new_labels:
                db_session.refresh(label)
                db_session.expunge(label)

                rename_handler = LabelRenameHandler(
                    account_id=self.account_id,
                    namespace_id=self.namespace_id,
                    label_name=label.name,
                    semaphore=self.label_rename_semaphore)

                rename_handler.start()

        self.set_sync_should_run_bit(account)

        deleted_labels = old_labels - current_labels
        self.mark_deleted_labels(db_session, deleted_labels)

        db_session.commit()
コード例 #14
0
ファイル: gmail.py プロジェクト: frknozr/sync-engine
    def save_folder_names(self, db_session, raw_folders):
        """
        Save the folders, labels present on the remote backend for an account.

        * Create Folder/ Label objects.
        * Delete Folders/ Labels that no longer exist on the remote.

        Notes
        -----
        Gmail uses IMAP folders and labels.
        Canonical folders ('all', 'trash', 'spam') are therefore mapped to both
        Folder and Label objects, everything else is created as a Label only.

        We don't canonicalize names to lowercase when saving because
        different backends may be case-sensitive or otherwise - code that
        references saved names should canonicalize if needed when doing
        comparisons.

        """
        account = db_session.query(Account).get(self.account_id)

        old_labels = {label for label in db_session.query(Label).filter(
            Label.account_id == self.account_id,
            Label.deleted_at == None)}

        new_labels = set()

        # Create new labels, folders
        for raw_folder in raw_folders:
            if raw_folder.role == 'starred':
                # The starred state of messages is tracked separately
                # (we set Message.is_starred from the '\\Flagged' flag)
                continue

            label = Label.find_or_create(db_session, account,
                                         raw_folder.display_name,
                                         raw_folder.role)
            new_labels.add(label)

            if label.deleted_at is not None:
                # This is a label which was previously marked as deleted
                # but which mysteriously reappeared. Unmark it.
                log.info('Deleted label recreated on remote',
                         name=raw_folder.display_name)
                label.deleted_at = None
                label.category.deleted_at = None

            if raw_folder.role in ('all', 'spam', 'trash'):
                folder = db_session.query(Folder).filter(
                    Folder.account_id == account.id,
                    Folder.canonical_name == raw_folder.role).first()
                if folder:
                    if folder.name != raw_folder.display_name:
                        log.info('Folder name changed on remote',
                                 account_id=self.account_id,
                                 role=raw_folder.role,
                                 new_name=raw_folder.display_name,
                                 name=folder.name)
                        folder.name = raw_folder.display_name

                    if folder.category:
                        if folder.category.display_name != \
                                raw_folder.display_name:
                            folder.category.display_name = raw_folder.display_name  # noqa
                    else:
                        log.info('Creating category for folder',
                                 account_id=self.account_id,
                                 folder_name=folder.name)
                        folder.category = Category.find_or_create(
                            db_session, namespace_id=account.namespace.id,
                            name=raw_folder.role,
                            display_name=raw_folder.display_name,
                            type_='folder')
                else:
                    Folder.find_or_create(db_session, account,
                                          raw_folder.display_name,
                                          raw_folder.role)

        # Ensure sync_should_run is True for the folders we want to sync (for
        # Gmail, that's just all folders, since we created them above if
        # they didn't exist.)
        for folder in account.folders:
            if folder.imapsyncstatus:
                folder.imapsyncstatus.sync_should_run = True

        # Go through the labels which have been "deleted" (i.e: they don't
        # show up when running LIST) and mark them as such.
        # We can't delete labels directly because Gmail allows users to hide
        # folders --- we need to check that there's no messages still
        # associated with the label.
        deleted_labels = old_labels - new_labels
        for deleted_label in deleted_labels:
            deleted_label.deleted_at = datetime.now()
            cat = deleted_label.category
            cat.deleted_at = datetime.now()

        db_session.commit()