mirror of
https://github.com/tutao/tutanota.git
synced 2025-12-07 13:49:47 +00:00
[tutadb] TutanotaV99 - Tutanota Model Cleanup
* Rename MailSet to MailFolder * Change cardinality of multiple type to One Co-authored-by: kib <kib@tutao.de>
This commit is contained in:
parent
86f278ebc9
commit
db154662ff
61 changed files with 2011 additions and 2100 deletions
|
|
@ -4,7 +4,7 @@ use std::fs;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tutasdk::bindings::test_file_client::TestFileClient;
|
||||
use tutasdk::entities::generated::tutanota::MailFolder;
|
||||
use tutasdk::entities::generated::tutanota::MailSet;
|
||||
use tutasdk::folder_system::MailSetKind;
|
||||
use tutasdk::net::native_rest_client::NativeRestClient;
|
||||
use tutasdk::{LoggedInSdk, Sdk};
|
||||
|
|
@ -105,10 +105,7 @@ pub async fn init_file_importer(source_paths: Vec<&str>) -> Importer {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
async fn get_test_import_folder_id(
|
||||
logged_in_sdk: &Arc<LoggedInSdk>,
|
||||
kind: MailSetKind,
|
||||
) -> MailFolder {
|
||||
async fn get_test_import_folder_id(logged_in_sdk: &Arc<LoggedInSdk>, kind: MailSetKind) -> MailSet {
|
||||
let mail_facade = logged_in_sdk.mail_facade();
|
||||
let mailbox = mail_facade.load_user_mailbox().await.unwrap();
|
||||
let folders = mail_facade
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
ContactCustomDate,
|
||||
ContactRelationship,
|
||||
ContactSocialId,
|
||||
MailFolder,
|
||||
MailSet,
|
||||
UserSettingsGroupRoot,
|
||||
} from "../entities/tutanota/TypeRefs.js"
|
||||
import { isApp, isElectronClient, isIOSApp } from "./Env"
|
||||
|
|
@ -29,17 +29,17 @@ export const REQUEST_SIZE_LIMIT_MAP: Map<string, number> = new Map([
|
|||
|
||||
export const SYSTEM_GROUP_MAIL_ADDRESS = "system@tutanota.de"
|
||||
|
||||
export const getMailFolderType = (folder: MailFolder): MailSetKind => downcast(folder.folderType)
|
||||
export const getMailFolderType = (folder: MailSet): MailSetKind => downcast(folder.folderType)
|
||||
|
||||
export function isFolder(folder: MailFolder): boolean {
|
||||
export function isFolder(folder: MailSet): boolean {
|
||||
return folder.folderType !== MailSetKind.ALL && folder.folderType !== MailSetKind.LABEL && folder.folderType !== MailSetKind.Imported
|
||||
}
|
||||
|
||||
export function isNestableMailSet(mailSet: MailFolder): boolean {
|
||||
export function isNestableMailSet(mailSet: MailSet): boolean {
|
||||
return mailSet.folderType === MailSetKind.CUSTOM
|
||||
}
|
||||
|
||||
export function isLabel(folder: MailFolder): boolean {
|
||||
export function isLabel(folder: MailSet): boolean {
|
||||
return folder.folderType === MailSetKind.LABEL
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ export enum MailSetKind {
|
|||
export const SYSTEM_FOLDERS = [MailSetKind.INBOX, MailSetKind.SENT, MailSetKind.TRASH, MailSetKind.ARCHIVE, MailSetKind.SPAM, MailSetKind.DRAFT] as const
|
||||
export type SystemFolderType = (typeof SYSTEM_FOLDERS)[number]
|
||||
|
||||
export function getMailSetKind(folder: MailFolder): MailSetKind {
|
||||
export function getMailSetKind(folder: MailSet): MailSetKind {
|
||||
return folder.folderType as MailSetKind
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
import { groupBy, partition } from "@tutao/tutanota-utils"
|
||||
import { Mail, MailFolder } from "../../entities/tutanota/TypeRefs.js"
|
||||
import { Mail, MailSet } from "../../entities/tutanota/TypeRefs.js"
|
||||
import { isFolder, MailSetKind, SystemFolderType } from "../TutanotaConstants.js"
|
||||
import { elementIdPart, getElementId, isSameId } from "../utils/EntityUtils.js"
|
||||
|
||||
export interface IndentedFolder {
|
||||
level: number
|
||||
folder: MailFolder
|
||||
folder: MailSet
|
||||
}
|
||||
|
||||
/** Accessor for the folder trees. */
|
||||
export class FolderSystem {
|
||||
readonly systemSubtrees: ReadonlyArray<FolderSubtree>
|
||||
readonly customSubtrees: ReadonlyArray<FolderSubtree>
|
||||
readonly importedMailSet: Readonly<MailFolder | null>
|
||||
readonly importedMailSet: Readonly<MailSet | null>
|
||||
|
||||
constructor(mailSets: readonly MailFolder[]) {
|
||||
constructor(mailSets: readonly MailSet[]) {
|
||||
const [folders, nonFolders] = partition(mailSets, (f) => isFolder(f))
|
||||
const folderByParent = groupBy(folders, (folder) => (folder.parentFolder ? elementIdPart(folder.parentFolder) : null))
|
||||
const topLevelFolders = folders.filter((f) => f.parentFolder == null)
|
||||
|
|
@ -26,21 +26,21 @@ export class FolderSystem {
|
|||
this.customSubtrees = customFolders.sort(compareCustom).map((f) => this.makeSubtree(folderByParent, f, compareCustom))
|
||||
}
|
||||
|
||||
getIndentedList(excludeFolder: MailFolder | null = null): IndentedFolder[] {
|
||||
getIndentedList(excludeFolder: MailSet | null = null): IndentedFolder[] {
|
||||
return [...this.getIndentedFolderList(this.systemSubtrees, excludeFolder), ...this.getIndentedFolderList(this.customSubtrees, excludeFolder)]
|
||||
}
|
||||
|
||||
/** Search for a specific folder type. Some mailboxes might not have some system folders! */
|
||||
getSystemFolderByType(type: SystemFolderType): MailFolder | null {
|
||||
getSystemFolderByType(type: SystemFolderType): MailSet | null {
|
||||
return this.systemSubtrees.find((f) => f.folder.folderType === type)?.folder ?? null
|
||||
}
|
||||
|
||||
getFolderById(folderId: Id): MailFolder | null {
|
||||
getFolderById(folderId: Id): MailSet | null {
|
||||
const subtree = this.getFolderByIdInSubtrees(this.systemSubtrees, folderId) ?? this.getFolderByIdInSubtrees(this.customSubtrees, folderId)
|
||||
return subtree?.folder ?? null
|
||||
}
|
||||
|
||||
getFolderByMail(mail: Mail): MailFolder | null {
|
||||
getFolderByMail(mail: Mail): MailSet | null {
|
||||
const sets = mail.sets
|
||||
for (const setId of sets) {
|
||||
const folder = this.getFolderById(elementIdPart(setId))
|
||||
|
|
@ -55,7 +55,7 @@ export class FolderSystem {
|
|||
* Returns the children of a parent (applies only to custom folders)
|
||||
* if no parent is given, the top level custom folders are returned
|
||||
*/
|
||||
getCustomFoldersOfParent(parent: IdTuple | null): MailFolder[] {
|
||||
getCustomFoldersOfParent(parent: IdTuple | null): MailSet[] {
|
||||
if (parent) {
|
||||
const parentFolder = this.getFolderByIdInSubtrees([...this.customSubtrees, ...this.systemSubtrees], elementIdPart(parent))
|
||||
return parentFolder ? parentFolder.children.map((child) => child.folder) : []
|
||||
|
|
@ -74,12 +74,12 @@ export class FolderSystem {
|
|||
}
|
||||
|
||||
/** returns all parents of the folder, including the folder itself */
|
||||
getPathToFolder(folderId: IdTuple): MailFolder[] {
|
||||
getPathToFolder(folderId: IdTuple): MailSet[] {
|
||||
return this.getPathToFolderInSubtrees(this.systemSubtrees, folderId) ?? this.getPathToFolderInSubtrees(this.customSubtrees, folderId) ?? []
|
||||
}
|
||||
|
||||
checkFolderForAncestor(folder: MailFolder, potentialAncestorId: IdTuple): boolean {
|
||||
let currentFolderPointer: MailFolder | null = folder
|
||||
checkFolderForAncestor(folder: MailSet, potentialAncestorId: IdTuple): boolean {
|
||||
let currentFolderPointer: MailSet | null = folder
|
||||
while (true) {
|
||||
if (currentFolderPointer?.parentFolder == null) {
|
||||
return false
|
||||
|
|
@ -90,7 +90,7 @@ export class FolderSystem {
|
|||
}
|
||||
}
|
||||
|
||||
private getIndentedFolderList(subtrees: ReadonlyArray<FolderSubtree>, excludeFolder: MailFolder | null = null, currentLevel: number = 0): IndentedFolder[] {
|
||||
private getIndentedFolderList(subtrees: ReadonlyArray<FolderSubtree>, excludeFolder: MailSet | null = null, currentLevel: number = 0): IndentedFolder[] {
|
||||
const plainList: IndentedFolder[] = []
|
||||
for (const subtree of subtrees) {
|
||||
if (!excludeFolder || !isSameId(subtree.folder._id, excludeFolder._id)) {
|
||||
|
|
@ -126,7 +126,7 @@ export class FolderSystem {
|
|||
return null
|
||||
}
|
||||
|
||||
private getPathToFolderInSubtrees(systems: readonly FolderSubtree[], folderId: IdTuple): MailFolder[] | null {
|
||||
private getPathToFolderInSubtrees(systems: readonly FolderSubtree[], folderId: IdTuple): MailSet[] | null {
|
||||
for (const system of systems) {
|
||||
if (isSameId(system.folder._id, folderId)) {
|
||||
return [system.folder]
|
||||
|
|
@ -139,7 +139,7 @@ export class FolderSystem {
|
|||
return null
|
||||
}
|
||||
|
||||
private makeSubtree(folderByParent: Map<Id | null, readonly MailFolder[]>, parent: MailFolder, comparator: FolderComparator): FolderSubtree {
|
||||
private makeSubtree(folderByParent: Map<Id | null, readonly MailSet[]>, parent: MailSet, comparator: FolderComparator): FolderSubtree {
|
||||
const childrenFolders = folderByParent.get(getElementId(parent))
|
||||
if (childrenFolders) {
|
||||
const childSystems = childrenFolders
|
||||
|
|
@ -153,9 +153,9 @@ export class FolderSystem {
|
|||
}
|
||||
}
|
||||
|
||||
type FolderComparator = (folder1: MailFolder, folder2: MailFolder) => number
|
||||
type FolderComparator = (folder1: MailSet, folder2: MailSet) => number
|
||||
|
||||
function compareCustom(folder1: MailFolder, folder2: MailFolder): number {
|
||||
function compareCustom(folder1: MailSet, folder2: MailSet): number {
|
||||
return folder1.name.localeCompare(folder2.name)
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ const folderTypeToOrder: Record<SystemMailFolderTypes, number> = {
|
|||
[MailSetKind.ALL]: 7,
|
||||
}
|
||||
|
||||
function compareSystem(folder1: MailFolder, folder2: MailFolder): number {
|
||||
function compareSystem(folder1: MailSet, folder2: MailSet): number {
|
||||
const order1 = folderTypeToOrder[folder1.folderType as SystemMailFolderTypes] ?? 7
|
||||
const order2 = folderTypeToOrder[folder2.folderType as SystemMailFolderTypes] ?? 7
|
||||
return order1 - order2
|
||||
|
|
@ -182,6 +182,6 @@ function compareSystem(folder1: MailFolder, folder2: MailFolder): number {
|
|||
* the top folders are the toplevel folders in with their respective subfolders.
|
||||
*/
|
||||
export interface FolderSubtree {
|
||||
readonly folder: MailFolder
|
||||
readonly folder: MailSet
|
||||
readonly children: readonly FolderSubtree[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const modelInfo = {
|
||||
version: 36,
|
||||
version: 37,
|
||||
}
|
||||
|
||||
export default modelInfo
|
||||
|
|
@ -9,7 +9,7 @@ export const typeModels = {
|
|||
"12": {
|
||||
"name": "ReadCounterData",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 1,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 12,
|
||||
|
|
@ -56,7 +56,7 @@ export const typeModels = {
|
|||
"16": {
|
||||
"name": "ReadCounterReturn",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 1,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 16,
|
||||
|
|
@ -97,7 +97,7 @@ export const typeModels = {
|
|||
"49": {
|
||||
"name": "WriteCounterData",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 4,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 49,
|
||||
|
|
@ -152,7 +152,7 @@ export const typeModels = {
|
|||
"221": {
|
||||
"name": "ApprovalMail",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 14,
|
||||
"type": "LIST_ELEMENT_TYPE",
|
||||
"id": 221,
|
||||
|
|
@ -233,7 +233,7 @@ export const typeModels = {
|
|||
"300": {
|
||||
"name": "CounterValue",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 22,
|
||||
"type": "AGGREGATED_TYPE",
|
||||
"id": 300,
|
||||
|
|
@ -272,7 +272,7 @@ export const typeModels = {
|
|||
"305": {
|
||||
"name": "ErrorReportFile",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 23,
|
||||
"type": "AGGREGATED_TYPE",
|
||||
"id": 305,
|
||||
|
|
@ -311,7 +311,7 @@ export const typeModels = {
|
|||
"316": {
|
||||
"name": "ErrorReportData",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 23,
|
||||
"type": "AGGREGATED_TYPE",
|
||||
"id": 316,
|
||||
|
|
@ -406,7 +406,7 @@ export const typeModels = {
|
|||
"335": {
|
||||
"name": "ReportErrorIn",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 23,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 335,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const modelInfo = {
|
||||
version: 98,
|
||||
version: 99,
|
||||
}
|
||||
|
||||
export default modelInfo
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
|||
import type { CryptoFacade } from "../../crypto/CryptoFacade.js"
|
||||
import {
|
||||
ApplyLabelService,
|
||||
ClientClassifierResultService,
|
||||
DraftService,
|
||||
ExternalUserService,
|
||||
ListUnsubscribeService,
|
||||
|
|
@ -34,7 +33,6 @@ import {
|
|||
MAX_NBR_OF_MAILS_SYNC_OPERATION,
|
||||
OperationType,
|
||||
PhishingMarkerStatus,
|
||||
ProcessingState,
|
||||
PublicKeyIdentifierType,
|
||||
ReportedMailFieldType,
|
||||
SimpleMoveMailTarget,
|
||||
|
|
@ -44,7 +42,6 @@ import {
|
|||
Contact,
|
||||
createApplyLabelServicePostIn,
|
||||
createAttachmentKeyData,
|
||||
createClientClassifierResultPostIn,
|
||||
createCreateExternalUserGroupData,
|
||||
createCreateMailFolderData,
|
||||
createDeleteMailData,
|
||||
|
|
@ -84,7 +81,7 @@ import {
|
|||
MailDetails,
|
||||
MailDetailsBlobTypeRef,
|
||||
MailDetailsDraftTypeRef,
|
||||
MailFolder,
|
||||
MailSet,
|
||||
MailTypeRef,
|
||||
MovedMails,
|
||||
PopulateClientSpamTrainingDatum,
|
||||
|
|
@ -245,7 +242,7 @@ export class MailFacade {
|
|||
* @param folder to be updated
|
||||
* @param newName - if this is the same as the folder's current name, nothing is done
|
||||
*/
|
||||
async updateMailFolderName(folder: MailFolder, newName: string): Promise<void> {
|
||||
async updateMailFolderName(folder: MailSet, newName: string): Promise<void> {
|
||||
if (newName !== folder.name) {
|
||||
folder.name = newName
|
||||
await this.entityClient.update(folder)
|
||||
|
|
@ -264,7 +261,7 @@ export class MailFacade {
|
|||
* @param folder to be updated
|
||||
* @param newParent - if this is the same as the folder's current parent, nothing is done
|
||||
*/
|
||||
async updateMailFolderParent(folder: MailFolder, newParent: IdTuple | null): Promise<void> {
|
||||
async updateMailFolderParent(folder: MailSet, newParent: IdTuple | null): Promise<void> {
|
||||
const isOwnParent = isSameId(folder._id, newParent)
|
||||
const isDifferentParent = folder.parentFolder != null && newParent != null && !isSameId(folder.parentFolder, newParent)
|
||||
const isNewParent = folder.parentFolder == null && newParent != null
|
||||
|
|
@ -750,7 +747,7 @@ export class MailFacade {
|
|||
await this.serviceExecutor.delete(MailFolderService, deleteMailFolderData, { sessionKey: "dummy" as any })
|
||||
}
|
||||
|
||||
async fixupCounterForFolder(groupId: Id, folder: MailFolder, unreadMails: number): Promise<void> {
|
||||
async fixupCounterForFolder(groupId: Id, folder: MailSet, unreadMails: number): Promise<void> {
|
||||
const counterId = getElementId(folder)
|
||||
const data = createWriteCounterData({
|
||||
counterType: CounterType.UnreadMails,
|
||||
|
|
@ -1132,7 +1129,7 @@ export class MailFacade {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a label (aka MailSet aka {@link MailFolder} of kind {@link MailSetKind.LABEL}) for the group {@param mailGroupId}.
|
||||
* Create a label (aka MailSet aka {@link MailSet} of kind {@link MailSetKind.LABEL}) for the group {@param mailGroupId}.
|
||||
*/
|
||||
async createLabel(mailGroupId: Id, labelData: { name: string; color: string }) {
|
||||
const mailGroupKey = await this.keyLoaderFacade.getCurrentSymGroupKey(mailGroupId)
|
||||
|
|
@ -1162,7 +1159,7 @@ export class MailFacade {
|
|||
* @param name possible new name for label
|
||||
* @param color possible new color for label
|
||||
*/
|
||||
async updateLabel(label: MailFolder, name: string, color: string) {
|
||||
async updateLabel(label: MailSet, name: string, color: string) {
|
||||
if (name !== label.name || color !== label.color) {
|
||||
label.name = name
|
||||
label.color = color
|
||||
|
|
@ -1170,7 +1167,7 @@ export class MailFacade {
|
|||
}
|
||||
}
|
||||
|
||||
async deleteLabel(label: MailFolder) {
|
||||
async deleteLabel(label: MailSet) {
|
||||
await this.serviceExecutor.delete(
|
||||
ManageLabelService,
|
||||
createManageLabelServiceDeleteIn({
|
||||
|
|
@ -1179,7 +1176,7 @@ export class MailFacade {
|
|||
)
|
||||
}
|
||||
|
||||
async applyLabels(mailIds: IdTuple[], addedLabels: readonly MailFolder[], removedLabels: readonly MailFolder[]) {
|
||||
async applyLabels(mailIds: IdTuple[], addedLabels: readonly MailSet[], removedLabels: readonly MailSet[]) {
|
||||
const postIn = createApplyLabelServicePostIn({
|
||||
mails: mailIds,
|
||||
addedLabels: addedLabels.map((label) => label._id),
|
||||
|
|
@ -1213,22 +1210,6 @@ export class MailFacade {
|
|||
* @param mails mail ids to mark as unread
|
||||
* @param processingState
|
||||
*/
|
||||
async updateMailPredictionState(mails: readonly IdTuple[], processingState: ProcessingState) {
|
||||
const isPredictionMade = processingState === ProcessingState.INBOX_RULE_PROCESSED_AND_SPAM_PREDICTION_MADE
|
||||
await promiseMap(
|
||||
splitInChunks(MAX_NBR_OF_MAILS_SYNC_OPERATION, mails),
|
||||
async (mails) =>
|
||||
this.serviceExecutor.post(
|
||||
ClientClassifierResultService,
|
||||
createClientClassifierResultPostIn({
|
||||
mails,
|
||||
isPredictionMade: isPredictionMade,
|
||||
}),
|
||||
),
|
||||
{ concurrency: 5 },
|
||||
)
|
||||
}
|
||||
|
||||
private async encryptUnencryptedProcessInboxData(
|
||||
mailGroupId: Id,
|
||||
unencryptedProcessInboxData: readonly UnencryptedProcessInboxDatum[],
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { ButtonType } from "../../gui/base/Button.js"
|
|||
import m from "mithril"
|
||||
import { DropDownSelector, DropDownSelectorAttrs } from "../../gui/base/DropDownSelector.js"
|
||||
import { BootIcons } from "../../gui/base/icons/BootIcons.js"
|
||||
import { MailFolder } from "../../api/entities/tutanota/TypeRefs"
|
||||
import { MailSet } from "../../api/entities/tutanota/TypeRefs"
|
||||
import { IndentedFolder } from "../../api/common/mail/FolderSystem"
|
||||
import { repeat } from "@tutao/tutanota-utils"
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ import { repeat } from "@tutao/tutanota-utils"
|
|||
* @param indentedFolders List of user's folders
|
||||
* @param okAction
|
||||
*/
|
||||
export function folderSelectionDialog(indentedFolders: IndentedFolder[], okAction: (dialog: Dialog, selectedMailFolder: MailFolder) => unknown) {
|
||||
export function folderSelectionDialog(indentedFolders: IndentedFolder[], okAction: (dialog: Dialog, selectedMailFolder: MailSet) => unknown) {
|
||||
let selectedIndentedFolder = indentedFolders[0]
|
||||
|
||||
const dialog = new Dialog(DialogType.EditSmall, {
|
||||
|
|
@ -54,7 +54,7 @@ export function folderSelectionDialog(indentedFolders: IndentedFolder[], okActio
|
|||
selectedValue: selectedIndentedFolder.folder,
|
||||
selectionChangedHandler: (v) => (selectedIndentedFolder.folder = v),
|
||||
icon: BootIcons.Expand,
|
||||
} satisfies DropDownSelectorAttrs<MailFolder>),
|
||||
} satisfies DropDownSelectorAttrs<MailSet>),
|
||||
]),
|
||||
],
|
||||
}).show()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { getApiBaseUrl } from "../../../common/api/common/Env"
|
||||
import { ImportMailState, ImportMailStateTypeRef, MailBox, MailFolder, MailFolderTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { ImportMailState, ImportMailStateTypeRef, MailBox, MailSet, MailSetTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { assertNotNull, first, isEmpty } from "@tutao/tutanota-utils"
|
||||
import { NativeMailImportFacade } from "../../../common/native/common/generatedipc/NativeMailImportFacade"
|
||||
import { CredentialsProvider } from "../../../common/misc/credentials/CredentialsProvider"
|
||||
|
|
@ -39,7 +39,7 @@ export class MailImporter {
|
|||
private finalisedImportStates: Map<Id, ImportMailState> = new Map()
|
||||
private activeImport: ActiveImport | null = null
|
||||
public foldersForMailbox: FolderSystem | undefined
|
||||
public selectedTargetFolder: MailFolder | null = null
|
||||
public selectedTargetFolder: MailSet | null = null
|
||||
|
||||
constructor(
|
||||
private readonly domainConfigProvider: DomainConfigProvider,
|
||||
|
|
@ -122,7 +122,7 @@ export class MailImporter {
|
|||
uiStatus: UiImportStatus.Paused,
|
||||
progressMonitor,
|
||||
}
|
||||
this.selectedTargetFolder = await this.entityClient.load(MailFolderTypeRef, importMailState.targetFolder)
|
||||
this.selectedTargetFolder = await this.entityClient.load(MailSetTypeRef, importMailState.targetFolder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { applyInboxRulesAndSpamPrediction, LoadedMail, MailSetListModel, resolveMailSetEntries } from "./MailSetListModel"
|
||||
import { ListLoadingState, ListState } from "../../../common/gui/base/List"
|
||||
import { Mail, MailFolder, MailFolderTypeRef, MailSetEntry, MailSetEntryTypeRef, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { Mail, MailSet, MailSetTypeRef, MailSetEntry, MailSetEntryTypeRef, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { EntityUpdateData, isUpdateForTypeRef } from "../../../common/api/common/utils/EntityUpdateUtils"
|
||||
import { ListFilter, ListModel } from "../../../common/misc/ListModel"
|
||||
import Stream from "mithril/stream"
|
||||
|
|
@ -64,7 +64,7 @@ export class ConversationListModel implements MailSetListModel {
|
|||
private olderDisplayedSelectedMailOverride: Id | null = null
|
||||
|
||||
constructor(
|
||||
private readonly mailSet: MailFolder,
|
||||
private readonly mailSet: MailSet,
|
||||
private readonly conversationPrefProvider: ConversationPrefProvider,
|
||||
private readonly entityClient: EntityClient,
|
||||
private readonly mailModel: MailModel,
|
||||
|
|
@ -108,7 +108,7 @@ export class ConversationListModel implements MailSetListModel {
|
|||
this.listModel.enterMultiselect()
|
||||
}
|
||||
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailFolder> {
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailSet> {
|
||||
return this._getLoadedMail(getElementId(mail))?.labels ?? []
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ export class ConversationListModel implements MailSetListModel {
|
|||
)
|
||||
|
||||
async handleEntityUpdate(update: EntityUpdateData) {
|
||||
if (isUpdateForTypeRef(MailFolderTypeRef, update)) {
|
||||
if (isUpdateForTypeRef(MailSetTypeRef, update)) {
|
||||
if (update.operation === OperationType.UPDATE) {
|
||||
this.handleMailFolderUpdate([update.instanceListId, update.instanceId])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { InboxRule, Mail, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { InboxRule, Mail, MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { InboxRuleType, MailSetKind, ProcessingState } from "../../../common/api/common/TutanotaConstants"
|
||||
import { isDomainName, isRegularExpression } from "../../../common/misc/FormatValidator"
|
||||
import { assertNotNull, asyncFind, Nullable } from "@tutao/tutanota-utils"
|
||||
import { asyncFind, Nullable } from "@tutao/tutanota-utils"
|
||||
import { lang } from "../../../common/misc/LanguageViewModel"
|
||||
import type { MailboxDetail } from "../../../common/mailFunctionality/MailboxModel.js"
|
||||
import type { SelectorItemList } from "../../../common/gui/base/DropDownSelector.js"
|
||||
|
|
@ -64,19 +64,13 @@ export class InboxRuleHandler {
|
|||
async findAndApplyMatchingRule(
|
||||
mailboxDetail: MailboxDetail,
|
||||
mail: Readonly<Mail>,
|
||||
): Promise<Nullable<{ targetFolder: MailFolder; processInboxDatum: UnencryptedProcessInboxDatum }>> {
|
||||
): Promise<Nullable<{ targetFolder: MailSet; processInboxDatum: UnencryptedProcessInboxDatum }>> {
|
||||
const shouldApply =
|
||||
(mail.processingState === ProcessingState.INBOX_RULE_NOT_PROCESSED ||
|
||||
mail.processingState === ProcessingState.INBOX_RULE_NOT_PROCESSED_AND_DO_NOT_RUN_SPAM_PREDICTION) &&
|
||||
mail.processNeeded
|
||||
|
||||
if (
|
||||
mail._errors ||
|
||||
!shouldApply ||
|
||||
!(await isLandingFolder(this.mailModel, mailboxDetail, mail)) ||
|
||||
!this.logins.getUserController().isPaidAccount() ||
|
||||
mailboxDetail.mailbox.folders == null
|
||||
) {
|
||||
if (mail._errors || !shouldApply || !(await isLandingFolder(this.mailModel, mailboxDetail, mail)) || !this.logins.getUserController().isPaidAccount()) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +188,7 @@ function _checkEmailAddresses(mailAddresses: string[], inboxRule: InboxRule): bo
|
|||
}
|
||||
|
||||
async function isLandingFolder(mailModel: MailModel, mailboxDetail: MailboxDetail, mail: Mail): Promise<boolean> {
|
||||
const folders = await mailModel.getMailboxFoldersForId(assertNotNull(mailboxDetail.mailbox.folders)._id)
|
||||
const folders = await mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
const mailFolder = folders.getFolderByMail(mail)
|
||||
return mailFolder?.folderType === MailSetKind.INBOX || mailFolder?.folderType === MailSetKind.SPAM
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
//@bundleInto:common
|
||||
|
||||
import { Mail, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { Mail, MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { MailModel } from "./MailModel.js"
|
||||
import { FolderSystem } from "../../../common/api/common/mail/FolderSystem.js"
|
||||
import { MailSetKind, SystemFolderType } from "../../../common/api/common/TutanotaConstants.js"
|
||||
|
||||
export function isSubfolderOfType(system: FolderSystem, folder: MailFolder, type: SystemFolderType): boolean {
|
||||
export function isSubfolderOfType(system: FolderSystem, folder: MailSet, type: SystemFolderType): boolean {
|
||||
const systemFolder = system.getSystemFolderByType(type)
|
||||
return systemFolder != null && system.checkFolderForAncestor(folder, systemFolder._id)
|
||||
}
|
||||
|
|
@ -34,14 +34,14 @@ export async function isMailInSpam(mail: Mail, mailModel: MailModel): Promise<bo
|
|||
}
|
||||
}
|
||||
|
||||
export function isSpamFolder(system: FolderSystem, folder: MailFolder): boolean {
|
||||
export function isSpamFolder(system: FolderSystem, folder: MailSet): boolean {
|
||||
return folder.folderType === MailSetKind.SPAM || isSubfolderOfType(system, folder, MailSetKind.SPAM)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given folder is the {@link MailFolderType.SPAM} or {@link MailFolderType.TRASH} folder, or a descendant of those folders.
|
||||
*/
|
||||
export function isSpamOrTrashFolder(system: FolderSystem, folder: MailFolder): boolean {
|
||||
export function isSpamOrTrashFolder(system: FolderSystem, folder: MailSet): boolean {
|
||||
// not using isOfTypeOrSubfolderOf because checking the type first is cheaper
|
||||
return (
|
||||
folder.folderType === MailSetKind.TRASH ||
|
||||
|
|
@ -51,6 +51,6 @@ export function isSpamOrTrashFolder(system: FolderSystem, folder: MailFolder): b
|
|||
)
|
||||
}
|
||||
|
||||
export function isOfTypeOrSubfolderOf(system: FolderSystem, folder: MailFolder, type: SystemFolderType): boolean {
|
||||
export function isOfTypeOrSubfolderOf(system: FolderSystem, folder: MailSet, type: SystemFolderType): boolean {
|
||||
return folder.folderType === type || isSubfolderOfType(system, folder, type)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ListFilter, ListModel } from "../../../common/misc/ListModel"
|
||||
import { Mail, MailFolder, MailFolderTypeRef, MailSetEntry, MailSetEntryTypeRef, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { Mail, MailSet, MailSetTypeRef, MailSetEntry, MailSetEntryTypeRef, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import {
|
||||
CUSTOM_MAX_ID,
|
||||
customIdToUint8array,
|
||||
|
|
@ -38,7 +38,7 @@ export class MailListModel implements MailSetListModel {
|
|||
private readonly mailMap: Map<Id, LoadedMail> = new Map()
|
||||
|
||||
constructor(
|
||||
private readonly mailSet: MailFolder,
|
||||
private readonly mailSet: MailSet,
|
||||
private readonly conversationPrefProvider: ConversationPrefProvider,
|
||||
private readonly entityClient: EntityClient,
|
||||
private readonly mailModel: MailModel,
|
||||
|
|
@ -118,7 +118,7 @@ export class MailListModel implements MailSetListModel {
|
|||
return this.getLoadedMailByMailId(mailElementId)?.mail ?? null
|
||||
}
|
||||
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailFolder> {
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailSet> {
|
||||
return this.getLoadedMailByMailInstance(mail)?.labels ?? []
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +150,7 @@ export class MailListModel implements MailSetListModel {
|
|||
)
|
||||
|
||||
async handleEntityUpdate(update: EntityUpdateData) {
|
||||
if (isUpdateForTypeRef(MailFolderTypeRef, update)) {
|
||||
if (isUpdateForTypeRef(MailSetTypeRef, update)) {
|
||||
// If a label is modified, we want to update all mails that reference it, which requires linearly iterating
|
||||
// through all mails. There are more efficient ways we could do this, such as by keeping track of each label
|
||||
// we've retrieved from the database and just update that, but we want to avoid adding more maps that we
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import {
|
|||
Mail,
|
||||
MailboxGroupRoot,
|
||||
MailboxProperties,
|
||||
MailFolder,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetTypeRef,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
MovedMails,
|
||||
|
|
@ -60,7 +60,7 @@ import { isWebClient } from "../../../common/api/common/Env"
|
|||
interface MailboxSets {
|
||||
folders: FolderSystem
|
||||
/** a map from element id to the mail set */
|
||||
labels: ReadonlyMap<Id, MailFolder>
|
||||
labels: ReadonlyMap<Id, MailSet>
|
||||
}
|
||||
|
||||
export const enum LabelState {
|
||||
|
|
@ -123,7 +123,7 @@ export class MailModel {
|
|||
for (let detail of mailboxDetails) {
|
||||
const foldersRef = detail.mailbox.folders
|
||||
if (foldersRef != null) {
|
||||
let mailSets: MailFolder[]
|
||||
let mailSets: MailSet[]
|
||||
try {
|
||||
mailSets = await this.loadMailSetsForListId(foldersRef.folders)
|
||||
} catch (e) {
|
||||
|
|
@ -162,8 +162,8 @@ export class MailModel {
|
|||
return tempFolders
|
||||
}
|
||||
|
||||
private async loadMailSetsForListId(listId: Id): Promise<MailFolder[]> {
|
||||
const folders = await this.entityClient.loadAll(MailFolderTypeRef, listId)
|
||||
private async loadMailSetsForListId(listId: Id): Promise<MailSet[]> {
|
||||
const folders = await this.entityClient.loadAll(MailSetTypeRef, listId)
|
||||
|
||||
return folders.filter((f) => {
|
||||
// We do not show spam or archive for external users
|
||||
|
|
@ -186,7 +186,7 @@ export class MailModel {
|
|||
// visibleForTesting
|
||||
async entityEventsReceived(updates: ReadonlyArray<EntityUpdateData>): Promise<void> {
|
||||
for (const update of updates) {
|
||||
if (isUpdateForTypeRef(MailFolderTypeRef, update)) {
|
||||
if (isUpdateForTypeRef(MailSetTypeRef, update)) {
|
||||
await this.init()
|
||||
m.redraw()
|
||||
} else if (isUpdateForTypeRef(MailTypeRef, update) && update.operation === OperationType.CREATE) {
|
||||
|
|
@ -239,7 +239,7 @@ export class MailModel {
|
|||
return detail
|
||||
}
|
||||
|
||||
async getMailboxDetailsForMailFolder(mailFolder: MailFolder): Promise<MailboxDetail | null> {
|
||||
async getMailboxDetailsForMailFolder(mailFolder: MailSet): Promise<MailboxDetail | null> {
|
||||
const detail = await this.mailboxModel.getMailboxDetailsForMailGroup(assertNotNull(mailFolder._ownerGroup))
|
||||
if (detail == null) {
|
||||
console.warn("mailbox detail for mail folder does not exist", mailFolder)
|
||||
|
|
@ -249,7 +249,7 @@ export class MailModel {
|
|||
|
||||
async getMailboxFoldersForMail(mail: Mail): Promise<FolderSystem | null> {
|
||||
const mailboxDetail = await this.getMailboxDetailsForMail(mail)
|
||||
if (mailboxDetail && mailboxDetail.mailbox.folders) {
|
||||
if (mailboxDetail) {
|
||||
const folders = await this.getFolders()
|
||||
return folders.get(mailboxDetail.mailbox.folders._id)?.folders ?? null
|
||||
} else {
|
||||
|
|
@ -266,7 +266,7 @@ export class MailModel {
|
|||
return folderSystem
|
||||
}
|
||||
|
||||
getMailFolderForMail(mail: Mail): MailFolder | null {
|
||||
getMailFolderForMail(mail: Mail): MailSet | null {
|
||||
const folderSystem = this.getFolderSystemByGroupId(assertNotNull(mail._ownerGroup))
|
||||
if (folderSystem == null) return null
|
||||
|
||||
|
|
@ -277,14 +277,14 @@ export class MailModel {
|
|||
return this.getMailSetsForGroup(groupId)?.folders ?? null
|
||||
}
|
||||
|
||||
getLabelsByGroupId(groupId: Id): ReadonlyMap<Id, MailFolder> {
|
||||
getLabelsByGroupId(groupId: Id): ReadonlyMap<Id, MailSet> {
|
||||
return this.getMailSetsForGroup(groupId)?.labels ?? new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all labels that could be applied to the {@param mails} with the state relative to {@param mails}.
|
||||
*/
|
||||
getLabelStatesForMails(mails: readonly Mail[]): { label: MailFolder; state: LabelState }[] {
|
||||
getLabelStatesForMails(mails: readonly Mail[]): { label: MailSet; state: LabelState }[] {
|
||||
if (mails.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
|
@ -304,8 +304,8 @@ export class MailModel {
|
|||
})
|
||||
}
|
||||
|
||||
getLabelsForMails(mails: readonly Mail[]): ReadonlyMap<Id, ReadonlyArray<MailFolder>> {
|
||||
const labelsForMails = new Map<Id, MailFolder[]>()
|
||||
getLabelsForMails(mails: readonly Mail[]): ReadonlyMap<Id, ReadonlyArray<MailSet>> {
|
||||
const labelsForMails = new Map<Id, MailSet[]>()
|
||||
for (const mail of mails) {
|
||||
labelsForMails.set(getElementId(mail), this.getLabelsForMail(mail))
|
||||
}
|
||||
|
|
@ -316,7 +316,7 @@ export class MailModel {
|
|||
/**
|
||||
* @return labels that are currently applied to {@param mail}.
|
||||
*/
|
||||
getLabelsForMail(mail: Mail): MailFolder[] {
|
||||
getLabelsForMail(mail: Mail): MailSet[] {
|
||||
const groupLabels = this.getLabelsByGroupId(assertNotNull(mail._ownerGroup))
|
||||
return mail.sets.map((labelId) => groupLabels.get(elementIdPart(labelId))).filter(isNotNull)
|
||||
}
|
||||
|
|
@ -324,7 +324,7 @@ export class MailModel {
|
|||
private getMailSetsForGroup(groupId: Id): MailboxSets | null {
|
||||
const mailboxDetails = this.mailboxModel.mailboxDetails() || []
|
||||
const detail = mailboxDetails.find((md) => groupId === md.mailGroup._id)
|
||||
const sets = detail?.mailbox?.folders?._id
|
||||
const sets = detail?.mailbox?.folders._id
|
||||
if (sets == null) {
|
||||
return null
|
||||
}
|
||||
|
|
@ -349,7 +349,7 @@ export class MailModel {
|
|||
/**
|
||||
* Move mails from {@param targetFolder} except those that are in {@param excludeMailSet}.
|
||||
*/
|
||||
async moveMails(mails: readonly IdTuple[], targetFolder: MailFolder, moveMode: MoveMode): Promise<MovedMails[]> {
|
||||
async moveMails(mails: readonly IdTuple[], targetFolder: MailSet, moveMode: MoveMode): Promise<MovedMails[]> {
|
||||
const folderSystem = this.getFolderSystemByGroupId(assertNotNull(targetFolder._ownerGroup))
|
||||
if (folderSystem == null) {
|
||||
return []
|
||||
|
|
@ -372,7 +372,7 @@ export class MailModel {
|
|||
/**
|
||||
* Sends the given folder and all its descendants to the spam folder, reporting mails (if applicable) and removes any empty folders
|
||||
*/
|
||||
async sendFolderToSpam(folder: MailFolder): Promise<void> {
|
||||
async sendFolderToSpam(folder: MailSet): Promise<void> {
|
||||
const mailboxDetail = await this.getMailboxDetailsForMailFolder(folder)
|
||||
if (mailboxDetail == null) {
|
||||
return
|
||||
|
|
@ -419,7 +419,7 @@ export class MailModel {
|
|||
await this.mailFacade.markMails(mails, unread)
|
||||
}
|
||||
|
||||
async applyLabels(mails: readonly IdTuple[], addedLabels: readonly MailFolder[], removedLabels: readonly MailFolder[]): Promise<void> {
|
||||
async applyLabels(mails: readonly IdTuple[], addedLabels: readonly MailSet[], removedLabels: readonly MailSet[]): Promise<void> {
|
||||
const groupedByListIds = groupBy(mails, (mailId) => listIdPart(mailId))
|
||||
for (const [_, groupedMails] of groupedByListIds) {
|
||||
const mailChunks = splitInChunks(MAX_NBR_OF_MAILS_SYNC_OPERATION, groupedMails)
|
||||
|
|
@ -439,14 +439,14 @@ export class MailModel {
|
|||
this.mailboxCounters(normalized)
|
||||
}
|
||||
|
||||
_showNotification(folder: MailFolder, mail: Mail) {
|
||||
_showNotification(folder: MailSet, mail: Mail) {
|
||||
this.notifications.showNotification(NotificationType.Mail, lang.get("newMails_msg"), {}, (_) => {
|
||||
m.route.set(`/mail/${getElementId(folder)}/${getElementId(mail)}`)
|
||||
window.focus()
|
||||
})
|
||||
}
|
||||
|
||||
getCounterValue(folder: MailFolder): Promise<number | null> {
|
||||
getCounterValue(folder: MailSet): Promise<number | null> {
|
||||
return this.getMailboxDetailsForMailFolder(folder)
|
||||
.then((mailboxDetails) => {
|
||||
if (mailboxDetails == null) {
|
||||
|
|
@ -477,7 +477,7 @@ export class MailModel {
|
|||
/**
|
||||
* Sends the given folder and all its descendants to the trash folder, removes any empty folders
|
||||
*/
|
||||
async trashFolderAndSubfolders(folder: MailFolder): Promise<void> {
|
||||
async trashFolderAndSubfolders(folder: MailSet): Promise<void> {
|
||||
const mailboxDetail = await this.getMailboxDetailsForMailFolder(folder)
|
||||
if (mailboxDetail == null) {
|
||||
return
|
||||
|
|
@ -492,14 +492,14 @@ export class MailModel {
|
|||
}
|
||||
}
|
||||
|
||||
async setParentForFolder(folder: MailFolder, newParentId: IdTuple) {
|
||||
async setParentForFolder(folder: MailSet, newParentId: IdTuple) {
|
||||
return this.mailFacade.updateMailFolderParent(folder, newParentId)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when moving a folder to SPAM or TRASH, which do not allow empty folders (since only folders that contain mail are allowed)
|
||||
*/
|
||||
private async removeAllEmpty(folderSystem: FolderSystem, folder: MailFolder): Promise<boolean> {
|
||||
private async removeAllEmpty(folderSystem: FolderSystem, folder: MailSet): Promise<boolean> {
|
||||
// sort descendants deepest first so that we can clean them up before checking their ancestors
|
||||
const descendants = folderSystem.getDescendantFoldersOfParent(folder._id).sort((l, r) => r.level - l.level)
|
||||
|
||||
|
|
@ -531,11 +531,11 @@ export class MailModel {
|
|||
}
|
||||
|
||||
// Only load one mail, if there is even one we won't remove
|
||||
private async isEmptyFolder(descendant: MailFolder) {
|
||||
private async isEmptyFolder(descendant: MailSet) {
|
||||
return (await this.entityClient.loadRange(MailSetEntryTypeRef, descendant.entries, CUSTOM_MIN_ID, 1, false)).length === 0
|
||||
}
|
||||
|
||||
public async finallyDeleteCustomMailFolder(folder: MailFolder): Promise<void> {
|
||||
public async finallyDeleteCustomMailFolder(folder: MailSet): Promise<void> {
|
||||
if (folder.folderType !== MailSetKind.CUSTOM && folder.folderType !== MailSetKind.Imported) {
|
||||
throw new ProgrammingError("Cannot delete non-custom folder: " + String(folder._id))
|
||||
}
|
||||
|
|
@ -550,14 +550,14 @@ export class MailModel {
|
|||
)
|
||||
}
|
||||
|
||||
async fixupCounterForFolder(folder: MailFolder, unreadMails: number) {
|
||||
async fixupCounterForFolder(folder: MailSet, unreadMails: number) {
|
||||
const mailboxDetails = await this.getMailboxDetailsForMailFolder(folder)
|
||||
if (mailboxDetails) {
|
||||
await this.mailFacade.fixupCounterForFolder(mailboxDetails.mailGroup._id, folder, unreadMails)
|
||||
}
|
||||
}
|
||||
|
||||
async clearFolder(folder: MailFolder): Promise<void> {
|
||||
async clearFolder(folder: MailSet): Promise<void> {
|
||||
await this.mailFacade.clearFolder(folder._id)
|
||||
}
|
||||
|
||||
|
|
@ -573,21 +573,21 @@ export class MailModel {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a label (aka MailSet aka {@link MailFolder} of kind {@link MailSetKind.LABEL}) for the group {@param mailGroupId}.
|
||||
* Create a label (aka MailSet aka {@link MailSet} of kind {@link MailSetKind.LABEL}) for the group {@param mailGroupId}.
|
||||
*/
|
||||
async createLabel(mailGroupId: Id, labelData: { name: string; color: string }) {
|
||||
await this.mailFacade.createLabel(mailGroupId, labelData)
|
||||
}
|
||||
|
||||
async updateLabel(label: MailFolder, newData: { name: string; color: string }) {
|
||||
async updateLabel(label: MailSet, newData: { name: string; color: string }) {
|
||||
await this.mailFacade.updateLabel(label, newData.name, newData.color)
|
||||
}
|
||||
|
||||
async deleteLabel(label: MailFolder) {
|
||||
async deleteLabel(label: MailSet) {
|
||||
await this.mailFacade.deleteLabel(label)
|
||||
}
|
||||
|
||||
async getMailSetById(folderElementId: Id): Promise<MailFolder | null> {
|
||||
async getMailSetById(folderElementId: Id): Promise<MailSet | null> {
|
||||
const folderStructures = await this.loadMailSets()
|
||||
for (const folders of folderStructures.values()) {
|
||||
const folder = folders.folders.getFolderById(folderElementId)
|
||||
|
|
@ -603,7 +603,7 @@ export class MailModel {
|
|||
return null
|
||||
}
|
||||
|
||||
getImportedMailSets(): Array<MailFolder> {
|
||||
getImportedMailSets(): Array<MailSet> {
|
||||
return [...this.mailSets.values()].filter((f) => f.folders.importedMailSet).map((f) => f.folders.importedMailSet!)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Mail, MailFolder, MailSetEntry } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { Mail, MailSet, MailSetEntry } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { ListFilter } from "../../../common/misc/ListModel"
|
||||
import { ListLoadingState, ListState } from "../../../common/gui/base/List"
|
||||
import { EntityUpdateData } from "../../../common/api/common/utils/EntityUpdateUtils"
|
||||
|
|
@ -183,7 +183,7 @@ export interface MailSetListModel {
|
|||
* Get all labels for the mail.
|
||||
* @param mail
|
||||
*/
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailFolder>
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailSet>
|
||||
|
||||
/**
|
||||
* Load the entire list.
|
||||
|
|
@ -215,7 +215,7 @@ export interface MailSetListModel {
|
|||
export interface LoadedMail {
|
||||
readonly mail: Mail
|
||||
readonly mailSetEntryId: IdTuple
|
||||
readonly labels: ReadonlyArray<MailFolder>
|
||||
readonly labels: ReadonlyArray<MailSet>
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,7 +247,7 @@ export async function resolveMailSetEntries(
|
|||
}
|
||||
|
||||
// Resolve labels
|
||||
const labels: MailFolder[] = mailModel.getLabelsForMail(mail)
|
||||
const labels: MailSet[] = mailModel.getLabelsForMail(mail)
|
||||
loadedMails.push({ mailSetEntryId: mailSetEntry._id, mail, labels })
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ export async function provideAllMails(ids: IdTuple[], mailProvider: (listId: Id,
|
|||
*/
|
||||
export async function applyInboxRulesAndSpamPrediction(
|
||||
entries: LoadedMail[],
|
||||
sourceFolder: MailFolder,
|
||||
sourceFolder: MailSet,
|
||||
mailModel: MailModel,
|
||||
processInboxHandler: ProcessInboxHandler,
|
||||
sendServerRequest: boolean,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { FolderSystem, IndentedFolder } from "../../../common/api/common/mail/FolderSystem.js"
|
||||
import { Header, InboxRule, Mail, MailDetails, MailFolder, TutanotaProperties } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { Header, InboxRule, Mail, MailDetails, MailSet, TutanotaProperties } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { assertNotNull, first } from "@tutao/tutanota-utils"
|
||||
import { MailModel } from "./MailModel.js"
|
||||
import { lang } from "../../../common/misc/LanguageViewModel.js"
|
||||
import { MailSetKind, ReplyType, SYSTEM_FOLDERS, SystemFolderType } from "../../../common/api/common/TutanotaConstants.js"
|
||||
import { isSameId, sortCompareByReverseId } from "../../../common/api/common/utils/EntityUtils"
|
||||
|
||||
export type FolderInfo = { level: number; folder: MailFolder }
|
||||
export type FolderInfo = { level: number; folder: MailSet }
|
||||
|
||||
export const enum MoveService {
|
||||
RegularMove = "RegularMove",
|
||||
|
|
@ -27,7 +27,7 @@ export type MoveTargets = RegularMoveTargets | SimpleMoveTargets
|
|||
|
||||
export const MAX_FOLDER_INDENT_LEVEL = 10
|
||||
|
||||
export function getFolderName(folder: MailFolder): string {
|
||||
export function getFolderName(folder: MailSet): string {
|
||||
switch (folder.folderType) {
|
||||
case MailSetKind.CUSTOM:
|
||||
return folder.name
|
||||
|
|
@ -78,7 +78,7 @@ export async function getMoveTargetFolderSystems(foldersModel: MailModel, mails:
|
|||
if (firstMail == null) return regularMoveTargets([])
|
||||
|
||||
const mailboxDetails = await foldersModel.getMailboxDetailsForMail(firstMail)
|
||||
if (mailboxDetails == null || mailboxDetails.mailbox.folders == null) {
|
||||
if (mailboxDetails == null) {
|
||||
return regularMoveTargets([])
|
||||
}
|
||||
|
||||
|
|
@ -116,9 +116,9 @@ export async function getMoveTargetFolderSystems(foldersModel: MailModel, mails:
|
|||
}
|
||||
}
|
||||
|
||||
export async function getMoveTargetFolderSystemsForMailsInFolder(foldersModel: MailModel, currentFolder: MailFolder): Promise<Array<FolderInfo>> {
|
||||
export async function getMoveTargetFolderSystemsForMailsInFolder(foldersModel: MailModel, currentFolder: MailSet): Promise<Array<FolderInfo>> {
|
||||
const mailboxDetails = await foldersModel.getMailboxDetailsForMailFolder(currentFolder)
|
||||
if (mailboxDetails == null || mailboxDetails.mailbox.folders == null) {
|
||||
if (mailboxDetails == null) {
|
||||
return []
|
||||
}
|
||||
|
||||
|
|
@ -138,11 +138,11 @@ export async function getMoveTargetFolderSystemsForMailsInFolder(foldersModel: M
|
|||
*
|
||||
* Use with caution.
|
||||
*/
|
||||
export function assertSystemFolderOfType(system: FolderSystem, type: SystemFolderType): MailFolder {
|
||||
export function assertSystemFolderOfType(system: FolderSystem, type: SystemFolderType): MailSet {
|
||||
return assertNotNull(system.getSystemFolderByType(type), "System folder of type does not exist!")
|
||||
}
|
||||
|
||||
export function getPathToFolderString(folderSystem: FolderSystem, folder: MailFolder, omitLast = false) {
|
||||
export function getPathToFolderString(folderSystem: FolderSystem, folder: MailSet, omitLast = false) {
|
||||
const folderPath = folderSystem.getPathToFolder(folder._id)
|
||||
if (omitLast) {
|
||||
folderPath.pop()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { SpamClassificationHandler } from "./SpamClassificationHandler"
|
||||
import { InboxRuleHandler } from "./InboxRuleHandler"
|
||||
import { Mail, MailFolder, ProcessInboxDatum } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { Mail, MailSet, ProcessInboxDatum } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { FeatureType, MailSetKind } from "../../../common/api/common/TutanotaConstants"
|
||||
import { assertNotNull, debounce, isEmpty, Nullable } from "@tutao/tutanota-utils"
|
||||
import { MailFacade } from "../../../common/api/worker/facades/lazy/MailFacade"
|
||||
|
|
@ -47,11 +47,11 @@ export class ProcessInboxHandler {
|
|||
|
||||
public async handleIncomingMail(
|
||||
mail: Mail,
|
||||
sourceFolder: MailFolder,
|
||||
sourceFolder: MailSet,
|
||||
mailboxDetail: MailboxDetail,
|
||||
folderSystem: FolderSystem,
|
||||
sendServerRequest: boolean,
|
||||
): Promise<MailFolder> {
|
||||
): Promise<MailSet> {
|
||||
await this.logins.loadCustomizations()
|
||||
const isSpamClassificationFeatureEnabled = this.logins.isEnabled(FeatureType.SpamClientClassification)
|
||||
if (!mail.processNeeded) {
|
||||
|
|
@ -61,7 +61,7 @@ export class ProcessInboxHandler {
|
|||
const mailDetails = await this.mailFacade.loadMailDetailsBlob(mail)
|
||||
|
||||
let finalProcessInboxDatum: Nullable<UnencryptedProcessInboxDatum> = null
|
||||
let moveToFolder: MailFolder = sourceFolder
|
||||
let moveToFolder: MailSet = sourceFolder
|
||||
|
||||
if (sourceFolder.folderType === MailSetKind.INBOX || sourceFolder.folderType === MailSetKind.SPAM) {
|
||||
const result = await this.inboxRuleHandler()?.findAndApplyMatchingRule(mailboxDetail, mail)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Mail, MailDetails, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { Mail, MailDetails, MailSet } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { MailPhishingStatus, MailSetKind } from "../../../common/api/common/TutanotaConstants"
|
||||
import { SpamClassifier } from "../../workerUtils/spamClassification/SpamClassifier"
|
||||
import { assertNotNull } from "@tutao/tutanota-utils"
|
||||
|
|
@ -17,9 +17,9 @@ export class SpamClassificationHandler {
|
|||
public async predictSpamForNewMail(
|
||||
mail: Mail,
|
||||
mailDetails: MailDetails,
|
||||
sourceFolder: MailFolder,
|
||||
sourceFolder: MailSet,
|
||||
folderSystem: FolderSystem,
|
||||
): Promise<{ targetFolder: MailFolder; processInboxDatum: UnencryptedProcessInboxDatum }> {
|
||||
): Promise<{ targetFolder: MailSet; processInboxDatum: UnencryptedProcessInboxDatum }> {
|
||||
const spamMailDatum = createSpamMailDatum(mail, mailDetails)
|
||||
|
||||
const vectorizedMail = await this.spamClassifier.vectorize(spamMailDatum)
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ export class ConversationViewModel {
|
|||
private async isInTrash(mail: Mail) {
|
||||
const mailboxDetail = await this.mailModel.getMailboxDetailsForMail(mail)
|
||||
const mailFolder = this.mailModel.getMailFolderForMail(mail)
|
||||
if (mailFolder == null || mailboxDetail == null || mailboxDetail.mailbox.folders == null) {
|
||||
if (mailFolder == null || mailboxDetail == null) {
|
||||
return
|
||||
}
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Mail, MailFolder, MailSetEntryTypeRef, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { Mail, MailSet, MailSetEntryTypeRef, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { DropDownSelector, SelectorItemList } from "../../../common/gui/base/DropDownSelector.js"
|
||||
import m from "mithril"
|
||||
import { TextField } from "../../../common/gui/base/TextField.js"
|
||||
|
|
@ -11,7 +11,7 @@ import { MailReportType, MailSetKind } from "../../../common/api/common/Tutanota
|
|||
import { elementIdPart, isSameId, listIdPart } from "../../../common/api/common/utils/EntityUtils.js"
|
||||
import { reportMailsAutomatically } from "./MailReportDialog.js"
|
||||
import { isOfflineError } from "../../../common/api/common/utils/ErrorUtils.js"
|
||||
import { assertNotNull, groupByAndMap } from "@tutao/tutanota-utils"
|
||||
import { groupByAndMap } from "@tutao/tutanota-utils"
|
||||
import { mailLocator } from "../../mailLocator.js"
|
||||
import type { FolderSystem, IndentedFolder } from "../../../common/api/common/mail/FolderSystem.js"
|
||||
import { getFolderName, getIndentedFolderNameForDropdown, getPathToFolderString } from "../model/MailUtils.js"
|
||||
|
|
@ -21,12 +21,12 @@ import { isSpamOrTrashFolder } from "../model/MailChecks.js"
|
|||
* Dialog for Edit and Add folder are the same.
|
||||
* @param editedFolder if this is null, a folder is being added, otherwise a folder is being edited
|
||||
*/
|
||||
export async function showEditFolderDialog(mailBoxDetail: MailboxDetail, editedFolder: MailFolder | null = null, parentFolder: MailFolder | null = null) {
|
||||
export async function showEditFolderDialog(mailBoxDetail: MailboxDetail, editedFolder: MailSet | null = null, parentFolder: MailSet | null = null) {
|
||||
const noParentFolderOption = lang.get("comboBoxSelectionNone_msg")
|
||||
const mailGroupId = mailBoxDetail.mailGroup._id
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(assertNotNull(mailBoxDetail.mailbox.folders)._id)
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(mailBoxDetail.mailbox.folders._id)
|
||||
let folderNameValue = editedFolder?.name ?? ""
|
||||
let targetFolders: SelectorItemList<MailFolder | null> = folders
|
||||
let targetFolders: SelectorItemList<MailSet | null> = folders
|
||||
.getIndentedList(editedFolder)
|
||||
// filter: SPAM and TRASH and descendants are only shown if editing (folders can only be moved there, not created there)
|
||||
.filter((folderInfo: IndentedFolder) => !(editedFolder === null && isSpamOrTrashFolder(folders, folderInfo.folder)))
|
||||
|
|
@ -51,12 +51,12 @@ export async function showEditFolderDialog(mailBoxDetail: MailboxDetail, editedF
|
|||
items: targetFolders,
|
||||
selectedValue: selectedParentFolder,
|
||||
selectedValueDisplay: selectedParentFolder ? getFolderName(selectedParentFolder) : noParentFolderOption,
|
||||
selectionChangedHandler: (newFolder: MailFolder | null) => (selectedParentFolder = newFolder),
|
||||
selectionChangedHandler: (newFolder: MailSet | null) => (selectedParentFolder = newFolder),
|
||||
helpLabel: () => (selectedParentFolder ? getPathToFolderString(folders, selectedParentFolder) : ""),
|
||||
}),
|
||||
]
|
||||
|
||||
async function getMailIdsGroupedByListId(folder: MailFolder): Promise<Map<Id, Id[]>> {
|
||||
async function getMailIdsGroupedByListId(folder: MailSet): Promise<Map<Id, Id[]>> {
|
||||
const mailSetEntries = await locator.entityClient.loadAll(MailSetEntryTypeRef, folder.entries)
|
||||
return groupByAndMap(
|
||||
mailSetEntries,
|
||||
|
|
@ -65,7 +65,7 @@ export async function showEditFolderDialog(mailBoxDetail: MailboxDetail, editedF
|
|||
)
|
||||
}
|
||||
|
||||
async function loadAllMailsOfFolder(folder: MailFolder, reportableMails: Array<Mail>) {
|
||||
async function loadAllMailsOfFolder(folder: MailSet, reportableMails: Array<Mail>) {
|
||||
const mailIdsPerBag = await getMailIdsGroupedByListId(folder)
|
||||
for (const [mailListId, mailIds] of mailIdsPerBag) {
|
||||
reportableMails.push(...(await locator.entityClient.loadMultiple(MailTypeRef, mailListId, mailIds)))
|
||||
|
|
@ -132,19 +132,13 @@ export async function showEditFolderDialog(mailBoxDetail: MailboxDetail, editedF
|
|||
Dialog.showActionDialog({
|
||||
title: editedFolder ? "editFolder_action" : "addFolder_action",
|
||||
child: form,
|
||||
validator: () => checkFolderName(mailBoxDetail, folders, folderNameValue, mailGroupId, selectedParentFolder?._id ?? null),
|
||||
validator: () => checkFolderName(folders, folderNameValue, selectedParentFolder?._id ?? null),
|
||||
allowOkWithReturn: true,
|
||||
okAction: okAction,
|
||||
})
|
||||
}
|
||||
|
||||
function checkFolderName(
|
||||
mailboxDetail: MailboxDetail,
|
||||
folders: FolderSystem,
|
||||
name: string,
|
||||
mailGroupId: Id,
|
||||
parentFolderId: IdTuple | null,
|
||||
): TranslationKey | null {
|
||||
function checkFolderName(folders: FolderSystem, name: string, parentFolderId: IdTuple | null): TranslationKey | null {
|
||||
if (name.trim() === "") {
|
||||
return "folderNameNeutral_msg"
|
||||
} else if (folders.getCustomFoldersOfParent(parentFolderId).some((f) => f.name === name)) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Dialog } from "../../../common/gui/base/Dialog"
|
||||
import { TextField, TextFieldAttrs } from "../../../common/gui/base/TextField"
|
||||
import m from "mithril"
|
||||
import type { MailBox, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import type { MailBox, MailSet } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { isOfflineError } from "../../../common/api/common/utils/ErrorUtils"
|
||||
import { LockedError, PreconditionFailedError } from "../../../common/api/common/error/RestError"
|
||||
import { MailViewModel } from "./MailViewModel"
|
||||
|
|
@ -11,7 +11,7 @@ import { showNotAvailableForFreeDialog } from "../../../common/misc/Subscription
|
|||
|
||||
const LIMIT_EXCEEDED_ERROR = "limitReached"
|
||||
|
||||
export async function showEditLabelDialog(mailbox: MailBox | null, mailViewModel: MailViewModel, label: MailFolder | null) {
|
||||
export async function showEditLabelDialog(mailbox: MailBox | null, mailViewModel: MailViewModel, label: MailSet | null) {
|
||||
let name = label ? label.name : ""
|
||||
let color = label && label.color ? label.color : ""
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { modal, ModalComponent } from "../../../common/gui/base/Modal.js"
|
|||
import { focusNext, focusPrevious, Shortcut } from "../../../common/misc/KeyManager.js"
|
||||
import { BaseButton, BaseButtonAttrs } from "../../../common/gui/base/buttons/BaseButton.js"
|
||||
import { PosRect, showDropdown } from "../../../common/gui/base/Dropdown.js"
|
||||
import { MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { component_size, size } from "../../../common/gui/size.js"
|
||||
import { AllIcons, Icon, IconSize } from "../../../common/gui/base/Icon.js"
|
||||
import { Icons } from "../../../common/gui/base/icons/Icons.js"
|
||||
|
|
@ -27,9 +27,9 @@ export class LabelsPopup implements ModalComponent {
|
|||
private readonly sourceElement: HTMLElement,
|
||||
private readonly origin: PosRect,
|
||||
private readonly width: number,
|
||||
private readonly labelsForMails: ReadonlyMap<Id, ReadonlyArray<MailFolder>>,
|
||||
private readonly labels: { label: MailFolder; state: LabelState }[],
|
||||
private readonly onLabelsApplied: (addedLabels: MailFolder[], removedLabels: MailFolder[]) => unknown,
|
||||
private readonly labelsForMails: ReadonlyMap<Id, ReadonlyArray<MailSet>>,
|
||||
private readonly labels: { label: MailSet; state: LabelState }[],
|
||||
private readonly onLabelsApplied: (addedLabels: MailSet[], removedLabels: MailSet[]) => unknown,
|
||||
) {
|
||||
this.view = this.view.bind(this)
|
||||
this.oncreate = this.oncreate.bind(this)
|
||||
|
|
@ -97,7 +97,16 @@ export class LabelsPopup implements ModalComponent {
|
|||
opacity,
|
||||
},
|
||||
}),
|
||||
m(".button-height.flex.items-center.ml-12.overflow-hidden", { style: { color, opacity } }, m(".text-ellipsis", label.name)),
|
||||
m(
|
||||
".button-height.flex.items-center.ml-12.overflow-hidden",
|
||||
{
|
||||
style: {
|
||||
color,
|
||||
opacity,
|
||||
},
|
||||
},
|
||||
m(".text-ellipsis", label.name),
|
||||
),
|
||||
],
|
||||
)
|
||||
}),
|
||||
|
|
@ -161,9 +170,9 @@ export class LabelsPopup implements ModalComponent {
|
|||
return false
|
||||
}
|
||||
|
||||
private getSortedLabels(): Record<"addedLabels" | "removedLabels", MailFolder[]> {
|
||||
const removedLabels: MailFolder[] = []
|
||||
const addedLabels: MailFolder[] = []
|
||||
private getSortedLabels(): Record<"addedLabels" | "removedLabels", MailSet[]> {
|
||||
const removedLabels: MailSet[] = []
|
||||
const addedLabels: MailSet[] = []
|
||||
for (const { label, state } of this.labels) {
|
||||
if (state === LabelState.Applied) {
|
||||
addedLabels.push(label)
|
||||
|
|
@ -250,7 +259,7 @@ export class LabelsPopup implements ModalComponent {
|
|||
modal.displayUnique(this, false)
|
||||
}
|
||||
|
||||
private toggleLabel(labelState: { label: MailFolder; state: LabelState }) {
|
||||
private toggleLabel(labelState: { label: MailSet; state: LabelState }) {
|
||||
switch (labelState.state) {
|
||||
case LabelState.AppliedToSome:
|
||||
labelState.state = this.isMaxLabelsReached ? LabelState.NotApplied : LabelState.Applied
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Icon, IconSize } from "../../../common/gui/base/Icon.js"
|
|||
import { Icons } from "../../../common/gui/base/icons/Icons.js"
|
||||
import { client } from "../../../common/misc/ClientDetector.js"
|
||||
import { lang } from "../../../common/misc/LanguageViewModel.js"
|
||||
import { MailFolder } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { MailSet } from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
import { getFolderIcon } from "./MailGuiUtils"
|
||||
|
||||
export type MailFolderRowAttrs = {
|
||||
|
|
@ -19,7 +19,7 @@ export type MailFolderRowAttrs = {
|
|||
expanded: boolean | null
|
||||
indentationLevel: number
|
||||
onExpanderClick: (event: Event) => unknown
|
||||
folder: MailFolder
|
||||
folder: MailSet
|
||||
hasChildren: boolean
|
||||
onSelectedPath: boolean
|
||||
numberOfPreviousRows: number
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { isSelectedPrefix, NavButtonAttrs, NavButtonColor } from "../../../commo
|
|||
import { MAIL_PREFIX } from "../../../common/misc/RouteChange.js"
|
||||
import { MailFolderRow } from "./MailFolderRow.js"
|
||||
import { last, Thunk } from "@tutao/tutanota-utils"
|
||||
import { MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { attachDropdown, DropdownButtonAttrs } from "../../../common/gui/base/Dropdown.js"
|
||||
import { Icons } from "../../../common/gui/base/icons/Icons.js"
|
||||
import { ButtonColor } from "../../../common/gui/base/Button.js"
|
||||
|
|
@ -29,12 +29,12 @@ export interface MailFolderViewAttrs {
|
|||
mailModel: MailModel
|
||||
mailboxDetail: MailboxDetail
|
||||
mailFolderElementIdToSelectedMailId: ReadonlyMap<Id, Id>
|
||||
onFolderClick: (folder: MailFolder) => unknown
|
||||
onFolderDrop: (dropData: DropData, folder: MailFolder) => unknown
|
||||
onFolderClick: (folder: MailSet) => unknown
|
||||
onFolderDrop: (dropData: DropData, folder: MailSet) => unknown
|
||||
expandedFolders: ReadonlySet<Id>
|
||||
onFolderExpanded: (folder: MailFolder, state: boolean) => unknown
|
||||
onShowFolderAddEditDialog: (mailGroupId: Id, folder: MailFolder | null, parentFolder: MailFolder | null) => unknown
|
||||
onDeleteCustomMailFolder: (folder: MailFolder) => unknown
|
||||
onFolderExpanded: (folder: MailSet, state: boolean) => unknown
|
||||
onShowFolderAddEditDialog: (mailGroupId: Id, folder: MailSet | null, parentFolder: MailSet | null) => unknown
|
||||
onDeleteCustomMailFolder: (folder: MailSet) => unknown
|
||||
inEditMode: boolean
|
||||
onEditMailbox: () => unknown
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
groupCounters: Counters,
|
||||
folders: FolderSystem,
|
||||
attrs: MailFolderViewAttrs,
|
||||
path: MailFolder[],
|
||||
path: MailSet[],
|
||||
isInternalUser: boolean,
|
||||
indentationLevel: number = 0,
|
||||
): { children: Children[]; numRows: number } {
|
||||
|
|
@ -207,7 +207,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
* Get a full path to a folder with colons in between,
|
||||
* Used for data-testids
|
||||
*/
|
||||
private getPathToFolderAsString(folderSystem: FolderSystem, currentFolder: MailFolder): string {
|
||||
private getPathToFolderAsString(folderSystem: FolderSystem, currentFolder: MailSet): string {
|
||||
return folderSystem
|
||||
.getPathToFolder(currentFolder._id)
|
||||
.map((f) => getFolderName(f))
|
||||
|
|
@ -219,7 +219,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
return (counters[counterId] ?? 0) + system.children.reduce((acc, child) => acc + this.getTotalFolderCounter(counters, child), 0)
|
||||
}
|
||||
|
||||
private createFolderMoreButton(folder: MailFolder, folders: FolderSystem, attrs: MailFolderViewAttrs, onClose: Thunk): IconButtonAttrs {
|
||||
private createFolderMoreButton(folder: MailSet, folders: FolderSystem, attrs: MailFolderViewAttrs, onClose: Thunk): IconButtonAttrs {
|
||||
return attachDropdown({
|
||||
mainButtonAttrs: {
|
||||
title: "more_label",
|
||||
|
|
@ -250,7 +250,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
})
|
||||
}
|
||||
|
||||
private deleteButtonAttrs(attrs: MailFolderViewAttrs, folder: MailFolder): DropdownButtonAttrs {
|
||||
private deleteButtonAttrs(attrs: MailFolderViewAttrs, folder: MailSet): DropdownButtonAttrs {
|
||||
return {
|
||||
label: "delete_action",
|
||||
icon: Icons.Trash,
|
||||
|
|
@ -260,7 +260,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
}
|
||||
}
|
||||
|
||||
private addButtonAttrs(attrs: MailFolderViewAttrs, folder: MailFolder): DropdownButtonAttrs {
|
||||
private addButtonAttrs(attrs: MailFolderViewAttrs, folder: MailSet): DropdownButtonAttrs {
|
||||
return {
|
||||
label: "addFolder_action",
|
||||
icon: Icons.Add,
|
||||
|
|
@ -270,7 +270,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
}
|
||||
}
|
||||
|
||||
private editButtonAttrs(attrs: MailFolderViewAttrs, folders: FolderSystem, folder: MailFolder): DropdownButtonAttrs {
|
||||
private editButtonAttrs(attrs: MailFolderViewAttrs, folders: FolderSystem, folder: MailSet): DropdownButtonAttrs {
|
||||
return {
|
||||
label: "edit_action",
|
||||
icon: Icons.Edit,
|
||||
|
|
@ -284,7 +284,7 @@ export class MailFoldersView implements Component<MailFolderViewAttrs> {
|
|||
}
|
||||
}
|
||||
|
||||
private renderCreateFolderAddButton(parentFolder: MailFolder | null, attrs: MailFolderViewAttrs): Child {
|
||||
private renderCreateFolderAddButton(parentFolder: MailSet | null, attrs: MailFolderViewAttrs): Child {
|
||||
return m(IconButton, {
|
||||
title: "addFolder_action",
|
||||
click: () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { MailboxModel } from "../../../common/mailFunctionality/MailboxModel.js"
|
||||
import { File as TutanotaFile, Mail, MailFolder, MovedMails } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { File as TutanotaFile, Mail, MailSet, MovedMails } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { LockedError, PreconditionFailedError } from "../../../common/api/common/error/RestError"
|
||||
import { Dialog } from "../../../common/gui/base/Dialog"
|
||||
import { AllIcons } from "../../../common/gui/base/Icon"
|
||||
|
|
@ -85,7 +85,7 @@ interface MoveMailsParams {
|
|||
mailModel: MailModel
|
||||
undoModel: UndoModel
|
||||
mailIds: ReadonlyArray<IdTuple>
|
||||
targetFolder: MailFolder
|
||||
targetFolder: MailSet
|
||||
moveMode: MoveMode
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ export async function moveMailsToSystemFolder({
|
|||
mailModel: MailModel
|
||||
mailIds: ReadonlyArray<IdTuple>
|
||||
targetFolderType: SystemFolderType
|
||||
currentFolder: MailFolder
|
||||
currentFolder: MailSet
|
||||
moveMode: MoveMode
|
||||
undoModel: UndoModel
|
||||
}): Promise<boolean> {
|
||||
|
|
@ -349,7 +349,7 @@ export function getFolderIconByType(folderType: MailSetKind): AllIcons {
|
|||
}
|
||||
}
|
||||
|
||||
export function getFolderIcon(folder: MailFolder): AllIcons {
|
||||
export function getFolderIcon(folder: MailSet): AllIcons {
|
||||
return getFolderIconByType(getMailFolderType(folder))
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +503,7 @@ export async function showMoveMailsFromFolderDropdown(
|
|||
mailModel: MailModel,
|
||||
undoModel: UndoModel,
|
||||
origin: PosRect,
|
||||
currentFolder: MailFolder,
|
||||
currentFolder: MailSet,
|
||||
mails: LazyMailIdResolver,
|
||||
moveMode: MoveMode,
|
||||
opts?: ShowMoveMailsDropdownOpts,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { lang } from "../../../common/misc/LanguageViewModel"
|
|||
|
||||
import { Keys, MailSetKind, MailState, SystemFolderType } from "../../../common/api/common/TutanotaConstants"
|
||||
import type { Mail } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { component_size, size } from "../../../common/gui/size"
|
||||
import { component_size } from "../../../common/gui/size"
|
||||
import { styles } from "../../../common/gui/styles"
|
||||
import { Icon } from "../../../common/gui/base/Icon"
|
||||
import { Icons } from "../../../common/gui/base/icons/Icons"
|
||||
|
|
@ -406,10 +406,8 @@ export class MailListView implements Component<MailListViewAttrs> {
|
|||
const selectedFolder = this.mailViewModel.getFolder()
|
||||
if (selectedFolder) {
|
||||
const mailDetails = await this.mailViewModel.getMailboxDetails()
|
||||
if (mailDetails.mailbox.folders) {
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(mailDetails.mailbox.folders._id)
|
||||
return isOfTypeOrSubfolderOf(folders, selectedFolder, MailSetKind.ARCHIVE) || selectedFolder.folderType === MailSetKind.TRASH
|
||||
}
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(mailDetails.mailbox.folders._id)
|
||||
return isOfTypeOrSubfolderOf(folders, selectedFolder, MailSetKind.ARCHIVE) || selectedFolder.folderType === MailSetKind.TRASH
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { getMailFolderType, MailSetKind, MailState, ReplyType } from "../../../common/api/common/TutanotaConstants"
|
||||
import { FontIcons } from "../../../common/gui/base/icons/FontIcons"
|
||||
import type { Mail, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import type { Mail, MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { formatTimeOrDateOrYesterday } from "../../../common/misc/Formatter.js"
|
||||
import m, { Children } from "mithril"
|
||||
import Badge from "../../../common/gui/base/Badge"
|
||||
|
|
@ -74,7 +74,7 @@ export class MailRow implements VirtualRow<Mail> {
|
|||
|
||||
constructor(
|
||||
private readonly showFolderIcon: boolean,
|
||||
private readonly getLabelsForMail: (mail: Mail) => ReadonlyArray<MailFolder>,
|
||||
private readonly getLabelsForMail: (mail: Mail) => ReadonlyArray<MailSet>,
|
||||
private readonly onSelected: (mail: Mail, selected: boolean) => unknown,
|
||||
private readonly getHighlightedStrings?: () => readonly SearchToken[],
|
||||
) {
|
||||
|
|
@ -141,7 +141,7 @@ export class MailRow implements VirtualRow<Mail> {
|
|||
}
|
||||
}
|
||||
|
||||
private updateLabels(mail: Mail): readonly MailFolder[] {
|
||||
private updateLabels(mail: Mail): readonly MailSet[] {
|
||||
const labels = this.getLabelsForMail(mail)
|
||||
|
||||
for (const [i, element] of this.labelsDom.entries()) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { lang } from "../../../common/misc/LanguageViewModel"
|
|||
import { Dialog } from "../../../common/gui/base/Dialog"
|
||||
import { FeatureType, getMailFolderType, Keys, MailReportType, MailSetKind, SystemFolderType } from "../../../common/api/common/TutanotaConstants"
|
||||
import { AppHeaderAttrs, Header } from "../../../common/gui/Header.js"
|
||||
import { Mail, MailBox, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { Mail, MailBox, MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { assertNotNull, first, getFirstOrThrow, isEmpty, isNotEmpty, noOp, ofClass } from "@tutao/tutanota-utils"
|
||||
import { MailListView } from "./MailListView"
|
||||
import { assertMainOrNode, isApp } from "../../../common/api/common/Env"
|
||||
|
|
@ -1015,7 +1015,7 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
})
|
||||
}
|
||||
|
||||
private setExpandedState(folder: MailFolder, currentExpansionState: boolean) {
|
||||
private setExpandedState(folder: MailSet, currentExpansionState: boolean) {
|
||||
if (currentExpansionState) {
|
||||
this.expandedState.delete(getElementId(folder))
|
||||
} else {
|
||||
|
|
@ -1112,7 +1112,7 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
return []
|
||||
}
|
||||
|
||||
private async handleLabelMailDrop(dropData: MailDropData, targetLabel: MailFolder): Promise<void> {
|
||||
private async handleLabelMailDrop(dropData: MailDropData, targetLabel: MailSet): Promise<void> {
|
||||
const mailsToAddLabel = this.getDroppedMails(dropData)
|
||||
|
||||
if (!isEmpty(mailsToAddLabel)) {
|
||||
|
|
@ -1121,7 +1121,7 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
}
|
||||
}
|
||||
|
||||
private async handleFolderInFolderDrop(dropData: FolderDropData, targetFolder: MailFolder) {
|
||||
private async handleFolderInFolderDrop(dropData: FolderDropData, targetFolder: MailSet) {
|
||||
if (
|
||||
// dragging to Trash/Spam can be added at a later point
|
||||
targetFolder.folderType === MailSetKind.TRASH ||
|
||||
|
|
@ -1148,7 +1148,7 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
await mailLocator.mailModel.setParentForFolder(folderToMove, targetFolder._id)
|
||||
}
|
||||
|
||||
private async handleFolderMailDrop(dropData: MailDropData, targetFolder: MailFolder) {
|
||||
private async handleFolderMailDrop(dropData: MailDropData, targetFolder: MailSet) {
|
||||
const currentFolder = this.mailViewModel.getFolder()
|
||||
|
||||
if (!currentFolder) {
|
||||
|
|
@ -1171,7 +1171,7 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
}
|
||||
}
|
||||
|
||||
private async handeFolderFileDrop(dropData: FileDropData, mailboxDetail: MailboxDetail, mailFolder: MailFolder) {
|
||||
private async handeFolderFileDrop(dropData: FileDropData, mailboxDetail: MailboxDetail, mailFolder: MailSet) {
|
||||
function droppedOnlyMailFiles(files: Array<File>): boolean {
|
||||
// there's similar logic on the AttachmentBubble, but for natively shared files.
|
||||
return files.every((f) => f.name.endsWith(".eml") || f.name.endsWith(".mbox"))
|
||||
|
|
@ -1217,16 +1217,13 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
dialog?.show()
|
||||
}
|
||||
|
||||
private async deleteCustomMailFolder(mailboxDetail: MailboxDetail, folder: MailFolder): Promise<void> {
|
||||
private async deleteCustomMailFolder(mailboxDetail: MailboxDetail, folder: MailSet): Promise<void> {
|
||||
if (folder.folderType !== MailSetKind.CUSTOM) {
|
||||
throw new Error("Cannot delete non-custom folder: " + String(folder._id))
|
||||
}
|
||||
|
||||
// remove any selection to avoid that the next mail is loaded and selected for each deleted mail event
|
||||
this.mailViewModel?.listModel?.selectNone()
|
||||
if (mailboxDetail.mailbox.folders == null) {
|
||||
return
|
||||
}
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
|
||||
if (isSpamOrTrashFolder(folders, folder)) {
|
||||
|
|
@ -1286,7 +1283,7 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
}
|
||||
}
|
||||
|
||||
private async showFolderAddEditDialog(mailGroupId: Id, folder: MailFolder | null, parentFolder: MailFolder | null) {
|
||||
private async showFolderAddEditDialog(mailGroupId: Id, folder: MailSet | null, parentFolder: MailSet | null) {
|
||||
const mailboxDetail = await locator.mailboxModel.getMailboxDetailsForMailGroup(mailGroupId)
|
||||
await showEditFolderDialog(mailboxDetail, folder, parentFolder)
|
||||
}
|
||||
|
|
@ -1295,11 +1292,11 @@ export class MailView extends BaseTopLevelView implements TopLevelView<MailViewA
|
|||
await showEditLabelDialog(mailbox, this.mailViewModel, null)
|
||||
}
|
||||
|
||||
private async showLabelEditDialog(label: MailFolder) {
|
||||
private async showLabelEditDialog(label: MailSet) {
|
||||
await showEditLabelDialog(null, this.mailViewModel, label)
|
||||
}
|
||||
|
||||
private async showLabelDeleteDialog(label: MailFolder) {
|
||||
private async showLabelDeleteDialog(label: MailSet) {
|
||||
const confirmed = await Dialog.confirm(
|
||||
lang.getTranslation("confirmDeleteLabel_msg", {
|
||||
"{1}": label.name,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import {
|
|||
ImportMailStateTypeRef,
|
||||
Mail,
|
||||
MailBox,
|
||||
MailFolder,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetTypeRef,
|
||||
MailSetEntry,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
|
|
@ -61,7 +61,7 @@ export interface UndoAction {
|
|||
/** ViewModel for the overall mail view. */
|
||||
export class MailViewModel {
|
||||
/** Beware: this can be a label. */
|
||||
private _folder: MailFolder | null = null
|
||||
private _folder: MailSet | null = null
|
||||
private _listModel: MailSetListModel | null = null
|
||||
/** id of the mail requested to be displayed, independent of the list state. */
|
||||
private stickyMailId: IdTuple | null = null
|
||||
|
|
@ -85,6 +85,7 @@ export class MailViewModel {
|
|||
private currentShowTargetMarker: object = {}
|
||||
/* We only attempt counter fixup once after switching folders and loading the list fully. */
|
||||
private shouldAttemptCounterFixup: boolean = true
|
||||
|
||||
constructor(
|
||||
private readonly mailboxModel: MailboxModel,
|
||||
private readonly mailModel: MailModel,
|
||||
|
|
@ -168,7 +169,7 @@ export class MailViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
private async showMail(folder?: MailFolder | null, mailId?: Id) {
|
||||
private async showMail(folder?: MailSet | null, mailId?: Id) {
|
||||
// an optimization to not open an email that we already display
|
||||
if (
|
||||
folder != null &&
|
||||
|
|
@ -229,7 +230,7 @@ export class MailViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
private async selectFolderToUse(folderArgument: MailFolder | null): Promise<MailFolder> {
|
||||
private async selectFolderToUse(folderArgument: MailSet | null): Promise<MailSet> {
|
||||
if (folderArgument) {
|
||||
const mailboxDetail = await this.mailModel.getMailboxDetailsForMailFolder(folderArgument)
|
||||
if (mailboxDetail) {
|
||||
|
|
@ -306,7 +307,7 @@ export class MailViewModel {
|
|||
return changed
|
||||
}
|
||||
|
||||
private async loadAndSelectMail(folder: MailFolder, mailId: Id) {
|
||||
private async loadAndSelectMail(folder: MailSet, mailId: Id) {
|
||||
let pagesLoaded = 0
|
||||
const foundMail = await this.listModel?.loadAndSelect(
|
||||
mailId,
|
||||
|
|
@ -368,6 +369,7 @@ export class MailViewModel {
|
|||
|
||||
return await this.getResolvedMails(actionableMails)
|
||||
}
|
||||
|
||||
clearStickyMail() {
|
||||
if (this.stickyMailId) {
|
||||
this.stickyMailId = null
|
||||
|
|
@ -388,13 +390,14 @@ export class MailViewModel {
|
|||
return currentFolder != null && (currentFolder.folderType === MailSetKind.TRASH || currentFolder.folderType === MailSetKind.SPAM)
|
||||
}
|
||||
}
|
||||
|
||||
isExportingMailsAllowed(): boolean {
|
||||
return this.mailModel.isExportingMailsAllowed() && !client.isMobileDevice()
|
||||
}
|
||||
|
||||
private async getFolderForUserInbox(): Promise<MailFolder> {
|
||||
private async getFolderForUserInbox(): Promise<MailSet> {
|
||||
const mailboxDetail = await this.mailboxModel.getUserMailboxDetails()
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(assertNotNull(mailboxDetail.mailbox.folders)._id)
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
return assertSystemFolderOfType(folders, MailSetKind.INBOX)
|
||||
}
|
||||
|
||||
|
|
@ -439,19 +442,19 @@ export class MailViewModel {
|
|||
/**
|
||||
* Beware: this can return a label.
|
||||
*/
|
||||
getFolder(): MailFolder | null {
|
||||
getFolder(): MailSet | null {
|
||||
return this._folder
|
||||
}
|
||||
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailFolder> {
|
||||
getLabelsForMail(mail: Mail): ReadonlyArray<MailSet> {
|
||||
return this.listModel?.getLabelsForMail(mail) ?? []
|
||||
}
|
||||
|
||||
async applyLabelToMails(mails: readonly IdTuple[], label: MailFolder): Promise<void> {
|
||||
async applyLabelToMails(mails: readonly IdTuple[], label: MailSet): Promise<void> {
|
||||
await this.mailModel.applyLabels(mails, [label], [])
|
||||
}
|
||||
|
||||
private setListId(folder: MailFolder) {
|
||||
private setListId(folder: MailSet) {
|
||||
const oldFolderId = this._folder?._id
|
||||
// update the folder just in case, maybe it got updated
|
||||
this._folder = folder
|
||||
|
|
@ -513,9 +516,9 @@ export class MailViewModel {
|
|||
this.shouldAttemptCounterFixup = true
|
||||
}
|
||||
|
||||
private fixCounterIfNeeded: (folder: MailFolder, loadedMailsWhenCalled: ReadonlyArray<Mail>) => void = debounce(
|
||||
private fixCounterIfNeeded: (folder: MailSet, loadedMailsWhenCalled: ReadonlyArray<Mail>) => void = debounce(
|
||||
2000,
|
||||
async (folder: MailFolder, loadedMailsWhenCalled: ReadonlyArray<Mail>) => {
|
||||
async (folder: MailSet, loadedMailsWhenCalled: ReadonlyArray<Mail>) => {
|
||||
// If folders are changed, the list won't have the data we need.
|
||||
// Do not rely on counters if we are not connected.
|
||||
// We can't know the correct unreadMailCount if some unread mails are filtered out.
|
||||
|
|
@ -662,7 +665,7 @@ export class MailViewModel {
|
|||
|
||||
private async processImportedMails(update: EntityUpdateData<ImportMailState>) {
|
||||
const importMailState = await this.entityClient.load(ImportMailStateTypeRef, [update.instanceListId, update.instanceId])
|
||||
const importedFolder = await this.entityClient.load(MailFolderTypeRef, importMailState.targetFolder)
|
||||
const importedFolder = await this.entityClient.load(MailSetTypeRef, importMailState.targetFolder)
|
||||
|
||||
let status = parseInt(importMailState.status) as ImportStatus
|
||||
|
||||
|
|
@ -715,7 +718,7 @@ export class MailViewModel {
|
|||
if (this.currentShowTargetMarker !== state) {
|
||||
return
|
||||
}
|
||||
if (mailboxDetail == null || mailboxDetail.mailbox.folders == null) {
|
||||
if (mailboxDetail == null) {
|
||||
return
|
||||
}
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
|
|
@ -735,7 +738,7 @@ export class MailViewModel {
|
|||
if (!this._folder) return false
|
||||
const mailboxDetail = await this.mailModel.getMailboxDetailsForMailFolder(this._folder)
|
||||
const selectedFolder = this.getFolder()
|
||||
if (selectedFolder && mailboxDetail && mailboxDetail.mailbox.folders) {
|
||||
if (selectedFolder && mailboxDetail) {
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
return isOfTypeOrSubfolderOf(folders, selectedFolder, MailSetKind.DRAFT)
|
||||
} else {
|
||||
|
|
@ -747,7 +750,7 @@ export class MailViewModel {
|
|||
const folder = this.getFolder()
|
||||
if (folder) {
|
||||
const mailboxDetail = await this.mailModel.getMailboxDetailsForMailFolder(folder)
|
||||
if (folder && mailboxDetail && mailboxDetail.mailbox.folders) {
|
||||
if (folder && mailboxDetail) {
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
return isSpamOrTrashFolder(folders, folder)
|
||||
}
|
||||
|
|
@ -755,12 +758,12 @@ export class MailViewModel {
|
|||
return false
|
||||
}
|
||||
|
||||
private async mailboxDetailForListWithFallback(folder?: MailFolder | null) {
|
||||
private async mailboxDetailForListWithFallback(folder?: MailSet | null) {
|
||||
const mailboxDetailForListId = folder ? await this.mailModel.getMailboxDetailsForMailFolder(folder) : null
|
||||
return mailboxDetailForListId ?? (await this.mailboxModel.getUserMailboxDetails())
|
||||
}
|
||||
|
||||
async finallyDeleteAllMailsInSelectedFolder(folder: MailFolder): Promise<void> {
|
||||
async finallyDeleteAllMailsInSelectedFolder(folder: MailSet): Promise<void> {
|
||||
// remove any selection to avoid that the next mail is loaded and selected for each deleted mail event
|
||||
this.listModel?.selectNone()
|
||||
|
||||
|
|
@ -774,7 +777,7 @@ export class MailViewModel {
|
|||
}),
|
||||
)
|
||||
} else {
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(assertNotNull(mailboxDetail.mailbox.folders)._id)
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
if (isSubfolderOfType(folders, folder, MailSetKind.TRASH) || isSubfolderOfType(folders, folder, MailSetKind.SPAM)) {
|
||||
return this.mailModel.finallyDeleteCustomMailFolder(folder).catch(
|
||||
ofClass(PreconditionFailedError, () => {
|
||||
|
|
@ -843,11 +846,11 @@ export class MailViewModel {
|
|||
await this.mailModel.createLabel(assertNotNull(mailbox._ownerGroup), labelData)
|
||||
}
|
||||
|
||||
async editLabel(label: MailFolder, newData: { name: string; color: string }) {
|
||||
async editLabel(label: MailSet, newData: { name: string; color: string }) {
|
||||
await this.mailModel.updateLabel(label, newData)
|
||||
}
|
||||
|
||||
async deleteLabel(label: MailFolder) {
|
||||
async deleteLabel(label: MailSet) {
|
||||
await this.mailModel.deleteLabel(label)
|
||||
}
|
||||
|
||||
|
|
@ -855,11 +858,11 @@ export class MailViewModel {
|
|||
* Returns true if mails should be grouped by conversation in the mail list based on user preference and a folder
|
||||
* @param folder the folder to check or, by default, the current folder
|
||||
*/
|
||||
groupMailsByConversation(folder: MailFolder | null = this._folder) {
|
||||
groupMailsByConversation(folder: MailSet | null = this._folder) {
|
||||
return this.mailModel.canUseConversationView() && listByConversationInFolder(this.conversationPrefProvider, folder)
|
||||
}
|
||||
|
||||
getMoveMode(folder: MailFolder): MoveMode {
|
||||
getMoveMode(folder: MailSet): MoveMode {
|
||||
return this.groupMailsByConversation(folder) ? MoveMode.Conversation : MoveMode.Mails
|
||||
}
|
||||
}
|
||||
|
|
@ -867,7 +870,7 @@ export class MailViewModel {
|
|||
/**
|
||||
* @return true if mails should be grouped by conversation in the mail list based on user preference and a given {@param folder}
|
||||
*/
|
||||
export function listByConversationInFolder(conversationPrefProvider: ConversationPrefProvider, folder: MailFolder | null): boolean {
|
||||
export function listByConversationInFolder(conversationPrefProvider: ConversationPrefProvider, folder: MailSet | null): boolean {
|
||||
const onlySelectedMailInViewer = conversationPrefProvider.getConversationViewShowOnlySelectedMail()
|
||||
const prefersConversationInList = !onlySelectedMailInViewer && conversationPrefProvider.getMailListDisplayMode() === MailListDisplayMode.CONVERSATIONS
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
Mail,
|
||||
MailAddress,
|
||||
MailDetails,
|
||||
MailFolder,
|
||||
MailSet,
|
||||
MailTypeRef,
|
||||
} from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import {
|
||||
|
|
@ -231,7 +231,7 @@ export class MailViewerViewModel {
|
|||
|
||||
if (folder) {
|
||||
this.mailModel.getMailboxDetailsForMail(this.mail).then(async (mailboxDetails) => {
|
||||
if (mailboxDetails == null || mailboxDetails.mailbox.folders == null) {
|
||||
if (mailboxDetails == null) {
|
||||
return
|
||||
}
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetails.mailbox.folders._id)
|
||||
|
|
@ -563,7 +563,7 @@ export class MailViewerViewModel {
|
|||
try {
|
||||
const mailboxDetail = await this.mailModel.getMailboxDetailsForMail(this.mail)
|
||||
// We should always have a mailbox, the check above throws due AssertNotNull in response.
|
||||
if (mailboxDetail == null || mailboxDetail.mailbox.folders == null) {
|
||||
if (mailboxDetail == null) {
|
||||
return
|
||||
}
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
|
|
@ -682,6 +682,7 @@ export class MailViewerViewModel {
|
|||
return encodedText
|
||||
})
|
||||
}
|
||||
|
||||
async determineUnsubscribeOrder(): Promise<Array<UnsubscribeAction>> {
|
||||
const mailHeaders = await this.getHeaders()
|
||||
const unsubscribeActions: Array<UnsubscribeAction> = []
|
||||
|
|
@ -1268,7 +1269,7 @@ export class MailViewerViewModel {
|
|||
this.collapsed = true
|
||||
}
|
||||
|
||||
getLabels(): readonly MailFolder[] {
|
||||
getLabels(): readonly MailSet[] {
|
||||
return this.mailModel.getLabelsForMail(this.mail).sort((labelA, labelB) => labelA.name.localeCompare(labelB.name))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export class OpenMailboxHandler {
|
|||
if (this.logins.isUserLoggedIn() && this.logins.getUserController().user._id === userId) {
|
||||
if (!requestedPath) {
|
||||
const [mailboxDetail] = await this.mailboxModel.getMailboxDetails()
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(assertNotNull(mailboxDetail.mailbox.folders)._id)
|
||||
const folders = await this.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
const inbox = assertSystemFolderOfType(folders, MailSetKind.INBOX)
|
||||
m.route.set("/mail/" + getElementId(inbox))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { List, ListAttrs, MultiselectMode, RenderConfig } from "../../../common/
|
|||
import { component_size, size } from "../../../common/gui/size.js"
|
||||
import { KindaContactRow } from "../../contacts/view/ContactListView.js"
|
||||
import { SearchableTypes } from "./SearchViewModel.js"
|
||||
import { CalendarEvent, CalendarEventTypeRef, Contact, ContactTypeRef, Mail, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { CalendarEvent, CalendarEventTypeRef, Contact, ContactTypeRef, Mail, MailSet } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import ColumnEmptyMessageBox from "../../../common/gui/base/ColumnEmptyMessageBox.js"
|
||||
import { BootIcons } from "../../../common/gui/base/icons/BootIcons.js"
|
||||
import { theme } from "../../../common/gui/theme.js"
|
||||
|
|
@ -36,7 +36,7 @@ export interface SearchListViewAttrs {
|
|||
currentType: TypeRef<Mail | Contact | CalendarEvent>
|
||||
isFreeAccount: boolean
|
||||
cancelCallback: () => unknown | null
|
||||
getLabelsForMail: (mail: Mail) => MailFolder[]
|
||||
getLabelsForMail: (mail: Mail) => MailSet[]
|
||||
highlightedStrings: readonly SearchToken[]
|
||||
availableCalendars: ReadonlyArray<CalendarInfoBase>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { ListElementListModel } from "../../../common/misc/ListElementListModel.
|
|||
import { SearchResultListEntry } from "./SearchListView.js"
|
||||
import { SearchRestriction, SearchResult } from "../../../common/api/worker/search/SearchTypes.js"
|
||||
import { EntityEventsListener, EventController } from "../../../common/api/main/EventController.js"
|
||||
import { CalendarEvent, CalendarEventTypeRef, Contact, ContactTypeRef, Mail, MailFolder, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { CalendarEvent, CalendarEventTypeRef, Contact, ContactTypeRef, Mail, MailSet, MailTypeRef } from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import { ListElementEntity } from "../../../common/api/common/EntityTypes.js"
|
||||
import { FULL_INDEXED_TIMESTAMP, MailSetKind, NOTHING_INDEXED_TIMESTAMP, OperationType } from "../../../common/api/common/TutanotaConstants.js"
|
||||
import {
|
||||
|
|
@ -1078,7 +1078,7 @@ export class SearchViewModel {
|
|||
this.eventController.removeEntityListener(this.entityEventsListener)
|
||||
}
|
||||
|
||||
getLabelsForMail(mail: Mail): MailFolder[] {
|
||||
getLabelsForMail(mail: Mail): MailSet[] {
|
||||
return mailLocator.mailModel.getLabelsForMail(mail)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export type InboxRuleTemplate = Pick<InboxRule, "type" | "value"> & {
|
|||
export async function show(mailBoxDetail: MailboxDetail, ruleOrTemplate: InboxRuleTemplate) {
|
||||
if (locator.logins.getUserController().isFreeAccount()) {
|
||||
showNotAvailableForFreeDialog()
|
||||
} else if (mailBoxDetail && mailBoxDetail.mailbox.folders) {
|
||||
} else if (mailBoxDetail) {
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(mailBoxDetail.mailbox.folders._id)
|
||||
let targetFolders = folders.getIndentedList().map((folderInfo: IndentedFolder) => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { AvailablePlanType, HighestTierPlans, ImportStatus, MailSetKind } from "
|
|||
import { IndentedFolder } from "../../common/api/common/mail/FolderSystem"
|
||||
import { lang, TranslationKey } from "../../common/misc/LanguageViewModel"
|
||||
import { MailImporter, UiImportStatus } from "../mail/import/MailImporter.js"
|
||||
import { MailFolder } from "../../common/api/entities/tutanota/TypeRefs"
|
||||
import { MailSet } from "../../common/api/entities/tutanota/TypeRefs"
|
||||
import { elementIdPart, generatedIdToTimestamp, isSameId, sortCompareByReverseId } from "../../common/api/common/utils/EntityUtils"
|
||||
import { Icons } from "../../common/gui/base/icons/Icons.js"
|
||||
import { DropDownSelector, SelectorItemList } from "../../common/gui/base/DropDownSelector.js"
|
||||
|
|
@ -85,7 +85,7 @@ export class DesktopMailImportSettingsViewer implements UpdatableSettingsViewer
|
|||
// but at least we won't block inbox ( incoming new mails )
|
||||
const selectableFolders = folders.getIndentedList().filter((folderInfo) => folderInfo.folder.folderType !== MailSetKind.INBOX)
|
||||
|
||||
let targetFolders: SelectorItemList<MailFolder | null> = selectableFolders.map((folderInfo: IndentedFolder) => {
|
||||
let targetFolders: SelectorItemList<MailSet | null> = selectableFolders.map((folderInfo: IndentedFolder) => {
|
||||
return {
|
||||
name: getIndentedFolderNameForDropdown(folderInfo),
|
||||
value: folderInfo.folder,
|
||||
|
|
@ -97,7 +97,7 @@ export class DesktopMailImportSettingsViewer implements UpdatableSettingsViewer
|
|||
disabled: this.mailImporter().shouldRenderImportStatus(),
|
||||
selectedValue: selectedTargetFolder,
|
||||
selectedValueDisplay: selectedTargetFolder ? getFolderName(selectedTargetFolder) : loadingMsg,
|
||||
selectionChangedHandler: (newFolder: MailFolder | null) => (this.mailImporter().selectedTargetFolder = newFolder),
|
||||
selectionChangedHandler: (newFolder: MailSet | null) => (this.mailImporter().selectedTargetFolder = newFolder),
|
||||
helpLabel: () => helpLabel,
|
||||
})
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { lang, type MaybeTranslation } from "../../common/misc/LanguageViewModel
|
|||
import type { MailboxGroupRoot, MailboxProperties, OutOfOfficeNotification, TutanotaProperties } from "../../common/api/entities/tutanota/TypeRefs.js"
|
||||
import {
|
||||
MailboxPropertiesTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
OutOfOfficeNotificationTypeRef,
|
||||
TutanotaPropertiesTypeRef,
|
||||
} from "../../common/api/entities/tutanota/TypeRefs.js"
|
||||
|
|
@ -517,7 +517,7 @@ export class MailSettingsViewer implements UpdatableSettingsViewer {
|
|||
}
|
||||
|
||||
private async getTextForTarget(mailboxDetail: MailboxDetail, targetFolderId: IdTuple): Promise<string> {
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(assertNotNull(mailboxDetail.mailbox.folders)._id)
|
||||
const folders = await mailLocator.mailModel.getMailboxFoldersForId(mailboxDetail.mailbox.folders._id)
|
||||
let folder = folders.getFolderById(elementIdPart(targetFolderId))
|
||||
|
||||
if (folder) {
|
||||
|
|
@ -534,7 +534,7 @@ export class MailSettingsViewer implements UpdatableSettingsViewer {
|
|||
const props = await mailLocator.entityClient.load(TutanotaPropertiesTypeRef, mailLocator.logins.getUserController().props._id)
|
||||
this._updateTutanotaPropertiesSettings(props)
|
||||
this._updateInboxRules(props)
|
||||
} else if (isUpdateForTypeRef(MailFolderTypeRef, update)) {
|
||||
} else if (isUpdateForTypeRef(MailSetTypeRef, update)) {
|
||||
this._updateInboxRules(mailLocator.logins.getUserController().props)
|
||||
} else if (isUpdateForTypeRef(OutOfOfficeNotificationTypeRef, update)) {
|
||||
this._outOfOfficeNotification.reload().then(() => this._updateOutOfOfficeNotification())
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
MailDetails,
|
||||
MailDetailsBlobTypeRef,
|
||||
MailDetailsDraftTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailSetEntry,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
|
|
@ -517,7 +517,7 @@ export class MailIndexer {
|
|||
* Provides all mail set list ids of the given mailbox
|
||||
*/
|
||||
private async loadMailFolderListIds(mailbox: MailBox): Promise<Id[]> {
|
||||
const mailSets = await this.entityClient.loadAll(MailFolderTypeRef, assertNotNull(mailbox.folders).folders)
|
||||
const mailSets = await this.entityClient.loadAll(MailSetTypeRef, mailbox.folders.folders)
|
||||
return mailSets.filter(isFolder).map((set) => set.entries)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
MailBoxTypeRef,
|
||||
MailDetailsBlobTypeRef,
|
||||
MailDetailsDraftTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
} from "../../../common/api/entities/tutanota/TypeRefs.js"
|
||||
|
|
@ -40,7 +40,7 @@ export class MailOfflineCleaner implements OfflineStorageCleaner {
|
|||
const mailBoxes = await offlineStorage.getElementsOfType(MailBoxTypeRef)
|
||||
for (const mailBox of mailBoxes) {
|
||||
const currentMailBag = assertNotNull(mailBox.currentMailBag)
|
||||
const folders = await offlineStorage.getWholeList(MailFolderTypeRef, mailBox.folders!.folders)
|
||||
const folders = await offlineStorage.getWholeList(MailSetTypeRef, mailBox.folders.folders)
|
||||
// Deleting MailSetEntries first to make sure that once we start deleting Mail
|
||||
// we don't have any MailSetEntries that reference that Mail anymore.
|
||||
for (const mailSet of folders) {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import {
|
|||
MailBox,
|
||||
MailboxGroupRootTypeRef,
|
||||
MailBoxTypeRef,
|
||||
MailFolder,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetTypeRef,
|
||||
MailTypeRef,
|
||||
PopulateClientSpamTrainingDatum,
|
||||
} from "../../../common/api/entities/tutanota/TypeRefs"
|
||||
|
|
@ -47,11 +47,7 @@ export class SpamClassifierDataDealer {
|
|||
public async fetchAllTrainingData(ownerGroup: Id): Promise<TrainingDataset> {
|
||||
const mailboxGroupRoot = await this.entityClient.load(MailboxGroupRootTypeRef, ownerGroup)
|
||||
const mailbox = await this.entityClient.load(MailBoxTypeRef, mailboxGroupRoot.mailbox)
|
||||
const mailSets = await this.entityClient.loadAll(MailFolderTypeRef, assertNotNull(mailbox.folders).folders)
|
||||
|
||||
if (mailbox.clientSpamTrainingData == null || mailbox.modifiedClientSpamTrainingDataIndex == null) {
|
||||
return { trainingData: [], lastTrainingDataIndexId: GENERATED_MIN_ID, hamCount: 0, spamCount: 0 }
|
||||
}
|
||||
const mailSets = await this.entityClient.loadAll(MailSetTypeRef, mailbox.folders.folders)
|
||||
|
||||
// clientSpamTrainingData is NOT cached
|
||||
let clientSpamTrainingData = await this.entityClient.loadAll(ClientSpamTrainingDatumTypeRef, mailbox.clientSpamTrainingData)
|
||||
|
|
@ -102,9 +98,6 @@ export class SpamClassifierDataDealer {
|
|||
const mailbox = await this.entityClient.load(MailBoxTypeRef, mailboxGroupRoot.mailbox)
|
||||
|
||||
const emptyResult = { trainingData: [], lastTrainingDataIndexId: indexStartId, hamCount: 0, spamCount: 0 }
|
||||
if (mailbox.clientSpamTrainingData == null || mailbox.modifiedClientSpamTrainingDataIndex == null) {
|
||||
return emptyResult
|
||||
}
|
||||
|
||||
const modifiedClientSpamTrainingDataIndicesSinceStart = await this.entityClient.loadRange(
|
||||
ClientSpamTrainingDatumIndexEntryTypeRef,
|
||||
|
|
@ -181,7 +174,7 @@ export class SpamClassifierDataDealer {
|
|||
}
|
||||
|
||||
// Visible for testing
|
||||
async fetchMailsByMailbagAfterDate(mailbag: MailBag, mailSets: MailFolder[], startDate: Date): Promise<Array<Mail>> {
|
||||
async fetchMailsByMailbagAfterDate(mailbag: MailBag, mailSets: MailSet[], startDate: Date): Promise<Array<Mail>> {
|
||||
const mails = await this.entityClient.loadAll(MailTypeRef, mailbag.mails, timestampToGeneratedId(startDate.getTime()))
|
||||
const trashFolder = assertNotNull(mailSets.find((set) => getMailSetKind(set) === MailSetKind.TRASH))
|
||||
return mails.filter((mail) => {
|
||||
|
|
@ -190,7 +183,7 @@ export class SpamClassifierDataDealer {
|
|||
})
|
||||
}
|
||||
|
||||
private async fetchMailsForMailbox(mailbox: MailBox, mailSets: MailFolder[]): Promise<Array<Mail>> {
|
||||
private async fetchMailsForMailbox(mailbox: MailBox, mailSets: MailSet[]): Promise<Array<Mail>> {
|
||||
const downloadedMailClassificationData = new Array<Mail>()
|
||||
|
||||
const { LocalTimeDateProvider } = await import("../../../common/api/worker/DateProvider")
|
||||
|
|
@ -210,12 +203,7 @@ export class SpamClassifierDataDealer {
|
|||
return downloadedMailClassificationData
|
||||
}
|
||||
|
||||
private async uploadTrainingDataForMails(mails: MailWithMailDetails[], mailBox: MailBox, mailSets: MailFolder[]): Promise<void> {
|
||||
const clientSpamTrainingDataListId = mailBox.clientSpamTrainingData
|
||||
if (clientSpamTrainingDataListId == null) {
|
||||
return
|
||||
}
|
||||
|
||||
private async uploadTrainingDataForMails(mails: MailWithMailDetails[], mailBox: MailBox, mailSets: MailSet[]): Promise<void> {
|
||||
const unencryptedPopulateClientSpamTrainingData: UnencryptedPopulateClientSpamTrainingDatum[] = await promiseMap(
|
||||
mails,
|
||||
async (mailWithDetail) => {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
import o from "@tutao/otest"
|
||||
import { GroupType } from "../../src/common/api/common/TutanotaConstants.js"
|
||||
import type { MailFolder } from "../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
import type { MailSet } from "../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
import {
|
||||
ContactAddressTypeRef,
|
||||
ContactListTypeRef,
|
||||
ContactTypeRef,
|
||||
MailBoxTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailSetEntryTypeRef,
|
||||
} from "../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
import { neverNull } from "@tutao/tutanota-utils"
|
||||
import { initLocator, locator } from "../../src/mail-app/workerUtils/worker/WorkerLocator.js"
|
||||
import { browserDataStub, createTestEntity } from "./TestUtils.js"
|
||||
import { SessionType } from "../../src/common/api/common/SessionType.js"
|
||||
|
||||
function loadFolders(folderListId: Id): Promise<MailFolder[]> {
|
||||
return locator.cachingEntityClient.loadAll(MailFolderTypeRef, folderListId)
|
||||
function loadFolders(folderListId: Id): Promise<MailSet[]> {
|
||||
return locator.cachingEntityClient.loadAll(MailSetTypeRef, folderListId)
|
||||
}
|
||||
|
||||
function loadMailboxSystemFolders(): Promise<MailFolder[]> {
|
||||
function loadMailboxSystemFolders(): Promise<MailSet[]> {
|
||||
return locator.cachingEntityClient.loadRoot(MailBoxTypeRef, locator.user.getUserGroupId()).then((mailbox) => {
|
||||
return loadFolders(neverNull(mailbox.folders).folders)
|
||||
return loadFolders(mailbox.folders.folders)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ import {
|
|||
MailDetailsBlob,
|
||||
MailDetailsBlobTypeRef,
|
||||
MailDetailsTypeRef,
|
||||
MailFolder,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetTypeRef,
|
||||
MailSetEntry,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
|
|
@ -933,16 +933,16 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
)
|
||||
await storage.put(MailBoxTypeRef, storableMailBox)
|
||||
const storableSpamFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const storableSpamFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", spamFolderId],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
entries: spamFolderEntriesId,
|
||||
folderType: MailSetKind.SPAM,
|
||||
})
|
||||
await storage.put(MailFolderTypeRef, await toStorableInstance(storableSpamFolder))
|
||||
await storage.put(MailSetTypeRef, await toStorableInstance(storableSpamFolder))
|
||||
const storableTrashFolder = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", trashFolderId],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -950,7 +950,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
folderType: MailSetKind.TRASH,
|
||||
}),
|
||||
)
|
||||
await storage.put(MailFolderTypeRef, storableTrashFolder)
|
||||
await storage.put(MailSetTypeRef, storableTrashFolder)
|
||||
})
|
||||
|
||||
o.test("ranges before timeRangeDays will be deleted", async function () {
|
||||
|
|
@ -963,14 +963,14 @@ o.spec("OfflineStorageDb", function () {
|
|||
const mailDetailsBlobId: IdTuple = ["mailDetailsList", "mailDetailsBlobId"]
|
||||
|
||||
const storableMailFolder = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "mailFolderId"],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
entries: listIdPart(mailSetEntryId),
|
||||
}),
|
||||
)
|
||||
await storage.put(MailFolderTypeRef, storableMailFolder)
|
||||
await storage.put(MailSetTypeRef, storableMailFolder)
|
||||
const storableEntry = await toStorableInstance(
|
||||
createTestEntity(MailSetEntryTypeRef, {
|
||||
_id: mailSetEntryId,
|
||||
|
|
@ -1035,7 +1035,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
const lowerMailSetEntryIdForRange = offsetMailSetEntryId(twoDaysBeforeTimeRangeDays, GENERATED_MIN_ID)
|
||||
const upperMailSetEntryIdForRange = offsetMailSetEntryId(twoDaysAfterTimeRangeDays, GENERATED_MAX_ID)
|
||||
const storableInbox = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "mailFolderId"],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1043,7 +1043,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
folderType: MailSetKind.INBOX,
|
||||
}),
|
||||
)
|
||||
await storage.put(MailFolderTypeRef, storableInbox)
|
||||
await storage.put(MailSetTypeRef, storableInbox)
|
||||
|
||||
await storage.setNewRangeForList(MailSetEntryTypeRef, entriesListId, lowerMailSetEntryIdForRange, upperMailSetEntryIdForRange)
|
||||
|
||||
|
|
@ -1068,7 +1068,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
const lowerMailSetEntryIdForRange = offsetMailSetEntryId(oneDayAfterTimeRangeDays, GENERATED_MIN_ID)
|
||||
const upperMailSetEntryIdForRange = offsetMailSetEntryId(twoDaysAfterTimeRangeDays, GENERATED_MAX_ID)
|
||||
const storableCustomFolder = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "mailFolderId"],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1076,7 +1076,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
folderType: MailSetKind.CUSTOM,
|
||||
}),
|
||||
)
|
||||
await storage.put(MailFolderTypeRef, storableCustomFolder)
|
||||
await storage.put(MailSetTypeRef, storableCustomFolder)
|
||||
await storage.setNewRangeForList(MailSetEntryTypeRef, entriesListId, lowerMailSetEntryIdForRange, upperMailSetEntryIdForRange)
|
||||
|
||||
// Here we clear the excluded data
|
||||
|
|
@ -1123,7 +1123,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
)
|
||||
const mailFolder = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "folderId"],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1131,7 +1131,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
)
|
||||
|
||||
await storage.put(MailFolderTypeRef, mailFolder)
|
||||
await storage.put(MailSetTypeRef, mailFolder)
|
||||
await storage.put(MailTypeRef, mail)
|
||||
const storableSetEntry = await toStorableInstance(
|
||||
createTestEntity(MailSetEntryTypeRef, {
|
||||
|
|
@ -1168,7 +1168,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
upper: ensureBase64Ext(mailSetEntryTypeModel, upperMailSetEntryIdForRange),
|
||||
})
|
||||
|
||||
const allFolderIds = await getAllIdsForType(MailFolderTypeRef)
|
||||
const allFolderIds = await getAllIdsForType(MailSetTypeRef)
|
||||
o.check(allFolderIds).deepEquals(["folderId", spamFolderId, trashFolderId])
|
||||
const allMailIds = await getAllIdsForType(MailTypeRef)
|
||||
o.check(allMailIds).deepEquals([elementIdPart(mailId)])
|
||||
|
|
@ -1208,7 +1208,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
)
|
||||
const mailFolder = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "folderId"],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1223,7 +1223,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
mail: mailId,
|
||||
}),
|
||||
)
|
||||
await storage.put(MailFolderTypeRef, mailFolder)
|
||||
await storage.put(MailSetTypeRef, mailFolder)
|
||||
await storage.put(MailTypeRef, mail)
|
||||
await storage.put(MailSetEntryTypeRef, storableMailSetEntry)
|
||||
const storableDetails = await toStorableInstance(
|
||||
|
|
@ -1252,7 +1252,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
upper: ensureBase64Ext(mailSetEntryTypeModel, upperMailSetEntryIdForRange),
|
||||
})
|
||||
|
||||
const allFolderIds = await getAllIdsForType(MailFolderTypeRef)
|
||||
const allFolderIds = await getAllIdsForType(MailSetTypeRef)
|
||||
o.check(allFolderIds).deepEquals(["folderId", spamFolderId, trashFolderId])
|
||||
const allMailIds = await getAllIdsForType(MailTypeRef)
|
||||
o.check(allMailIds).deepEquals([])
|
||||
|
|
@ -1336,7 +1336,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
const trashSubfolderMailSetEntryId: IdTuple = [trashSubfolderEntriesId, trashSubfolderMailSetEntryElementId]
|
||||
|
||||
const storableCustomFolder = await toStorableInstance(
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", trashSubfolderId],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1345,7 +1345,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
folderType: MailSetKind.CUSTOM,
|
||||
}),
|
||||
)
|
||||
await storage.put(MailFolderTypeRef, storableCustomFolder)
|
||||
await storage.put(MailSetTypeRef, storableCustomFolder)
|
||||
|
||||
const storableSpamMailSetEntry = await toStorableInstance(
|
||||
createTestEntity(MailSetEntryTypeRef, {
|
||||
|
|
@ -1455,7 +1455,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
ensureBase64Ext(detailsBlobTypeModel, elementIdPart(trashSubfolderDetailsId)),
|
||||
])
|
||||
|
||||
o.check(await getAllIdsForType(MailFolderTypeRef)).deepEquals([spamFolderId, trashFolderId, trashSubfolderId])
|
||||
o.check(await getAllIdsForType(MailSetTypeRef)).deepEquals([spamFolderId, trashFolderId, trashSubfolderId])
|
||||
const count = await dbFacade.get("SELECT COUNT(*) FROM list_entities", [])
|
||||
o.check(untagSqlObject(assertNotNull(count))["COUNT(*)"]).equals(9)
|
||||
})
|
||||
|
|
@ -1532,14 +1532,14 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
})
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", inboxFolderId],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
folderType: MailSetKind.INBOX,
|
||||
entries: inboxFolderEntriesId,
|
||||
})
|
||||
await storage.put(MailFolderTypeRef, await toStorableInstance(inboxFolder))
|
||||
await storage.put(MailSetTypeRef, await toStorableInstance(inboxFolder))
|
||||
await storage.put(MailTypeRef, await toStorableInstance(mailBefore))
|
||||
await storage.put(MailTypeRef, await toStorableInstance(mailAfter))
|
||||
await storage.put(MailSetEntryTypeRef, await toStorableInstance(mailSetEntryBefore))
|
||||
|
|
@ -1551,7 +1551,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
await storage.clearExcludedData(timeRangeDate, userId)
|
||||
const mailSetEntryTypeModel = await typeModelResolver.resolveClientTypeReference(MailSetEntryTypeRef)
|
||||
|
||||
o.check(await getAllIdsForType(MailFolderTypeRef)).deepEquals([inboxFolderId, spamFolderId, trashFolderId])
|
||||
o.check(await getAllIdsForType(MailSetTypeRef)).deepEquals([inboxFolderId, spamFolderId, trashFolderId])
|
||||
const allMailSetEntryIds = await getAllIdsForType(MailSetEntryTypeRef)
|
||||
o.check(allMailSetEntryIds).deepEquals([ensureBase64Ext(mailSetEntryTypeModel, twoDaysAfterMailSetEntryElementId)])
|
||||
o.check(await getAllIdsForType(MailTypeRef)).deepEquals([twoDaysAfterMailId])
|
||||
|
|
@ -1631,14 +1631,14 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
})
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", inboxFolderId],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
folderType: MailSetKind.INBOX,
|
||||
entries: inboxFolderEntriesId,
|
||||
})
|
||||
await storage.put(MailFolderTypeRef, await toStorableInstance(inboxFolder))
|
||||
await storage.put(MailSetTypeRef, await toStorableInstance(inboxFolder))
|
||||
await storage.put(MailTypeRef, await toStorableInstance(mailOneDayBefore))
|
||||
await storage.put(MailTypeRef, await toStorableInstance(mailTwoDaysBefore))
|
||||
await storage.put(MailSetEntryTypeRef, await toStorableInstance(mailSetEntryTwoDaysBefore))
|
||||
|
|
@ -1649,7 +1649,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
// Here we clear the excluded data
|
||||
await storage.clearExcludedData(timeRangeDate, userId)
|
||||
|
||||
o.check(await getAllIdsForType(MailFolderTypeRef)).deepEquals([inboxFolderId, spamFolderId, trashFolderId])
|
||||
o.check(await getAllIdsForType(MailSetTypeRef)).deepEquals([inboxFolderId, spamFolderId, trashFolderId])
|
||||
const allMailSetEntryIds = await getAllIdsForType(MailSetEntryTypeRef)
|
||||
o.check(allMailSetEntryIds).deepEquals([])
|
||||
o.check(await getAllIdsForType(MailTypeRef)).deepEquals([])
|
||||
|
|
@ -1742,14 +1742,14 @@ o.spec("OfflineStorageDb", function () {
|
|||
}),
|
||||
})
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", inboxFolderId],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
folderType: MailSetKind.INBOX,
|
||||
entries: inboxFolderEntriesId,
|
||||
})
|
||||
await storage.put(MailFolderTypeRef, await toStorableInstance(inboxFolder))
|
||||
await storage.put(MailSetTypeRef, await toStorableInstance(inboxFolder))
|
||||
await storage.put(MailSetEntryTypeRef, await toStorableInstance(mailSetEntryBefore))
|
||||
await storage.put(MailSetEntryTypeRef, await toStorableInstance(mailSetEntryAfter))
|
||||
await storage.put(MailTypeRef, await toStorableInstance(mailBefore))
|
||||
|
|
@ -1777,7 +1777,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
mailSetEntryIdGenerator: MailSetEntryIdGenerator,
|
||||
getSubject: (i: number) => string,
|
||||
getBody: (i: number) => string,
|
||||
folder: MailFolder,
|
||||
folder: MailSet,
|
||||
): { mailSetEntries: Array<MailSetEntry>; mails: Array<Mail>; mailDetailsBlobs: Array<MailDetailsBlob> } {
|
||||
const mailSetEntries: Array<MailSetEntry> = []
|
||||
const mails: Array<Mail> = []
|
||||
|
|
@ -1844,7 +1844,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
mailImportStates: "mailImportStates",
|
||||
})
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", oldIds.getNext()],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1877,7 +1877,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
inboxFolder,
|
||||
)
|
||||
|
||||
const trashFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const trashFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", oldIds.getNext()],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
@ -1909,7 +1909,7 @@ o.spec("OfflineStorageDb", function () {
|
|||
trashFolder,
|
||||
)
|
||||
|
||||
const spamFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const spamFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", oldIds.getNext()],
|
||||
_ownerGroup: "ownerGroup",
|
||||
_permissions: "permissions",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
Mail,
|
||||
MailAddress,
|
||||
MailAddressTypeRef,
|
||||
MailBox,
|
||||
MailboxGroupRoot,
|
||||
MailboxGroupRootTypeRef,
|
||||
MailDetailsBlob,
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ import {
|
|||
MailDetailsBlobTypeRef,
|
||||
MailDetailsDraftTypeRef,
|
||||
MailDetailsTypeRef,
|
||||
MailFolder,
|
||||
MailFolderRefTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetRefTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailSetEntry,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
|
|
@ -172,9 +172,9 @@ o.spec("MailIndexer", () => {
|
|||
})
|
||||
})
|
||||
|
||||
function _addFolder(mailbox: MailBox): MailFolder {
|
||||
const folder = createTestEntity(MailFolderTypeRef)
|
||||
folder._id = [neverNull(mailbox.folders).folders, entityMock.getNextId()]
|
||||
function _addFolder(mailbox: MailBox): MailSet {
|
||||
const folder = createTestEntity(MailSetTypeRef)
|
||||
folder._id = [mailbox.folders.folders, entityMock.getNextId()]
|
||||
folder.entries = entityMock.getNextId()
|
||||
return folder
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ o.spec("MailIndexer", () => {
|
|||
const rangeEndShifted2Days = getDayShifted(new Date(rangeEnd), -2).getTime()
|
||||
const mailGroup = "mail-group-id"
|
||||
let mailbox: MailBox
|
||||
let folder1: MailFolder, folder2: MailFolder
|
||||
let folder1: MailSet, folder2: MailSet
|
||||
let mail0: Mail,
|
||||
details0: MailDetailsBlob,
|
||||
mailEntry0: MailSetEntry,
|
||||
|
|
@ -217,7 +217,7 @@ o.spec("MailIndexer", () => {
|
|||
mailbox.currentMailBag = createTestEntity(MailBagTypeRef, { _id: "mailBagId", mails: mailBagMailListId })
|
||||
mailbox._id = "mailbox-id"
|
||||
mailbox._ownerGroup = mailGroup
|
||||
const folderRef = createTestEntity(MailFolderRefTypeRef)
|
||||
const folderRef = createTestEntity(MailSetRefTypeRef)
|
||||
folderRef.folders = entityMock.getNextId()
|
||||
mailbox.folders = folderRef
|
||||
folder1 = _addFolder(mailbox)
|
||||
|
|
@ -768,7 +768,7 @@ o.spec("MailIndexer", () => {
|
|||
const mailbox = createTestEntity(MailBoxTypeRef, {
|
||||
_id: "mailbox-id",
|
||||
_ownerGroup: mailGroup1,
|
||||
folders: createTestEntity(MailFolderRefTypeRef, {
|
||||
folders: createTestEntity(MailSetRefTypeRef, {
|
||||
folders: "foldersId",
|
||||
}),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import {
|
|||
MailBoxTypeRef,
|
||||
MailDetails,
|
||||
MailDetailsTypeRef,
|
||||
MailFolderRefTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetRefTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailTypeRef,
|
||||
} from "../../../../../../src/common/api/entities/tutanota/TypeRefs"
|
||||
import { MailSetKind, MAX_NBR_OF_MAILS_SYNC_OPERATION, SpamDecision } from "../../../../../../src/common/api/common/TutanotaConstants"
|
||||
|
|
@ -67,17 +67,17 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
let mailboxGroupRoot: MailboxGroupRoot
|
||||
let mailBox: MailBox
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "inbox"],
|
||||
_ownerGroup: "owner",
|
||||
folderType: MailSetKind.INBOX,
|
||||
})
|
||||
const trashFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const trashFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "trash"],
|
||||
_ownerGroup: "owner",
|
||||
folderType: MailSetKind.TRASH,
|
||||
})
|
||||
const spamFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const spamFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "spam"],
|
||||
_ownerGroup: "owner",
|
||||
folderType: MailSetKind.SPAM,
|
||||
|
|
@ -91,7 +91,7 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
mailBox = createTestEntity(MailBoxTypeRef, {
|
||||
_id: "mailbox",
|
||||
_ownerGroup: "owner",
|
||||
folders: createTestEntity(MailFolderRefTypeRef, { folders: "folderListId" }),
|
||||
folders: createTestEntity(MailSetRefTypeRef, { folders: "folderListId" }),
|
||||
currentMailBag: createTestEntity(MailBagTypeRef, { mails: "mailListId" }),
|
||||
archivedMailBags: [createTestEntity(MailBagTypeRef, { mails: "oldMailListId" })],
|
||||
clientSpamTrainingData: "clientSpamTrainingData",
|
||||
|
|
@ -141,20 +141,6 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
})
|
||||
|
||||
o.spec("fetchAllTrainingData", () => {
|
||||
o("returns empty training data when index or training data is null", async () => {
|
||||
mailBox.clientSpamTrainingData = null
|
||||
mailBox.modifiedClientSpamTrainingDataIndex = null
|
||||
when(entityClientMock.load(MailboxGroupRootTypeRef, "owner")).thenResolve(mailboxGroupRoot)
|
||||
when(entityClientMock.load(MailBoxTypeRef, "mailbox")).thenResolve(mailBox)
|
||||
|
||||
const trainingDataset = await spamClassificationDataDealer.fetchAllTrainingData("owner")
|
||||
|
||||
o(trainingDataset.trainingData.length).equals(0)
|
||||
o(trainingDataset.hamCount).equals(0)
|
||||
o(trainingDataset.spamCount).equals(0)
|
||||
o(trainingDataset.lastTrainingDataIndexId).equals(GENERATED_MIN_ID)
|
||||
})
|
||||
|
||||
o("uploads training data when clientSpamTrainingData is empty", async () => {
|
||||
when(entityClientMock.load(MailboxGroupRootTypeRef, "owner")).thenResolve(mailboxGroupRoot)
|
||||
when(entityClientMock.load(MailBoxTypeRef, "mailbox")).thenResolve(mailBox)
|
||||
|
|
@ -167,13 +153,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
)
|
||||
const spamTrainingData = Array.from({ length: 10 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(mails[index]),
|
||||
]),
|
||||
).concat(
|
||||
Array.from({ length: 10 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(mails[10 + index]),
|
||||
]),
|
||||
),
|
||||
|
|
@ -181,11 +167,11 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
const modifiedIndicesSinceStart = spamTrainingData.map((data) =>
|
||||
createClientSpamTrainingDatumIndexEntryByClientSpamTrainingDatumElementId(getElementId(data)),
|
||||
)
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!)).thenResolve([], spamTrainingData)
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData)).thenResolve([], spamTrainingData)
|
||||
when(entityClientMock.loadAll(MailTypeRef, mailBox.currentMailBag!.mails, anything())).thenResolve(mails)
|
||||
when(entityClientMock.loadAll(MailTypeRef, mailBox.archivedMailBags[0].mails, anything())).thenResolve([])
|
||||
when(entityClientMock.loadAll(MailFolderTypeRef, mailBox.folders!.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!)).thenResolve(
|
||||
when(entityClientMock.loadAll(MailSetTypeRef, mailBox.folders.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex)).thenResolve(
|
||||
modifiedIndicesSinceStart,
|
||||
)
|
||||
|
||||
|
|
@ -198,8 +184,8 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
const trainingDataset = await spamClassificationDataDealer.fetchAllTrainingData("owner")
|
||||
|
||||
// first load: empty, second load: fetch uploaded data
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!), { times: 2 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!), { times: 1 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData), { times: 2 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex), { times: 1 })
|
||||
const unencryptedPayload = mails.map((mail) => {
|
||||
return {
|
||||
mailId: mail._id,
|
||||
|
|
@ -232,13 +218,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
|
||||
const existingSpamTrainingData = Array.from({ length: 20 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[index]),
|
||||
]),
|
||||
).concat(
|
||||
Array.from({ length: 20 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[40 + index]),
|
||||
]),
|
||||
),
|
||||
|
|
@ -246,13 +232,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
|
||||
const updatedSpamTrainingData = Array.from({ length: 40 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[index]),
|
||||
]),
|
||||
).concat(
|
||||
Array.from({ length: 40 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[40 + index]),
|
||||
]),
|
||||
),
|
||||
|
|
@ -262,14 +248,14 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
createClientSpamTrainingDatumIndexEntryByClientSpamTrainingDatumElementId(getElementId(data)),
|
||||
)
|
||||
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!)).thenResolve(
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData)).thenResolve(
|
||||
existingSpamTrainingData,
|
||||
updatedSpamTrainingData,
|
||||
)
|
||||
when(entityClientMock.loadAll(MailTypeRef, mailBox.currentMailBag!.mails, anything())).thenResolve(relevantMails)
|
||||
when(entityClientMock.loadAll(MailTypeRef, mailBox.archivedMailBags[0].mails, anything())).thenResolve([])
|
||||
when(entityClientMock.loadAll(MailFolderTypeRef, mailBox.folders!.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!)).thenResolve(
|
||||
when(entityClientMock.loadAll(MailSetTypeRef, mailBox.folders.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex)).thenResolve(
|
||||
modifiedIndicesSinceStart,
|
||||
)
|
||||
|
||||
|
|
@ -286,8 +272,8 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
const trainingDataset = await spamClassificationDataDealer.fetchAllTrainingData("owner")
|
||||
|
||||
// first load: empty, second load: fetch uploaded data
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!), { times: 2 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!), { times: 1 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData), { times: 2 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex), { times: 1 })
|
||||
|
||||
const unencryptedPayload = expectUploadMailsTotal.map((mail) => {
|
||||
return {
|
||||
|
|
@ -321,13 +307,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
|
||||
const existingSpamTrainingData = Array.from({ length: 40 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[index]),
|
||||
]),
|
||||
).concat(
|
||||
Array.from({ length: 40 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[80 + index]),
|
||||
]),
|
||||
),
|
||||
|
|
@ -335,13 +321,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
|
||||
const updatedSpamTrainingData = Array.from({ length: 80 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[index]),
|
||||
]),
|
||||
).concat(
|
||||
Array.from({ length: 80 }, (_, index) =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST, [
|
||||
mailBox.clientSpamTrainingData!,
|
||||
mailBox.clientSpamTrainingData,
|
||||
getElementId(relevantMails[80 + index]),
|
||||
]),
|
||||
),
|
||||
|
|
@ -351,14 +337,14 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
createClientSpamTrainingDatumIndexEntryByClientSpamTrainingDatumElementId(getElementId(data)),
|
||||
)
|
||||
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!)).thenResolve(
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData)).thenResolve(
|
||||
existingSpamTrainingData,
|
||||
updatedSpamTrainingData,
|
||||
)
|
||||
when(entityClientMock.loadAll(MailTypeRef, mailBox.currentMailBag!.mails, anything())).thenResolve(relevantMails)
|
||||
when(entityClientMock.loadAll(MailTypeRef, mailBox.archivedMailBags[0].mails, anything())).thenResolve([])
|
||||
when(entityClientMock.loadAll(MailFolderTypeRef, mailBox.folders!.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!)).thenResolve(
|
||||
when(entityClientMock.loadAll(MailSetTypeRef, mailBox.folders.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex)).thenResolve(
|
||||
modifiedIndicesSinceStart,
|
||||
)
|
||||
|
||||
|
|
@ -382,8 +368,8 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
const trainingDataset = await spamClassificationDataDealer.fetchAllTrainingData("owner")
|
||||
|
||||
// first load: empty, second load: fetch uploaded data
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!), { times: 2 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!), { times: 1 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData), { times: 2 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex), { times: 1 })
|
||||
|
||||
const firstUnencryptedPayload = expectedFirstChunk.map((mail) => {
|
||||
return {
|
||||
|
|
@ -423,17 +409,17 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
const modifiedIndicesSinceStart = spamTrainingData.map((data) =>
|
||||
createClientSpamTrainingDatumIndexEntryByClientSpamTrainingDatumElementId(getElementId(data)),
|
||||
)
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!)).thenResolve(spamTrainingData)
|
||||
when(entityClientMock.loadAll(MailFolderTypeRef, mailBox.folders!.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!)).thenResolve(
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData)).thenResolve(spamTrainingData)
|
||||
when(entityClientMock.loadAll(MailSetTypeRef, mailBox.folders.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex)).thenResolve(
|
||||
modifiedIndicesSinceStart,
|
||||
)
|
||||
|
||||
const trainingDataset = await spamClassificationDataDealer.fetchAllTrainingData("owner")
|
||||
|
||||
// only one load as the list is already populated
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!), { times: 1 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!), { times: 1 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData), { times: 1 })
|
||||
verify(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex), { times: 1 })
|
||||
|
||||
o(trainingDataset).deepEquals({
|
||||
trainingData: spamTrainingData,
|
||||
|
|
@ -456,13 +442,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
const modifiedIndicesSinceStart = spamTrainingData.map((data) =>
|
||||
createClientSpamTrainingDatumIndexEntryByClientSpamTrainingDatumElementId(getElementId(data)),
|
||||
)
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData!)).thenResolve(spamTrainingData)
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumTypeRef, mailBox.clientSpamTrainingData)).thenResolve(spamTrainingData)
|
||||
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex!)).thenResolve(
|
||||
when(entityClientMock.loadAll(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex)).thenResolve(
|
||||
modifiedIndicesSinceStart,
|
||||
)
|
||||
|
||||
when(entityClientMock.loadAll(MailFolderTypeRef, mailBox.folders!.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
when(entityClientMock.loadAll(MailSetTypeRef, mailBox.folders.folders)).thenResolve([inboxFolder, spamFolder, trashFolder])
|
||||
|
||||
const result = await spamClassificationDataDealer.fetchAllTrainingData("owner")
|
||||
|
||||
|
|
@ -474,27 +460,13 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
})
|
||||
|
||||
o.spec("fetchPartialTrainingDataFromIndexStartId", () => {
|
||||
o("returns empty training data when index or training data is null", async () => {
|
||||
mailBox.clientSpamTrainingData = null
|
||||
mailBox.modifiedClientSpamTrainingDataIndex = null
|
||||
when(entityClientMock.load(MailboxGroupRootTypeRef, "owner")).thenResolve(mailboxGroupRoot)
|
||||
when(entityClientMock.load(MailBoxTypeRef, "mailbox")).thenResolve(mailBox)
|
||||
|
||||
const trainingDataset = await spamClassificationDataDealer.fetchPartialTrainingDataFromIndexStartId("startId", "owner")
|
||||
|
||||
o(trainingDataset.trainingData.length).equals(0)
|
||||
o(trainingDataset.hamCount).equals(0)
|
||||
o(trainingDataset.spamCount).equals(0)
|
||||
o(trainingDataset.lastTrainingDataIndexId).equals("startId")
|
||||
})
|
||||
|
||||
o("returns empty training data when modifiedClientSpamTrainingDataIndicesSinceStart are null", async () => {
|
||||
when(entityClientMock.load(MailboxGroupRootTypeRef, "owner")).thenResolve(mailboxGroupRoot)
|
||||
when(entityClientMock.load(MailBoxTypeRef, "mailbox")).thenResolve(mailBox)
|
||||
when(
|
||||
entityClientMock.loadRange(
|
||||
ClientSpamTrainingDatumIndexEntryTypeRef,
|
||||
mailBox.modifiedClientSpamTrainingDataIndex!,
|
||||
mailBox.modifiedClientSpamTrainingDataIndex,
|
||||
"startId",
|
||||
SINGLE_TRAIN_INTERVAL_TRAINING_DATA_LIMIT,
|
||||
false,
|
||||
|
|
@ -517,26 +489,20 @@ o.spec("SpamClassificationDataDealer", () => {
|
|||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST),
|
||||
).concat(Array.from({ length: 50 }, () => createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST)))
|
||||
|
||||
oldSpamTrainingData.map((data) => (data._id = [mailBox.clientSpamTrainingData!, GENERATED_MIN_ID]))
|
||||
oldSpamTrainingData.map((data) => (data._id = [mailBox.clientSpamTrainingData, GENERATED_MIN_ID]))
|
||||
|
||||
const newSpamTrainingData = Array.from({ length: 10 }, () =>
|
||||
createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.WHITELIST),
|
||||
).concat(Array.from({ length: 10 }, () => createSpamTrainingDatumByConfidenceAndDecision(DEFAULT_IS_SPAM_CONFIDENCE, SpamDecision.BLACKLIST)))
|
||||
|
||||
newSpamTrainingData.map((data) => (data._id = [mailBox.clientSpamTrainingData!, GENERATED_MIN_ID]))
|
||||
newSpamTrainingData.map((data) => (data._id = [mailBox.clientSpamTrainingData, GENERATED_MIN_ID]))
|
||||
|
||||
const modifiedIndicesSinceStart = newSpamTrainingData.map((data) =>
|
||||
createClientSpamTrainingDatumIndexEntryByClientSpamTrainingDatumElementId(getElementId(data)),
|
||||
)
|
||||
|
||||
when(
|
||||
entityClientMock.loadRange(
|
||||
ClientSpamTrainingDatumIndexEntryTypeRef,
|
||||
mailBox.modifiedClientSpamTrainingDataIndex!,
|
||||
"startId",
|
||||
anything(),
|
||||
false,
|
||||
),
|
||||
entityClientMock.loadRange(ClientSpamTrainingDatumIndexEntryTypeRef, mailBox.modifiedClientSpamTrainingDataIndex, "startId", anything(), false),
|
||||
).thenResolve(modifiedIndicesSinceStart)
|
||||
|
||||
when(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
MailDetailsBlob,
|
||||
MailDetailsBlobTypeRef,
|
||||
MailDetailsTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailTypeRef,
|
||||
RecipientsTypeRef,
|
||||
} from "../../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
|
|
@ -39,15 +39,15 @@ o.spec("MailModelTest", function () {
|
|||
let notifications: Partial<Notifications>
|
||||
let showSpy: Spy
|
||||
let model: MailModel
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "inboxId"],
|
||||
folderType: MailSetKind.INBOX,
|
||||
})
|
||||
const spamFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const spamFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "spamId"],
|
||||
folderType: MailSetKind.SPAM,
|
||||
})
|
||||
const anotherFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const anotherFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "archiveId"],
|
||||
folderType: MailSetKind.ARCHIVE,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
Mail,
|
||||
MailDetails,
|
||||
MailDetailsTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailTypeRef,
|
||||
} from "../../../src/common/api/entities/tutanota/TypeRefs"
|
||||
import { FeatureType, MailSetKind, ProcessingState, SpamDecision } from "../../../src/common/api/common/TutanotaConstants"
|
||||
|
|
@ -38,9 +38,9 @@ o.spec("ProcessInboxHandlerTest", function () {
|
|||
let inboxRuleHandler: InboxRuleHandler = object<InboxRuleHandler>()
|
||||
let processInboxHandler: ProcessInboxHandler
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, { _id: ["listId", "inbox"], folderType: MailSetKind.INBOX })
|
||||
const trashFolder = createTestEntity(MailFolderTypeRef, { _id: ["listId", "trash"], folderType: MailSetKind.TRASH })
|
||||
const spamFolder = createTestEntity(MailFolderTypeRef, { _id: ["listId", "spam"], folderType: MailSetKind.SPAM })
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, { _id: ["listId", "inbox"], folderType: MailSetKind.INBOX })
|
||||
const trashFolder = createTestEntity(MailSetTypeRef, { _id: ["listId", "trash"], folderType: MailSetKind.TRASH })
|
||||
const spamFolder = createTestEntity(MailSetTypeRef, { _id: ["listId", "spam"], folderType: MailSetKind.SPAM })
|
||||
|
||||
o.beforeEach(function () {
|
||||
spamHandler = object<SpamClassificationHandler>()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
Mail,
|
||||
MailDetails,
|
||||
MailDetailsTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailTypeRef,
|
||||
} from "../../../src/common/api/entities/tutanota/TypeRefs"
|
||||
import { SpamClassifier } from "../../../src/mail-app/workerUtils/spamClassification/SpamClassifier"
|
||||
|
|
@ -34,9 +34,9 @@ o.spec("SpamClassificationHandlerTest", function () {
|
|||
let folderSystem: FolderSystem
|
||||
let mailDetails: MailDetails
|
||||
|
||||
const inboxFolder = createTestEntity(MailFolderTypeRef, { _id: ["listId", "inbox"], folderType: MailSetKind.INBOX })
|
||||
const trashFolder = createTestEntity(MailFolderTypeRef, { _id: ["listId", "trash"], folderType: MailSetKind.TRASH })
|
||||
const spamFolder = createTestEntity(MailFolderTypeRef, { _id: ["listId", "spam"], folderType: MailSetKind.SPAM })
|
||||
const inboxFolder = createTestEntity(MailSetTypeRef, { _id: ["listId", "inbox"], folderType: MailSetKind.INBOX })
|
||||
const trashFolder = createTestEntity(MailSetTypeRef, { _id: ["listId", "trash"], folderType: MailSetKind.TRASH })
|
||||
const spamFolder = createTestEntity(MailSetTypeRef, { _id: ["listId", "spam"], folderType: MailSetKind.SPAM })
|
||||
|
||||
const compressedUnencryptedTestVector = new Uint8Array([23, 3, 21, 12, 14, 2, 23, 3, 30, 3, 4, 3, 2, 31, 23, 22, 30])
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import {
|
|||
Mail,
|
||||
MailboxGroupRootTypeRef,
|
||||
MailBoxTypeRef,
|
||||
MailFolder,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetTypeRef,
|
||||
MailSetEntry,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
|
|
@ -62,15 +62,15 @@ o.spec("ConversationListModel", () => {
|
|||
const mailSetEntriesListId = "entries"
|
||||
const _ownerGroup = "me"
|
||||
|
||||
const labels: MailFolder[] = [
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
const labels: MailSet[] = [
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "tutaPrimary"],
|
||||
color: theme.primary,
|
||||
folderType: MailSetKind.LABEL,
|
||||
name: "Tuta Primary Label",
|
||||
parentFolder: null,
|
||||
}),
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "tutaSecondary"],
|
||||
color: theme.secondary,
|
||||
folderType: MailSetKind.LABEL,
|
||||
|
|
@ -79,7 +79,7 @@ o.spec("ConversationListModel", () => {
|
|||
}),
|
||||
]
|
||||
|
||||
let mailSet: MailFolder
|
||||
let mailSet: MailSet
|
||||
let conversationPrefProvider: ConversationPrefProvider
|
||||
let entityClient: EntityClient
|
||||
let mailModel: MailModel
|
||||
|
|
@ -88,7 +88,7 @@ o.spec("ConversationListModel", () => {
|
|||
let connectivityModel: WebsocketConnectivityModel
|
||||
|
||||
o.beforeEach(() => {
|
||||
mailSet = createTestEntity(MailFolderTypeRef, {
|
||||
mailSet = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "mailFolderId"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
name: "My Folder",
|
||||
|
|
@ -125,7 +125,7 @@ o.spec("ConversationListModel", () => {
|
|||
}
|
||||
|
||||
// Creates a totalMails number of mails, grouping into a number of conversations equal to totalMails/mailsPerConversation
|
||||
async function setUpTestData(totalMails: number, initialLabels: MailFolder[], offline: boolean, mailsPerConversation: number): Promise<Mail[]> {
|
||||
async function setUpTestData(totalMails: number, initialLabels: MailSet[], offline: boolean, mailsPerConversation: number): Promise<Mail[]> {
|
||||
const mailSetEntries: MailSetEntry[] = []
|
||||
const mails: Mail[][] = [[], [], [], [], [], [], [], [], [], []]
|
||||
const allMails: Mail[] = []
|
||||
|
|
@ -155,7 +155,7 @@ o.spec("ConversationListModel", () => {
|
|||
}
|
||||
|
||||
when(mailModel.getLabelsForMail(matchers.anything())).thenDo((mail: Mail) => {
|
||||
const sets: MailFolder[] = []
|
||||
const sets: MailSet[] = []
|
||||
for (const set of mail.sets) {
|
||||
const setToAdd = labels.find((label) => isSameId(label._id, set))
|
||||
if (setToAdd) {
|
||||
|
|
@ -436,7 +436,7 @@ o.spec("ConversationListModel", () => {
|
|||
o.check(model.getLabelsForMail(someMail.mail)[1]).notDeepEquals(labels[1])
|
||||
|
||||
const entityUpdateData: EntityUpdateData = {
|
||||
typeRef: MailFolderTypeRef,
|
||||
typeRef: MailSetTypeRef,
|
||||
instanceListId: getListId(labels[1]) as NonEmptyString,
|
||||
instanceId: getElementId(labels[1]),
|
||||
operation: OperationType.DELETE,
|
||||
|
|
@ -464,7 +464,7 @@ o.spec("ConversationListModel", () => {
|
|||
await model.loadInitial()
|
||||
|
||||
const entityUpdateData: EntityUpdateData = {
|
||||
typeRef: MailFolderTypeRef,
|
||||
typeRef: MailSetTypeRef,
|
||||
instanceListId: getListId(labels[1]) as NonEmptyString,
|
||||
instanceId: getElementId(labels[1]),
|
||||
operation: OperationType.DELETE,
|
||||
|
|
@ -516,7 +516,7 @@ o.spec("ConversationListModel", () => {
|
|||
mail: Mail
|
||||
mailSetEntry: MailSetEntry
|
||||
entityUpdateData: EntityUpdateData
|
||||
mailLabels: MailFolder[]
|
||||
mailLabels: MailSet[]
|
||||
} {
|
||||
const newMail = createTestEntity(MailTypeRef, {
|
||||
_id: ["new mail!!!", deconstructMailSetEntryId(elementIdPart(mailSetEntryId)).mailId],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import o from "@tutao/otest"
|
||||
import { MailFolderTypeRef, MailTypeRef } from "../../../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
import { MailSetTypeRef, MailTypeRef } from "../../../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
import { MailSetKind } from "../../../../src/common/api/common/TutanotaConstants.js"
|
||||
import { FolderSystem } from "../../../../src/common/api/common/mail/FolderSystem.js"
|
||||
import { createTestEntity } from "../../TestUtils.js"
|
||||
|
|
@ -7,26 +7,26 @@ import { getElementId } from "../../../../src/common/api/common/utils/EntityUtil
|
|||
|
||||
o.spec("FolderSystem", function () {
|
||||
const listId = "listId"
|
||||
const inbox = createTestEntity(MailFolderTypeRef, { _id: [listId, "inbox"], folderType: MailSetKind.INBOX })
|
||||
const archive = createTestEntity(MailFolderTypeRef, { _id: [listId, "archive"], folderType: MailSetKind.ARCHIVE })
|
||||
const customFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const inbox = createTestEntity(MailSetTypeRef, { _id: [listId, "inbox"], folderType: MailSetKind.INBOX })
|
||||
const archive = createTestEntity(MailSetTypeRef, { _id: [listId, "archive"], folderType: MailSetKind.ARCHIVE })
|
||||
const customFolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "custom"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
name: "X",
|
||||
})
|
||||
const customSubfolder = createTestEntity(MailFolderTypeRef, {
|
||||
const customSubfolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "customSub"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
parentFolder: customFolder._id,
|
||||
name: "AA",
|
||||
})
|
||||
const customSubSubfolder = createTestEntity(MailFolderTypeRef, {
|
||||
const customSubSubfolder = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "customSubSub"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
parentFolder: customSubfolder._id,
|
||||
name: "B",
|
||||
})
|
||||
const customSubSubfolderAnother = createTestEntity(MailFolderTypeRef, {
|
||||
const customSubSubfolderAnother = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "customSubSubAnother"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
parentFolder: customSubfolder._id,
|
||||
|
|
@ -74,12 +74,12 @@ o.spec("FolderSystem", function () {
|
|||
})
|
||||
|
||||
o("indented list sorts stepsiblings correctly", function () {
|
||||
const customFolderAnother = createTestEntity(MailFolderTypeRef, {
|
||||
const customFolderAnother = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "customAnother"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
name: "Another top-level custom",
|
||||
})
|
||||
const customFolderAnotherSub = createTestEntity(MailFolderTypeRef, {
|
||||
const customFolderAnotherSub = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "customAnotherSub"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
parentFolder: customFolderAnother._id,
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import {
|
|||
Mail,
|
||||
MailboxGroupRootTypeRef,
|
||||
MailBoxTypeRef,
|
||||
MailFolder,
|
||||
MailFolderTypeRef,
|
||||
MailSet,
|
||||
MailSetTypeRef,
|
||||
MailSetEntry,
|
||||
MailSetEntryTypeRef,
|
||||
MailTypeRef,
|
||||
|
|
@ -59,15 +59,15 @@ o.spec("MailListModel", () => {
|
|||
const mailSetEntriesListId = "entries"
|
||||
const _ownerGroup = "me"
|
||||
|
||||
const labels: MailFolder[] = [
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
const labels: MailSet[] = [
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "tutaPrimary"],
|
||||
color: theme.primary,
|
||||
folderType: MailSetKind.LABEL,
|
||||
name: "Tuta Primary Label",
|
||||
parentFolder: null,
|
||||
}),
|
||||
createTestEntity(MailFolderTypeRef, {
|
||||
createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "tutaSecondary"],
|
||||
color: theme.secondary,
|
||||
folderType: MailSetKind.LABEL,
|
||||
|
|
@ -76,7 +76,7 @@ o.spec("MailListModel", () => {
|
|||
}),
|
||||
]
|
||||
|
||||
let mailSet: MailFolder
|
||||
let mailSet: MailSet
|
||||
let conversationPrefProvider: ConversationPrefProvider
|
||||
let entityClient: EntityClient
|
||||
let mailModel: MailModel
|
||||
|
|
@ -85,7 +85,7 @@ o.spec("MailListModel", () => {
|
|||
let connectivityModel: WebsocketConnectivityModel
|
||||
|
||||
o.beforeEach(() => {
|
||||
mailSet = createTestEntity(MailFolderTypeRef, {
|
||||
mailSet = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["mailFolderList", "mailFolderId"],
|
||||
folderType: MailSetKind.CUSTOM,
|
||||
name: "My Folder",
|
||||
|
|
@ -123,7 +123,7 @@ o.spec("MailListModel", () => {
|
|||
|
||||
async function setUpTestData(
|
||||
count: number,
|
||||
initialLabels: MailFolder[],
|
||||
initialLabels: MailSet[],
|
||||
offline: boolean,
|
||||
mailTemplate: (idx: number) => Mail = (idx) =>
|
||||
createTestEntity(MailTypeRef, {
|
||||
|
|
@ -151,7 +151,7 @@ o.spec("MailListModel", () => {
|
|||
}
|
||||
|
||||
when(mailModel.getLabelsForMail(matchers.anything())).thenDo((mail: Mail) => {
|
||||
const sets: MailFolder[] = []
|
||||
const sets: MailSet[] = []
|
||||
for (const set of mail.sets) {
|
||||
const setToAdd = labels.find((label) => isSameId(label._id, set))
|
||||
if (setToAdd) {
|
||||
|
|
@ -370,7 +370,7 @@ o.spec("MailListModel", () => {
|
|||
o(model.getLabelsForMail(someMail.mail)[1]).notDeepEquals(labels[1])
|
||||
|
||||
const entityUpdateData: EntityUpdateData = {
|
||||
typeRef: MailFolderTypeRef,
|
||||
typeRef: MailSetTypeRef,
|
||||
instanceListId: getListId(labels[1]) as NonEmptyString,
|
||||
instanceId: getElementId(labels[1]),
|
||||
operation: OperationType.DELETE,
|
||||
|
|
@ -392,7 +392,7 @@ o.spec("MailListModel", () => {
|
|||
await model.loadInitial()
|
||||
|
||||
const entityUpdateData: EntityUpdateData = {
|
||||
typeRef: MailFolderTypeRef,
|
||||
typeRef: MailSetTypeRef,
|
||||
instanceListId: getListId(labels[1]) as NonEmptyString,
|
||||
instanceId: getElementId(labels[1]),
|
||||
operation: OperationType.DELETE,
|
||||
|
|
@ -434,7 +434,7 @@ o.spec("MailListModel", () => {
|
|||
mail: Mail
|
||||
mailSetEntry: MailSetEntry
|
||||
entityUpdateData: EntityUpdateData
|
||||
mailLabels: MailFolder[]
|
||||
mailLabels: MailSet[]
|
||||
} {
|
||||
const newMail = createTestEntity(MailTypeRef, {
|
||||
_id: ["new mail!!!", "the mail!!!"],
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
Mail,
|
||||
MailboxProperties,
|
||||
MailboxPropertiesTypeRef,
|
||||
MailFolderTypeRef,
|
||||
MailSetTypeRef,
|
||||
MailTypeRef,
|
||||
} from "../../../../src/common/api/entities/tutanota/TypeRefs.js"
|
||||
import { CreateMailViewerOptions } from "../../../../src/mail-app/mail/view/MailViewer.js"
|
||||
|
|
@ -198,7 +198,7 @@ o.spec("ConversationViewModel", function () {
|
|||
const trashDraftMail = addMail("trashDraftMail")
|
||||
trashDraftMail.state = MailState.DRAFT
|
||||
|
||||
const trash = createTestEntity(MailFolderTypeRef, {
|
||||
const trash = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "trashFolder"],
|
||||
folderType: MailSetKind.TRASH,
|
||||
})
|
||||
|
|
@ -223,7 +223,7 @@ o.spec("ConversationViewModel", function () {
|
|||
const trashDraftMail = addMail("trashDraftMail")
|
||||
trashDraftMail.state = MailState.DRAFT
|
||||
|
||||
const trash = createTestEntity(MailFolderTypeRef, {
|
||||
const trash = createTestEntity(MailSetTypeRef, {
|
||||
_id: [listId, "trashFolder"],
|
||||
folderType: MailSetKind.TRASH,
|
||||
})
|
||||
|
|
@ -371,7 +371,7 @@ o.spec("ConversationViewModel", function () {
|
|||
await loadingDefer.promise
|
||||
|
||||
conversation.pop()
|
||||
const trash = createTestEntity(MailFolderTypeRef, {
|
||||
const trash = createTestEntity(MailSetTypeRef, {
|
||||
_id: ["folderListId", "trashFolder"],
|
||||
folderType: MailSetKind.TRASH,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import o from "@tutao/otest"
|
||||
import { createTestEntity } from "../../TestUtils"
|
||||
import { MailFolderTypeRef } from "../../../../src/common/api/entities/tutanota/TypeRefs"
|
||||
import { MailSetTypeRef } from "../../../../src/common/api/entities/tutanota/TypeRefs"
|
||||
import { MailSetKind } from "../../../../src/common/api/common/TutanotaConstants"
|
||||
import { ConversationPrefProvider } from "../../../../src/mail-app/mail/view/ConversationViewModel"
|
||||
import { object, when } from "testdouble"
|
||||
|
|
@ -10,7 +10,7 @@ import { listByConversationInFolder } from "../../../../src/mail-app/mail/view/M
|
|||
o.spec("MailViewModelTest", () => {
|
||||
o.spec("listByConversation", () => {
|
||||
o.spec("in inbox folder", () => {
|
||||
const testInbox = createTestEntity(MailFolderTypeRef, {
|
||||
const testInbox = createTestEntity(MailSetTypeRef, {
|
||||
folderType: MailSetKind.INBOX,
|
||||
})
|
||||
|
||||
|
|
@ -36,10 +36,10 @@ o.spec("MailViewModelTest", () => {
|
|||
})
|
||||
})
|
||||
o.spec("in sent and draft folders", () => {
|
||||
const testDraftFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const testDraftFolder = createTestEntity(MailSetTypeRef, {
|
||||
folderType: MailSetKind.DRAFT,
|
||||
})
|
||||
const testSentFolder = createTestEntity(MailFolderTypeRef, {
|
||||
const testSentFolder = createTestEntity(MailSetTypeRef, {
|
||||
folderType: MailSetKind.SENT,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -460,9 +460,9 @@ pub struct MailBox {
|
|||
#[serde(rename = "134")]
|
||||
pub receivedAttachments: GeneratedId,
|
||||
#[serde(rename = "443")]
|
||||
pub folders: Option<MailFolderRef>,
|
||||
pub folders: MailSetRef,
|
||||
#[serde(rename = "1220")]
|
||||
pub spamResults: Option<SpamResults>,
|
||||
pub spamResults: SpamResults,
|
||||
#[serde(rename = "1318")]
|
||||
pub mailDetailsDrafts: Option<MailDetailsDraftsRef>,
|
||||
#[serde(rename = "1463")]
|
||||
|
|
@ -474,11 +474,11 @@ pub struct MailBox {
|
|||
#[serde(rename = "1585")]
|
||||
pub mailImportStates: GeneratedId,
|
||||
#[serde(rename = "1710")]
|
||||
pub extractedFeatures: Option<GeneratedId>,
|
||||
pub extractedFeatures: GeneratedId,
|
||||
#[serde(rename = "1754")]
|
||||
pub clientSpamTrainingData: Option<GeneratedId>,
|
||||
pub clientSpamTrainingData: GeneratedId,
|
||||
#[serde(rename = "1755")]
|
||||
pub modifiedClientSpamTrainingDataIndex: Option<GeneratedId>,
|
||||
pub modifiedClientSpamTrainingDataIndex: GeneratedId,
|
||||
|
||||
#[serde(default)]
|
||||
pub _errors: Errors,
|
||||
|
|
@ -815,7 +815,7 @@ impl Entity for DeleteMailData {
|
|||
|
||||
#[derive(uniffi::Record, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "testing"), derive(PartialEq, Debug))]
|
||||
pub struct MailFolder {
|
||||
pub struct MailSet {
|
||||
#[serde(rename = "431")]
|
||||
pub _id: Option<IdTupleGenerated>,
|
||||
#[serde(rename = "432")]
|
||||
|
|
@ -846,7 +846,7 @@ pub struct MailFolder {
|
|||
pub _finalIvs: HashMap<String, Option<FinalIv>>,
|
||||
}
|
||||
|
||||
impl Entity for MailFolder {
|
||||
impl Entity for MailSet {
|
||||
fn type_ref() -> TypeRef {
|
||||
TypeRef {
|
||||
app: AppName::Tutanota,
|
||||
|
|
@ -857,14 +857,14 @@ impl Entity for MailFolder {
|
|||
|
||||
#[derive(uniffi::Record, Clone, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "testing"), derive(PartialEq, Debug))]
|
||||
pub struct MailFolderRef {
|
||||
pub struct MailSetRef {
|
||||
#[serde(rename = "441")]
|
||||
pub _id: Option<CustomId>,
|
||||
#[serde(rename = "442")]
|
||||
pub folders: GeneratedId,
|
||||
}
|
||||
|
||||
impl Entity for MailFolderRef {
|
||||
impl Entity for MailSetRef {
|
||||
fn type_ref() -> TypeRef {
|
||||
TypeRef {
|
||||
app: AppName::Tutanota,
|
||||
|
|
@ -1660,8 +1660,6 @@ pub struct MailboxServerProperties {
|
|||
pub _format: i64,
|
||||
#[serde(rename = "682")]
|
||||
pub _ownerGroup: Option<GeneratedId>,
|
||||
#[serde(rename = "683")]
|
||||
pub whitelistProtectionEnabled: bool,
|
||||
}
|
||||
|
||||
impl Entity for MailboxServerProperties {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::entities::generated::tutanota::MailFolder;
|
||||
use crate::entities::generated::tutanota::MailSet;
|
||||
use num_enum::TryFromPrimitive;
|
||||
|
||||
pub struct FolderSystem {
|
||||
// this structure should probably change rather soon
|
||||
folders: Vec<MailFolder>,
|
||||
folders: Vec<MailSet>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, TryFromPrimitive, Debug)]
|
||||
|
|
@ -20,7 +20,7 @@ pub enum MailSetKind {
|
|||
Unknown = 9999,
|
||||
}
|
||||
|
||||
impl MailFolder {
|
||||
impl MailSet {
|
||||
fn mail_set_kind(&self) -> MailSetKind {
|
||||
MailSetKind::try_from(self.folderType as u64).unwrap_or(MailSetKind::Unknown)
|
||||
}
|
||||
|
|
@ -28,12 +28,12 @@ impl MailFolder {
|
|||
|
||||
impl FolderSystem {
|
||||
#[must_use]
|
||||
pub fn new(folders: Vec<MailFolder>) -> Self {
|
||||
pub fn new(folders: Vec<MailSet>) -> Self {
|
||||
Self { folders }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn system_folder_by_type(&self, mail_set_kind: MailSetKind) -> Option<&MailFolder> {
|
||||
pub fn system_folder_by_type(&self, mail_set_kind: MailSetKind) -> Option<&MailSet> {
|
||||
self.folders
|
||||
.iter()
|
||||
.find(|f| f.mail_set_kind() == mail_set_kind)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::crypto_entity_client::CryptoEntityClient;
|
|||
use crate::element_value::ParsedEntity;
|
||||
use crate::entities::generated::sys::{Group, GroupInfo};
|
||||
use crate::entities::generated::tutanota::{
|
||||
Mail, MailBox, MailFolder, MailboxGroupRoot, SimpleMoveMailPostIn, UnreadMailStatePostIn,
|
||||
Mail, MailBox, MailSet, MailboxGroupRoot, SimpleMoveMailPostIn, UnreadMailStatePostIn,
|
||||
};
|
||||
use crate::entities::Entity;
|
||||
use crate::folder_system::{FolderSystem, MailSetKind};
|
||||
|
|
@ -71,8 +71,8 @@ impl MailFacade {
|
|||
&self,
|
||||
mailbox: &MailBox,
|
||||
) -> Result<FolderSystem, ApiCallError> {
|
||||
let folders_list = &mailbox.folders.as_ref().unwrap().folders;
|
||||
let folders: Vec<MailFolder> = self
|
||||
let folders_list = &mailbox.folders.folders;
|
||||
let folders: Vec<MailSet> = self
|
||||
.crypto_entity_client
|
||||
.load_range(
|
||||
folders_list,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ use crate::entities::generated::monitor::ReadCounterReturn;
|
|||
use crate::entities::generated::monitor::ReportErrorIn;
|
||||
pub struct CounterService;
|
||||
|
||||
crate::service_impl!(declare, CounterService, "monitor/counterservice", 36);
|
||||
crate::service_impl!(declare, CounterService, "monitor/counterservice", 37);
|
||||
crate::service_impl!(POST, CounterService, WriteCounterData, ());
|
||||
crate::service_impl!(GET, CounterService, ReadCounterData, ReadCounterReturn);
|
||||
|
||||
|
||||
pub struct ReportErrorService;
|
||||
|
||||
crate::service_impl!(declare, ReportErrorService, "monitor/reporterrorservice", 36);
|
||||
crate::service_impl!(declare, ReportErrorService, "monitor/reporterrorservice", 37);
|
||||
crate::service_impl!(POST, ReportErrorService, ReportErrorIn, ());
|
||||
|
|
|
|||
|
|
@ -61,70 +61,70 @@ use crate::entities::generated::tutanota::UserAccountCreateData;
|
|||
use crate::entities::generated::tutanota::UserAccountPostOut;
|
||||
pub struct ApplyLabelService;
|
||||
|
||||
crate::service_impl!(declare, ApplyLabelService, "tutanota/applylabelservice", 98);
|
||||
crate::service_impl!(declare, ApplyLabelService, "tutanota/applylabelservice", 99);
|
||||
crate::service_impl!(POST, ApplyLabelService, ApplyLabelServicePostIn, ());
|
||||
|
||||
|
||||
pub struct CalendarService;
|
||||
|
||||
crate::service_impl!(declare, CalendarService, "tutanota/calendarservice", 98);
|
||||
crate::service_impl!(declare, CalendarService, "tutanota/calendarservice", 99);
|
||||
crate::service_impl!(POST, CalendarService, UserAreaGroupPostData, CreateGroupPostReturn);
|
||||
crate::service_impl!(DELETE, CalendarService, CalendarDeleteData, ());
|
||||
|
||||
|
||||
pub struct ChangePrimaryAddressService;
|
||||
|
||||
crate::service_impl!(declare, ChangePrimaryAddressService, "tutanota/changeprimaryaddressservice", 98);
|
||||
crate::service_impl!(declare, ChangePrimaryAddressService, "tutanota/changeprimaryaddressservice", 99);
|
||||
crate::service_impl!(PUT, ChangePrimaryAddressService, ChangePrimaryAddressServicePutIn, ());
|
||||
|
||||
|
||||
pub struct ClientClassifierResultService;
|
||||
|
||||
crate::service_impl!(declare, ClientClassifierResultService, "tutanota/clientclassifierresultservice", 98);
|
||||
crate::service_impl!(declare, ClientClassifierResultService, "tutanota/clientclassifierresultservice", 99);
|
||||
crate::service_impl!(POST, ClientClassifierResultService, ClientClassifierResultPostIn, ());
|
||||
|
||||
|
||||
pub struct ContactListGroupService;
|
||||
|
||||
crate::service_impl!(declare, ContactListGroupService, "tutanota/contactlistgroupservice", 98);
|
||||
crate::service_impl!(declare, ContactListGroupService, "tutanota/contactlistgroupservice", 99);
|
||||
crate::service_impl!(POST, ContactListGroupService, UserAreaGroupPostData, CreateGroupPostReturn);
|
||||
crate::service_impl!(DELETE, ContactListGroupService, UserAreaGroupDeleteData, ());
|
||||
|
||||
|
||||
pub struct CustomerAccountService;
|
||||
|
||||
crate::service_impl!(declare, CustomerAccountService, "tutanota/customeraccountservice", 98);
|
||||
crate::service_impl!(declare, CustomerAccountService, "tutanota/customeraccountservice", 99);
|
||||
crate::service_impl!(POST, CustomerAccountService, CustomerAccountCreateData, ());
|
||||
|
||||
|
||||
pub struct DraftService;
|
||||
|
||||
crate::service_impl!(declare, DraftService, "tutanota/draftservice", 98);
|
||||
crate::service_impl!(declare, DraftService, "tutanota/draftservice", 99);
|
||||
crate::service_impl!(POST, DraftService, DraftCreateData, DraftCreateReturn);
|
||||
crate::service_impl!(PUT, DraftService, DraftUpdateData, DraftUpdateReturn);
|
||||
|
||||
|
||||
pub struct EncryptTutanotaPropertiesService;
|
||||
|
||||
crate::service_impl!(declare, EncryptTutanotaPropertiesService, "tutanota/encrypttutanotapropertiesservice", 98);
|
||||
crate::service_impl!(declare, EncryptTutanotaPropertiesService, "tutanota/encrypttutanotapropertiesservice", 99);
|
||||
crate::service_impl!(POST, EncryptTutanotaPropertiesService, EncryptTutanotaPropertiesData, ());
|
||||
|
||||
|
||||
pub struct EntropyService;
|
||||
|
||||
crate::service_impl!(declare, EntropyService, "tutanota/entropyservice", 98);
|
||||
crate::service_impl!(declare, EntropyService, "tutanota/entropyservice", 99);
|
||||
crate::service_impl!(PUT, EntropyService, EntropyData, ());
|
||||
|
||||
|
||||
pub struct ExternalUserService;
|
||||
|
||||
crate::service_impl!(declare, ExternalUserService, "tutanota/externaluserservice", 98);
|
||||
crate::service_impl!(declare, ExternalUserService, "tutanota/externaluserservice", 99);
|
||||
crate::service_impl!(POST, ExternalUserService, ExternalUserData, ());
|
||||
|
||||
|
||||
pub struct GroupInvitationService;
|
||||
|
||||
crate::service_impl!(declare, GroupInvitationService, "tutanota/groupinvitationservice", 98);
|
||||
crate::service_impl!(declare, GroupInvitationService, "tutanota/groupinvitationservice", 99);
|
||||
crate::service_impl!(POST, GroupInvitationService, GroupInvitationPostData, GroupInvitationPostReturn);
|
||||
crate::service_impl!(PUT, GroupInvitationService, GroupInvitationPutData, ());
|
||||
crate::service_impl!(DELETE, GroupInvitationService, GroupInvitationDeleteData, ());
|
||||
|
|
@ -132,26 +132,26 @@ crate::service_impl!(DELETE, GroupInvitationService, GroupInvitationDeleteData,
|
|||
|
||||
pub struct ImportMailService;
|
||||
|
||||
crate::service_impl!(declare, ImportMailService, "tutanota/importmailservice", 98);
|
||||
crate::service_impl!(declare, ImportMailService, "tutanota/importmailservice", 99);
|
||||
crate::service_impl!(POST, ImportMailService, ImportMailPostIn, ImportMailPostOut);
|
||||
crate::service_impl!(GET, ImportMailService, ImportMailGetIn, ImportMailGetOut);
|
||||
|
||||
|
||||
pub struct ListUnsubscribeService;
|
||||
|
||||
crate::service_impl!(declare, ListUnsubscribeService, "tutanota/listunsubscribeservice", 98);
|
||||
crate::service_impl!(declare, ListUnsubscribeService, "tutanota/listunsubscribeservice", 99);
|
||||
crate::service_impl!(POST, ListUnsubscribeService, ListUnsubscribeData, ());
|
||||
|
||||
|
||||
pub struct MailExportTokenService;
|
||||
|
||||
crate::service_impl!(declare, MailExportTokenService, "tutanota/mailexporttokenservice", 98);
|
||||
crate::service_impl!(declare, MailExportTokenService, "tutanota/mailexporttokenservice", 99);
|
||||
crate::service_impl!(POST, MailExportTokenService, (), MailExportTokenServicePostOut);
|
||||
|
||||
|
||||
pub struct MailFolderService;
|
||||
|
||||
crate::service_impl!(declare, MailFolderService, "tutanota/mailfolderservice", 98);
|
||||
crate::service_impl!(declare, MailFolderService, "tutanota/mailfolderservice", 99);
|
||||
crate::service_impl!(POST, MailFolderService, CreateMailFolderData, CreateMailFolderReturn);
|
||||
crate::service_impl!(PUT, MailFolderService, UpdateMailFolderData, ());
|
||||
crate::service_impl!(DELETE, MailFolderService, DeleteMailFolderData, ());
|
||||
|
|
@ -159,99 +159,99 @@ crate::service_impl!(DELETE, MailFolderService, DeleteMailFolderData, ());
|
|||
|
||||
pub struct MailGroupService;
|
||||
|
||||
crate::service_impl!(declare, MailGroupService, "tutanota/mailgroupservice", 98);
|
||||
crate::service_impl!(declare, MailGroupService, "tutanota/mailgroupservice", 99);
|
||||
crate::service_impl!(POST, MailGroupService, CreateMailGroupData, MailGroupPostOut);
|
||||
crate::service_impl!(DELETE, MailGroupService, DeleteGroupData, ());
|
||||
|
||||
|
||||
pub struct MailService;
|
||||
|
||||
crate::service_impl!(declare, MailService, "tutanota/mailservice", 98);
|
||||
crate::service_impl!(declare, MailService, "tutanota/mailservice", 99);
|
||||
crate::service_impl!(DELETE, MailService, DeleteMailData, ());
|
||||
|
||||
|
||||
pub struct ManageLabelService;
|
||||
|
||||
crate::service_impl!(declare, ManageLabelService, "tutanota/managelabelservice", 98);
|
||||
crate::service_impl!(declare, ManageLabelService, "tutanota/managelabelservice", 99);
|
||||
crate::service_impl!(POST, ManageLabelService, ManageLabelServicePostIn, ());
|
||||
crate::service_impl!(DELETE, ManageLabelService, ManageLabelServiceDeleteIn, ());
|
||||
|
||||
|
||||
pub struct MoveMailService;
|
||||
|
||||
crate::service_impl!(declare, MoveMailService, "tutanota/movemailservice", 98);
|
||||
crate::service_impl!(declare, MoveMailService, "tutanota/movemailservice", 99);
|
||||
crate::service_impl!(POST, MoveMailService, MoveMailData, MoveMailPostOut);
|
||||
|
||||
|
||||
pub struct NewsService;
|
||||
|
||||
crate::service_impl!(declare, NewsService, "tutanota/newsservice", 98);
|
||||
crate::service_impl!(declare, NewsService, "tutanota/newsservice", 99);
|
||||
crate::service_impl!(POST, NewsService, NewsIn, ());
|
||||
crate::service_impl!(GET, NewsService, (), NewsOut);
|
||||
|
||||
|
||||
pub struct PopulateClientSpamTrainingDataService;
|
||||
|
||||
crate::service_impl!(declare, PopulateClientSpamTrainingDataService, "tutanota/populateclientspamtrainingdataservice", 98);
|
||||
crate::service_impl!(declare, PopulateClientSpamTrainingDataService, "tutanota/populateclientspamtrainingdataservice", 99);
|
||||
crate::service_impl!(POST, PopulateClientSpamTrainingDataService, PopulateClientSpamTrainingDataPostIn, ());
|
||||
|
||||
|
||||
pub struct ProcessInboxService;
|
||||
|
||||
crate::service_impl!(declare, ProcessInboxService, "tutanota/processinboxservice", 98);
|
||||
crate::service_impl!(declare, ProcessInboxService, "tutanota/processinboxservice", 99);
|
||||
crate::service_impl!(POST, ProcessInboxService, ProcessInboxPostIn, ());
|
||||
|
||||
|
||||
pub struct ReceiveInfoService;
|
||||
|
||||
crate::service_impl!(declare, ReceiveInfoService, "tutanota/receiveinfoservice", 98);
|
||||
crate::service_impl!(declare, ReceiveInfoService, "tutanota/receiveinfoservice", 99);
|
||||
crate::service_impl!(POST, ReceiveInfoService, ReceiveInfoServiceData, ReceiveInfoServicePostOut);
|
||||
|
||||
|
||||
pub struct ReportMailService;
|
||||
|
||||
crate::service_impl!(declare, ReportMailService, "tutanota/reportmailservice", 98);
|
||||
crate::service_impl!(declare, ReportMailService, "tutanota/reportmailservice", 99);
|
||||
crate::service_impl!(POST, ReportMailService, ReportMailPostData, ());
|
||||
|
||||
|
||||
pub struct ResolveConversationsService;
|
||||
|
||||
crate::service_impl!(declare, ResolveConversationsService, "tutanota/resolveconversationsservice", 98);
|
||||
crate::service_impl!(declare, ResolveConversationsService, "tutanota/resolveconversationsservice", 99);
|
||||
crate::service_impl!(GET, ResolveConversationsService, ResolveConversationsServiceGetIn, ResolveConversationsServiceGetOut);
|
||||
|
||||
|
||||
pub struct SendDraftService;
|
||||
|
||||
crate::service_impl!(declare, SendDraftService, "tutanota/senddraftservice", 98);
|
||||
crate::service_impl!(declare, SendDraftService, "tutanota/senddraftservice", 99);
|
||||
crate::service_impl!(POST, SendDraftService, SendDraftData, SendDraftReturn);
|
||||
|
||||
|
||||
pub struct SimpleMoveMailService;
|
||||
|
||||
crate::service_impl!(declare, SimpleMoveMailService, "tutanota/simplemovemailservice", 98);
|
||||
crate::service_impl!(declare, SimpleMoveMailService, "tutanota/simplemovemailservice", 99);
|
||||
crate::service_impl!(POST, SimpleMoveMailService, SimpleMoveMailPostIn, MoveMailPostOut);
|
||||
|
||||
|
||||
pub struct TemplateGroupService;
|
||||
|
||||
crate::service_impl!(declare, TemplateGroupService, "tutanota/templategroupservice", 98);
|
||||
crate::service_impl!(declare, TemplateGroupService, "tutanota/templategroupservice", 99);
|
||||
crate::service_impl!(POST, TemplateGroupService, UserAreaGroupPostData, CreateGroupPostReturn);
|
||||
crate::service_impl!(DELETE, TemplateGroupService, UserAreaGroupDeleteData, ());
|
||||
|
||||
|
||||
pub struct TranslationService;
|
||||
|
||||
crate::service_impl!(declare, TranslationService, "tutanota/translationservice", 98);
|
||||
crate::service_impl!(declare, TranslationService, "tutanota/translationservice", 99);
|
||||
crate::service_impl!(GET, TranslationService, TranslationGetIn, TranslationGetOut);
|
||||
|
||||
|
||||
pub struct UnreadMailStateService;
|
||||
|
||||
crate::service_impl!(declare, UnreadMailStateService, "tutanota/unreadmailstateservice", 98);
|
||||
crate::service_impl!(declare, UnreadMailStateService, "tutanota/unreadmailstateservice", 99);
|
||||
crate::service_impl!(POST, UnreadMailStateService, UnreadMailStatePostIn, ());
|
||||
|
||||
|
||||
pub struct UserAccountService;
|
||||
|
||||
crate::service_impl!(declare, UserAccountService, "tutanota/useraccountservice", 98);
|
||||
crate::service_impl!(declare, UserAccountService, "tutanota/useraccountservice", 99);
|
||||
crate::service_impl!(POST, UserAccountService, UserAccountCreateData, UserAccountPostOut);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"12": {
|
||||
"name": "ReadCounterData",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 1,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 12,
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
"16": {
|
||||
"name": "ReadCounterReturn",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 1,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 16,
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
"49": {
|
||||
"name": "WriteCounterData",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 4,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 49,
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
"221": {
|
||||
"name": "ApprovalMail",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 14,
|
||||
"type": "LIST_ELEMENT_TYPE",
|
||||
"id": 221,
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
"300": {
|
||||
"name": "CounterValue",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 22,
|
||||
"type": "AGGREGATED_TYPE",
|
||||
"id": 300,
|
||||
|
|
@ -265,7 +265,7 @@
|
|||
"305": {
|
||||
"name": "ErrorReportFile",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 23,
|
||||
"type": "AGGREGATED_TYPE",
|
||||
"id": 305,
|
||||
|
|
@ -304,7 +304,7 @@
|
|||
"316": {
|
||||
"name": "ErrorReportData",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 23,
|
||||
"type": "AGGREGATED_TYPE",
|
||||
"id": 316,
|
||||
|
|
@ -399,7 +399,7 @@
|
|||
"335": {
|
||||
"name": "ReportErrorIn",
|
||||
"app": "monitor",
|
||||
"version": 36,
|
||||
"version": 37,
|
||||
"since": 23,
|
||||
"type": "DATA_TRANSFER_TYPE",
|
||||
"id": 335,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue