Skip to content

Commit

Permalink
LocalFolderDiff
Browse files Browse the repository at this point in the history
  • Loading branch information
squeaky-pl committed Nov 7, 2024
1 parent ceae07d commit e930e84
Showing 1 changed file with 103 additions and 29 deletions.
132 changes: 103 additions & 29 deletions bin/inbox-summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,64 +86,128 @@ def fetch_remote_folders(
provider: str, crispin_client: CrispinClient
) -> Iterable[RemoteFolder]:
try:
folder_names = crispin_client.folder_names()
folders = crispin_client.folders()
except Exception:
return

for role, folders in folder_names.items():
if provider == "gmail" and role not in ["all", "spam", "trash"]:
for folder in sorted(folders, key=lambda f: f.display_name):
if provider == "gmail" and folder.role not in ["all", "spam", "trash"]:
continue

for folder in folders:
try:
result = crispin_client.select_folder(
folder, lambda _account_id, _folder_name, select_info: select_info
)
except Exception:
continue

yield RemoteFolder(
name=folder,
role=role,
uidnext=result[b"UIDNEXT"],
exists=result[b"EXISTS"],
try:
result = crispin_client.select_folder(
folder.display_name,
lambda _account_id, _folder_name, select_info: select_info,
)
except Exception:
continue

yield RemoteFolder(
name=folder.display_name,
role=folder.role,
uidnext=result[b"UIDNEXT"],
exists=result[b"EXISTS"],
)


@dataclasses.dataclass
class LocalFolder:
id: int
name: str
state: str
uidnext: int
uidmax: int
exists: int


def fetch_local_folders(account: LocalAccount) -> Iterable[LocalFolder]:
with global_session_scope() as db_session:
for folder in db_session.query(Folder).filter(Folder.account_id == account.id):
for folder in (
db_session.query(Folder)
.filter(Folder.account_id == account.id)
.order_by(Folder.name)
):
exists = (
db_session.query(ImapUid).filter(ImapUid.folder_id == folder.id).count()
)
uidnext = (
(
db_session.query(ImapUid.msg_uid)
.filter(ImapUid.folder_id == folder.id)
.order_by(ImapUid.msg_uid.desc())
.limit(1)
.scalar()
)
or 0
) + 1
uidmax = (
db_session.query(ImapUid.msg_uid)
.filter(ImapUid.folder_id == folder.id)
.order_by(ImapUid.msg_uid.desc())
.limit(1)
.scalar()
) or 0
yield LocalFolder(
id=folder.id,
name=folder.name,
state=folder.imapsyncstatus.state,
uidnext=uidnext,
uidmax=uidmax,
exists=exists,
)


@dataclasses.dataclass
class SummarizedList:
value: list
max_values: int = 10

def __repr__(self):
if len(self.value) <= self.max_values:
return repr(self.value)

return f"[{self.value[0]}, ... ,{self.value[-1]} len={len(self.value)}]"


@dataclasses.dataclass
class LocalFolderDiff:
name: str
uids_to_add: list[int]
uids_to_delete: list[int]


@dataclasses.dataclass
class LocalFolderMissing:
name: str


def compare_local_and_remote(
crispin_client: CrispinClient,
remote_folders: list[RemoteFolder],
local_folders: list[LocalFolder],
):
remote_folders_by_name = {folder.name: folder for folder in remote_folders}
local_folders_by_name = {folder.name: folder for folder in local_folders}

for name, remote_folder in remote_folders_by_name.items():
local_folder = local_folders_by_name.get(name)
if not local_folder:
yield LocalFolderMissing(name=name)

if local_folder.exists == remote_folder.exists:
continue

crispin_client.select_folder(
local_folder.name,
lambda _account_id, _folder_name, select_info: select_info,
)
remote_uids = set(crispin_client.all_uids())
with global_session_scope() as db_session:
local_uids = set(
uid
for uid, in db_session.query(ImapUid.msg_uid).filter(
ImapUid.folder_id == local_folder.id
)
)

uids_to_add = remote_uids - local_uids
uids_to_delete = local_uids - remote_uids

yield LocalFolderDiff(
name=local_folder.name,
uids_to_add=SummarizedList(sorted(uids_to_add)),
uids_to_delete=SummarizedList(sorted(uids_to_delete)),
)


@click.command()
@click.option("--host", default=None)
@click.option("--account-id", default=None)
Expand All @@ -163,18 +227,22 @@ def main(host: "str | None", account_id: "str | None", include_server_info: bool
print()

total_folder_remote_exists = 0
remote_folders = []
for remote_folder in fetch_remote_folders(
account.provider, crispin_client
):
print("\t", remote_folder)
remote_folders.append(remote_folder)
total_folder_remote_exists += remote_folder.exists
total_remote_exists += remote_folder.exists
print("\t Total remote EXISTS:", total_folder_remote_exists)
print()

total_folder_local_exists = 0
local_folders = []
for local_folder in fetch_local_folders(account):
print("\t", local_folder)
local_folders.append(local_folder)
total_folder_local_exists += local_folder.exists
total_local_exists += local_folder.exists
print("\t Total local EXISTS:", total_folder_local_exists)
Expand All @@ -183,6 +251,12 @@ def main(host: "str | None", account_id: "str | None", include_server_info: bool
total_folder_remote_exists - total_folder_local_exists,
)
print()

for diff in compare_local_and_remote(
crispin_client, remote_folders, local_folders
):
print("\t", diff)
print()
except Exception as e:
print("\t Exception opening the connection", e)
print()
Expand Down

0 comments on commit e930e84

Please sign in to comment.