Disallow Partial instance initializers

Co-authored-by: @paw-hub, @mpfau, @vaf-hub
tutanota#6118
This commit is contained in:
vis 2023-11-10 16:59:39 +01:00 committed by ganthern
parent af9d0e668c
commit 16a5590760
109 changed files with 1963 additions and 1414 deletions

View file

@ -66,4 +66,5 @@ export interface BlobElementEntity extends Entity, BlobElement {
_ownerGroup: null | Id _ownerGroup: null | Id
} }
// FIXME ask willow about Entity
export type SomeEntity = ElementEntity | ListElementEntity | BlobElementEntity export type SomeEntity = ElementEntity | ListElementEntity | BlobElementEntity

View file

@ -20,7 +20,7 @@ export function isoDateToBirthday(birthdayIso: string): Birthday {
//return new Date(Number(newBirthday.year), Number(newBirthday.month) - 1, Number(newBirthday.day)) //return new Date(Number(newBirthday.year), Number(newBirthday.month) - 1, Number(newBirthday.day))
const birthdayInitializer: Partial<Birthday> = {} const birthdayInitializer: Partial<Birthday> = {}
if (birthdayIso.startsWith("--")) { if (birthdayIso.startsWith("--")) {
const monthAndDay = birthdayIso.substr(2).split("-") const monthAndDay = birthdayIso.substring(2).split("-")
if (monthAndDay.length !== 2) { if (monthAndDay.length !== 2) {
throw new ParsingError("invalid birthday without year: " + birthdayIso) throw new ParsingError("invalid birthday without year: " + birthdayIso)
@ -41,16 +41,14 @@ export function isoDateToBirthday(birthdayIso: string): Birthday {
birthdayInitializer.day = yearMonthAndDay[2] birthdayInitializer.day = yearMonthAndDay[2]
} }
const birthday = createBirthday(birthdayInitializer) if (!isValidBirthday(birthdayInitializer)) {
if (!isValidBirthday(birthday)) {
throw new ParsingError("Invalid birthday format: " + birthdayIso) throw new ParsingError("Invalid birthday format: " + birthdayIso)
} }
return birthday return createBirthday(birthdayInitializer)
} }
export function isValidBirthday(birthday: Birthday): boolean { export function isValidBirthday(birthday: Partial<Birthday>): birthday is Birthday {
const day = Number(birthday.day) const day = Number(birthday.day)
const month = Number(birthday.month) const month = Number(birthday.month)
const year = birthday.year ? Number(birthday.year) : null const year = birthday.year ? Number(birthday.year) : null

View file

@ -15,7 +15,7 @@ import {
utf8Uint8ArrayToString, utf8Uint8ArrayToString,
} from "@tutao/tutanota-utils" } from "@tutao/tutanota-utils"
import { Cardinality, ValueType } from "../EntityConstants" import { Cardinality, ValueType } from "../EntityConstants"
import type { ModelValue, SomeEntity, TypeModel } from "../EntityTypes" import type { Entity, ModelValue, SomeEntity, TypeModel } from "../EntityTypes"
import { ElementEntity } from "../EntityTypes" import { ElementEntity } from "../EntityTypes"
import { ProgrammingError } from "../error/ProgrammingError.js" import { ProgrammingError } from "../error/ProgrammingError.js"
@ -60,9 +60,41 @@ export const POST_MULTIPLE_LIMIT = 100
*/ */
export type Stripped<T extends Partial<SomeEntity>> = Omit< export type Stripped<T extends Partial<SomeEntity>> = Omit<
T, T,
"_id" | "_ownerGroup" | "_ownerEncSessionKey" | "_permissions" | "_errors" | "_format" | "_type" | `_finalEncrypted${string}` | `_defaultEncrypted${string}` | "_id"
| "_area"
| "_owner"
| "_ownerGroup"
| "_ownerEncSessionKey"
| "_permissions"
| "_errors"
| "_format"
| "_type"
| `_finalEncrypted${string}`
| `_defaultEncrypted${string}`
> >
type OptionalEntity<T extends Entity> = T & {
_id?: Id | IdTuple
_ownerGroup?: Id
}
export type StrippedEntity<T extends Entity> =
| Omit<
T,
| "_id"
| "_ownerGroup"
| "_ownerEncSessionKey"
| "_permissions"
| "_errors"
| "_format"
| "_type"
| "_area"
| "_owner"
| `_finalEncrypted${string}`
| `_defaultEncrypted${string}`
>
| OptionalEntity<T>
/** /**
* Tests if one id is bigger than another. * Tests if one id is bigger than another.
* For generated IDs we use base64ext which is sortable. * For generated IDs we use base64ext which is sortable.
@ -371,7 +403,7 @@ export function removeTechnicalFields<E extends Partial<SomeEntity>>(entity: E)
* get a clone of a (partial) entity that does not contain any fields that would indicate that it was ever persisted anywhere. * get a clone of a (partial) entity that does not contain any fields that would indicate that it was ever persisted anywhere.
* @param entity the entity to strip * @param entity the entity to strip
*/ */
export function getStrippedClone<E extends SomeEntity>(entity: Partial<E>): Stripped<Partial<E>> { export function getStrippedClone<E extends SomeEntity>(entity: StrippedEntity<E>): Stripped<E> {
const cloned = clone(entity) const cloned = clone(entity)
removeTechnicalFields(cloned) removeTechnicalFields(cloned)
removeIdentityFields(cloned) removeIdentityFields(cloned)

View file

@ -1,11 +1,11 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"
export const CustomerAccountPostingTypeRef: TypeRef<CustomerAccountPosting> = new TypeRef("accounting", "CustomerAccountPosting") export const CustomerAccountPostingTypeRef: TypeRef<CustomerAccountPosting> = new TypeRef("accounting", "CustomerAccountPosting")
export function createCustomerAccountPosting(values: Partial<CustomerAccountPosting>): CustomerAccountPosting { export function createCustomerAccountPosting(values: StrippedEntity<CustomerAccountPosting>): CustomerAccountPosting {
return Object.assign(create(typeModels.CustomerAccountPosting, CustomerAccountPostingTypeRef), values) return Object.assign(create(typeModels.CustomerAccountPosting, CustomerAccountPostingTypeRef), values)
} }
@ -20,7 +20,7 @@ export type CustomerAccountPosting = {
} }
export const CustomerAccountReturnTypeRef: TypeRef<CustomerAccountReturn> = new TypeRef("accounting", "CustomerAccountReturn") export const CustomerAccountReturnTypeRef: TypeRef<CustomerAccountReturn> = new TypeRef("accounting", "CustomerAccountReturn")
export function createCustomerAccountReturn(values: Partial<CustomerAccountReturn>): CustomerAccountReturn { export function createCustomerAccountReturn(values: StrippedEntity<CustomerAccountReturn>): CustomerAccountReturn {
return Object.assign(create(typeModels.CustomerAccountReturn, CustomerAccountReturnTypeRef), values) return Object.assign(create(typeModels.CustomerAccountReturn, CustomerAccountReturnTypeRef), values)
} }

View file

@ -1,11 +1,11 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"
export const PersistenceResourcePostReturnTypeRef: TypeRef<PersistenceResourcePostReturn> = new TypeRef("base", "PersistenceResourcePostReturn") export const PersistenceResourcePostReturnTypeRef: TypeRef<PersistenceResourcePostReturn> = new TypeRef("base", "PersistenceResourcePostReturn")
export function createPersistenceResourcePostReturn(values: Partial<PersistenceResourcePostReturn>): PersistenceResourcePostReturn { export function createPersistenceResourcePostReturn(values: StrippedEntity<PersistenceResourcePostReturn>): PersistenceResourcePostReturn {
return Object.assign(create(typeModels.PersistenceResourcePostReturn, PersistenceResourcePostReturnTypeRef), values) return Object.assign(create(typeModels.PersistenceResourcePostReturn, PersistenceResourcePostReturnTypeRef), values)
} }

View file

@ -1,4 +1,4 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"

View file

@ -1,11 +1,11 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"
export const ApprovalMailTypeRef: TypeRef<ApprovalMail> = new TypeRef("monitor", "ApprovalMail") export const ApprovalMailTypeRef: TypeRef<ApprovalMail> = new TypeRef("monitor", "ApprovalMail")
export function createApprovalMail(values: Partial<ApprovalMail>): ApprovalMail { export function createApprovalMail(values: StrippedEntity<ApprovalMail>): ApprovalMail {
return Object.assign(create(typeModels.ApprovalMail, ApprovalMailTypeRef), values) return Object.assign(create(typeModels.ApprovalMail, ApprovalMailTypeRef), values)
} }
@ -24,7 +24,7 @@ export type ApprovalMail = {
} }
export const CounterValueTypeRef: TypeRef<CounterValue> = new TypeRef("monitor", "CounterValue") export const CounterValueTypeRef: TypeRef<CounterValue> = new TypeRef("monitor", "CounterValue")
export function createCounterValue(values: Partial<CounterValue>): CounterValue { export function createCounterValue(values: StrippedEntity<CounterValue>): CounterValue {
return Object.assign(create(typeModels.CounterValue, CounterValueTypeRef), values) return Object.assign(create(typeModels.CounterValue, CounterValueTypeRef), values)
} }
@ -37,7 +37,7 @@ export type CounterValue = {
} }
export const ReadCounterDataTypeRef: TypeRef<ReadCounterData> = new TypeRef("monitor", "ReadCounterData") export const ReadCounterDataTypeRef: TypeRef<ReadCounterData> = new TypeRef("monitor", "ReadCounterData")
export function createReadCounterData(values: Partial<ReadCounterData>): ReadCounterData { export function createReadCounterData(values: StrippedEntity<ReadCounterData>): ReadCounterData {
return Object.assign(create(typeModels.ReadCounterData, ReadCounterDataTypeRef), values) return Object.assign(create(typeModels.ReadCounterData, ReadCounterDataTypeRef), values)
} }
@ -51,7 +51,7 @@ export type ReadCounterData = {
} }
export const ReadCounterReturnTypeRef: TypeRef<ReadCounterReturn> = new TypeRef("monitor", "ReadCounterReturn") export const ReadCounterReturnTypeRef: TypeRef<ReadCounterReturn> = new TypeRef("monitor", "ReadCounterReturn")
export function createReadCounterReturn(values: Partial<ReadCounterReturn>): ReadCounterReturn { export function createReadCounterReturn(values: StrippedEntity<ReadCounterReturn>): ReadCounterReturn {
return Object.assign(create(typeModels.ReadCounterReturn, ReadCounterReturnTypeRef), values) return Object.assign(create(typeModels.ReadCounterReturn, ReadCounterReturnTypeRef), values)
} }
@ -65,7 +65,7 @@ export type ReadCounterReturn = {
} }
export const WriteCounterDataTypeRef: TypeRef<WriteCounterData> = new TypeRef("monitor", "WriteCounterData") export const WriteCounterDataTypeRef: TypeRef<WriteCounterData> = new TypeRef("monitor", "WriteCounterData")
export function createWriteCounterData(values: Partial<WriteCounterData>): WriteCounterData { export function createWriteCounterData(values: StrippedEntity<WriteCounterData>): WriteCounterData {
return Object.assign(create(typeModels.WriteCounterData, WriteCounterDataTypeRef), values) return Object.assign(create(typeModels.WriteCounterData, WriteCounterDataTypeRef), values)
} }

View file

@ -1,4 +1,4 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"
import {Blob} from '../sys/TypeRefs.js' import {Blob} from '../sys/TypeRefs.js'
@ -6,7 +6,7 @@ import {BlobReferenceTokenWrapper} from '../sys/TypeRefs.js'
export const BlobAccessTokenPostInTypeRef: TypeRef<BlobAccessTokenPostIn> = new TypeRef("storage", "BlobAccessTokenPostIn") export const BlobAccessTokenPostInTypeRef: TypeRef<BlobAccessTokenPostIn> = new TypeRef("storage", "BlobAccessTokenPostIn")
export function createBlobAccessTokenPostIn(values: Partial<BlobAccessTokenPostIn>): BlobAccessTokenPostIn { export function createBlobAccessTokenPostIn(values: StrippedEntity<BlobAccessTokenPostIn>): BlobAccessTokenPostIn {
return Object.assign(create(typeModels.BlobAccessTokenPostIn, BlobAccessTokenPostInTypeRef), values) return Object.assign(create(typeModels.BlobAccessTokenPostIn, BlobAccessTokenPostInTypeRef), values)
} }
@ -21,7 +21,7 @@ export type BlobAccessTokenPostIn = {
} }
export const BlobAccessTokenPostOutTypeRef: TypeRef<BlobAccessTokenPostOut> = new TypeRef("storage", "BlobAccessTokenPostOut") export const BlobAccessTokenPostOutTypeRef: TypeRef<BlobAccessTokenPostOut> = new TypeRef("storage", "BlobAccessTokenPostOut")
export function createBlobAccessTokenPostOut(values: Partial<BlobAccessTokenPostOut>): BlobAccessTokenPostOut { export function createBlobAccessTokenPostOut(values: StrippedEntity<BlobAccessTokenPostOut>): BlobAccessTokenPostOut {
return Object.assign(create(typeModels.BlobAccessTokenPostOut, BlobAccessTokenPostOutTypeRef), values) return Object.assign(create(typeModels.BlobAccessTokenPostOut, BlobAccessTokenPostOutTypeRef), values)
} }
@ -34,7 +34,7 @@ export type BlobAccessTokenPostOut = {
} }
export const BlobArchiveRefTypeRef: TypeRef<BlobArchiveRef> = new TypeRef("storage", "BlobArchiveRef") export const BlobArchiveRefTypeRef: TypeRef<BlobArchiveRef> = new TypeRef("storage", "BlobArchiveRef")
export function createBlobArchiveRef(values: Partial<BlobArchiveRef>): BlobArchiveRef { export function createBlobArchiveRef(values: StrippedEntity<BlobArchiveRef>): BlobArchiveRef {
return Object.assign(create(typeModels.BlobArchiveRef, BlobArchiveRefTypeRef), values) return Object.assign(create(typeModels.BlobArchiveRef, BlobArchiveRefTypeRef), values)
} }
@ -50,7 +50,7 @@ export type BlobArchiveRef = {
} }
export const BlobGetInTypeRef: TypeRef<BlobGetIn> = new TypeRef("storage", "BlobGetIn") export const BlobGetInTypeRef: TypeRef<BlobGetIn> = new TypeRef("storage", "BlobGetIn")
export function createBlobGetIn(values: Partial<BlobGetIn>): BlobGetIn { export function createBlobGetIn(values: StrippedEntity<BlobGetIn>): BlobGetIn {
return Object.assign(create(typeModels.BlobGetIn, BlobGetInTypeRef), values) return Object.assign(create(typeModels.BlobGetIn, BlobGetInTypeRef), values)
} }
@ -65,7 +65,7 @@ export type BlobGetIn = {
} }
export const BlobIdTypeRef: TypeRef<BlobId> = new TypeRef("storage", "BlobId") export const BlobIdTypeRef: TypeRef<BlobId> = new TypeRef("storage", "BlobId")
export function createBlobId(values: Partial<BlobId>): BlobId { export function createBlobId(values: StrippedEntity<BlobId>): BlobId {
return Object.assign(create(typeModels.BlobId, BlobIdTypeRef), values) return Object.assign(create(typeModels.BlobId, BlobIdTypeRef), values)
} }
@ -77,7 +77,7 @@ export type BlobId = {
} }
export const BlobPostOutTypeRef: TypeRef<BlobPostOut> = new TypeRef("storage", "BlobPostOut") export const BlobPostOutTypeRef: TypeRef<BlobPostOut> = new TypeRef("storage", "BlobPostOut")
export function createBlobPostOut(values: Partial<BlobPostOut>): BlobPostOut { export function createBlobPostOut(values: StrippedEntity<BlobPostOut>): BlobPostOut {
return Object.assign(create(typeModels.BlobPostOut, BlobPostOutTypeRef), values) return Object.assign(create(typeModels.BlobPostOut, BlobPostOutTypeRef), values)
} }
@ -89,7 +89,7 @@ export type BlobPostOut = {
} }
export const BlobReadDataTypeRef: TypeRef<BlobReadData> = new TypeRef("storage", "BlobReadData") export const BlobReadDataTypeRef: TypeRef<BlobReadData> = new TypeRef("storage", "BlobReadData")
export function createBlobReadData(values: Partial<BlobReadData>): BlobReadData { export function createBlobReadData(values: StrippedEntity<BlobReadData>): BlobReadData {
return Object.assign(create(typeModels.BlobReadData, BlobReadDataTypeRef), values) return Object.assign(create(typeModels.BlobReadData, BlobReadDataTypeRef), values)
} }
@ -104,7 +104,7 @@ export type BlobReadData = {
} }
export const BlobReferenceDeleteInTypeRef: TypeRef<BlobReferenceDeleteIn> = new TypeRef("storage", "BlobReferenceDeleteIn") export const BlobReferenceDeleteInTypeRef: TypeRef<BlobReferenceDeleteIn> = new TypeRef("storage", "BlobReferenceDeleteIn")
export function createBlobReferenceDeleteIn(values: Partial<BlobReferenceDeleteIn>): BlobReferenceDeleteIn { export function createBlobReferenceDeleteIn(values: StrippedEntity<BlobReferenceDeleteIn>): BlobReferenceDeleteIn {
return Object.assign(create(typeModels.BlobReferenceDeleteIn, BlobReferenceDeleteInTypeRef), values) return Object.assign(create(typeModels.BlobReferenceDeleteIn, BlobReferenceDeleteInTypeRef), values)
} }
@ -120,7 +120,7 @@ export type BlobReferenceDeleteIn = {
} }
export const BlobReferencePutInTypeRef: TypeRef<BlobReferencePutIn> = new TypeRef("storage", "BlobReferencePutIn") export const BlobReferencePutInTypeRef: TypeRef<BlobReferencePutIn> = new TypeRef("storage", "BlobReferencePutIn")
export function createBlobReferencePutIn(values: Partial<BlobReferencePutIn>): BlobReferencePutIn { export function createBlobReferencePutIn(values: StrippedEntity<BlobReferencePutIn>): BlobReferencePutIn {
return Object.assign(create(typeModels.BlobReferencePutIn, BlobReferencePutInTypeRef), values) return Object.assign(create(typeModels.BlobReferencePutIn, BlobReferencePutInTypeRef), values)
} }
@ -136,7 +136,7 @@ export type BlobReferencePutIn = {
} }
export const BlobServerAccessInfoTypeRef: TypeRef<BlobServerAccessInfo> = new TypeRef("storage", "BlobServerAccessInfo") export const BlobServerAccessInfoTypeRef: TypeRef<BlobServerAccessInfo> = new TypeRef("storage", "BlobServerAccessInfo")
export function createBlobServerAccessInfo(values: Partial<BlobServerAccessInfo>): BlobServerAccessInfo { export function createBlobServerAccessInfo(values: StrippedEntity<BlobServerAccessInfo>): BlobServerAccessInfo {
return Object.assign(create(typeModels.BlobServerAccessInfo, BlobServerAccessInfoTypeRef), values) return Object.assign(create(typeModels.BlobServerAccessInfo, BlobServerAccessInfoTypeRef), values)
} }
@ -151,7 +151,7 @@ export type BlobServerAccessInfo = {
} }
export const BlobServerUrlTypeRef: TypeRef<BlobServerUrl> = new TypeRef("storage", "BlobServerUrl") export const BlobServerUrlTypeRef: TypeRef<BlobServerUrl> = new TypeRef("storage", "BlobServerUrl")
export function createBlobServerUrl(values: Partial<BlobServerUrl>): BlobServerUrl { export function createBlobServerUrl(values: StrippedEntity<BlobServerUrl>): BlobServerUrl {
return Object.assign(create(typeModels.BlobServerUrl, BlobServerUrlTypeRef), values) return Object.assign(create(typeModels.BlobServerUrl, BlobServerUrlTypeRef), values)
} }
@ -163,7 +163,7 @@ export type BlobServerUrl = {
} }
export const BlobWriteDataTypeRef: TypeRef<BlobWriteData> = new TypeRef("storage", "BlobWriteData") export const BlobWriteDataTypeRef: TypeRef<BlobWriteData> = new TypeRef("storage", "BlobWriteData")
export function createBlobWriteData(values: Partial<BlobWriteData>): BlobWriteData { export function createBlobWriteData(values: StrippedEntity<BlobWriteData>): BlobWriteData {
return Object.assign(create(typeModels.BlobWriteData, BlobWriteDataTypeRef), values) return Object.assign(create(typeModels.BlobWriteData, BlobWriteDataTypeRef), values)
} }
@ -175,7 +175,7 @@ export type BlobWriteData = {
} }
export const InstanceIdTypeRef: TypeRef<InstanceId> = new TypeRef("storage", "InstanceId") export const InstanceIdTypeRef: TypeRef<InstanceId> = new TypeRef("storage", "InstanceId")
export function createInstanceId(values: Partial<InstanceId>): InstanceId { export function createInstanceId(values: StrippedEntity<InstanceId>): InstanceId {
return Object.assign(create(typeModels.InstanceId, InstanceIdTypeRef), values) return Object.assign(create(typeModels.InstanceId, InstanceIdTypeRef), values)
} }

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"
import {DateWrapper} from '../sys/TypeRefs.js' import {DateWrapper} from '../sys/TypeRefs.js'
@ -8,7 +8,7 @@ import {BlobReferenceTokenWrapper} from '../sys/TypeRefs.js'
export const AttachmentKeyDataTypeRef: TypeRef<AttachmentKeyData> = new TypeRef("tutanota", "AttachmentKeyData") export const AttachmentKeyDataTypeRef: TypeRef<AttachmentKeyData> = new TypeRef("tutanota", "AttachmentKeyData")
export function createAttachmentKeyData(values: Partial<AttachmentKeyData>): AttachmentKeyData { export function createAttachmentKeyData(values: StrippedEntity<AttachmentKeyData>): AttachmentKeyData {
return Object.assign(create(typeModels.AttachmentKeyData, AttachmentKeyDataTypeRef), values) return Object.assign(create(typeModels.AttachmentKeyData, AttachmentKeyDataTypeRef), values)
} }
@ -23,7 +23,7 @@ export type AttachmentKeyData = {
} }
export const BirthdayTypeRef: TypeRef<Birthday> = new TypeRef("tutanota", "Birthday") export const BirthdayTypeRef: TypeRef<Birthday> = new TypeRef("tutanota", "Birthday")
export function createBirthday(values: Partial<Birthday>): Birthday { export function createBirthday(values: StrippedEntity<Birthday>): Birthday {
return Object.assign(create(typeModels.Birthday, BirthdayTypeRef), values) return Object.assign(create(typeModels.Birthday, BirthdayTypeRef), values)
} }
@ -37,7 +37,7 @@ export type Birthday = {
} }
export const BodyTypeRef: TypeRef<Body> = new TypeRef("tutanota", "Body") export const BodyTypeRef: TypeRef<Body> = new TypeRef("tutanota", "Body")
export function createBody(values: Partial<Body>): Body { export function createBody(values: StrippedEntity<Body>): Body {
return Object.assign(create(typeModels.Body, BodyTypeRef), values) return Object.assign(create(typeModels.Body, BodyTypeRef), values)
} }
@ -50,7 +50,7 @@ export type Body = {
} }
export const CalendarDeleteDataTypeRef: TypeRef<CalendarDeleteData> = new TypeRef("tutanota", "CalendarDeleteData") export const CalendarDeleteDataTypeRef: TypeRef<CalendarDeleteData> = new TypeRef("tutanota", "CalendarDeleteData")
export function createCalendarDeleteData(values: Partial<CalendarDeleteData>): CalendarDeleteData { export function createCalendarDeleteData(values: StrippedEntity<CalendarDeleteData>): CalendarDeleteData {
return Object.assign(create(typeModels.CalendarDeleteData, CalendarDeleteDataTypeRef), values) return Object.assign(create(typeModels.CalendarDeleteData, CalendarDeleteDataTypeRef), values)
} }
@ -63,7 +63,7 @@ export type CalendarDeleteData = {
} }
export const CalendarEventTypeRef: TypeRef<CalendarEvent> = new TypeRef("tutanota", "CalendarEvent") export const CalendarEventTypeRef: TypeRef<CalendarEvent> = new TypeRef("tutanota", "CalendarEvent")
export function createCalendarEvent(values: Partial<CalendarEvent>): CalendarEvent { export function createCalendarEvent(values: StrippedEntity<CalendarEvent>): CalendarEvent {
return Object.assign(create(typeModels.CalendarEvent, CalendarEventTypeRef), values) return Object.assign(create(typeModels.CalendarEvent, CalendarEventTypeRef), values)
} }
@ -94,7 +94,7 @@ export type CalendarEvent = {
} }
export const CalendarEventAttendeeTypeRef: TypeRef<CalendarEventAttendee> = new TypeRef("tutanota", "CalendarEventAttendee") export const CalendarEventAttendeeTypeRef: TypeRef<CalendarEventAttendee> = new TypeRef("tutanota", "CalendarEventAttendee")
export function createCalendarEventAttendee(values: Partial<CalendarEventAttendee>): CalendarEventAttendee { export function createCalendarEventAttendee(values: StrippedEntity<CalendarEventAttendee>): CalendarEventAttendee {
return Object.assign(create(typeModels.CalendarEventAttendee, CalendarEventAttendeeTypeRef), values) return Object.assign(create(typeModels.CalendarEventAttendee, CalendarEventAttendeeTypeRef), values)
} }
@ -108,7 +108,7 @@ export type CalendarEventAttendee = {
} }
export const CalendarEventIndexRefTypeRef: TypeRef<CalendarEventIndexRef> = new TypeRef("tutanota", "CalendarEventIndexRef") export const CalendarEventIndexRefTypeRef: TypeRef<CalendarEventIndexRef> = new TypeRef("tutanota", "CalendarEventIndexRef")
export function createCalendarEventIndexRef(values: Partial<CalendarEventIndexRef>): CalendarEventIndexRef { export function createCalendarEventIndexRef(values: StrippedEntity<CalendarEventIndexRef>): CalendarEventIndexRef {
return Object.assign(create(typeModels.CalendarEventIndexRef, CalendarEventIndexRefTypeRef), values) return Object.assign(create(typeModels.CalendarEventIndexRef, CalendarEventIndexRefTypeRef), values)
} }
@ -121,7 +121,7 @@ export type CalendarEventIndexRef = {
} }
export const CalendarEventUidIndexTypeRef: TypeRef<CalendarEventUidIndex> = new TypeRef("tutanota", "CalendarEventUidIndex") export const CalendarEventUidIndexTypeRef: TypeRef<CalendarEventUidIndex> = new TypeRef("tutanota", "CalendarEventUidIndex")
export function createCalendarEventUidIndex(values: Partial<CalendarEventUidIndex>): CalendarEventUidIndex { export function createCalendarEventUidIndex(values: StrippedEntity<CalendarEventUidIndex>): CalendarEventUidIndex {
return Object.assign(create(typeModels.CalendarEventUidIndex, CalendarEventUidIndexTypeRef), values) return Object.assign(create(typeModels.CalendarEventUidIndex, CalendarEventUidIndexTypeRef), values)
} }
@ -138,7 +138,7 @@ export type CalendarEventUidIndex = {
} }
export const CalendarEventUpdateTypeRef: TypeRef<CalendarEventUpdate> = new TypeRef("tutanota", "CalendarEventUpdate") export const CalendarEventUpdateTypeRef: TypeRef<CalendarEventUpdate> = new TypeRef("tutanota", "CalendarEventUpdate")
export function createCalendarEventUpdate(values: Partial<CalendarEventUpdate>): CalendarEventUpdate { export function createCalendarEventUpdate(values: StrippedEntity<CalendarEventUpdate>): CalendarEventUpdate {
return Object.assign(create(typeModels.CalendarEventUpdate, CalendarEventUpdateTypeRef), values) return Object.assign(create(typeModels.CalendarEventUpdate, CalendarEventUpdateTypeRef), values)
} }
@ -157,7 +157,7 @@ export type CalendarEventUpdate = {
} }
export const CalendarEventUpdateListTypeRef: TypeRef<CalendarEventUpdateList> = new TypeRef("tutanota", "CalendarEventUpdateList") export const CalendarEventUpdateListTypeRef: TypeRef<CalendarEventUpdateList> = new TypeRef("tutanota", "CalendarEventUpdateList")
export function createCalendarEventUpdateList(values: Partial<CalendarEventUpdateList>): CalendarEventUpdateList { export function createCalendarEventUpdateList(values: StrippedEntity<CalendarEventUpdateList>): CalendarEventUpdateList {
return Object.assign(create(typeModels.CalendarEventUpdateList, CalendarEventUpdateListTypeRef), values) return Object.assign(create(typeModels.CalendarEventUpdateList, CalendarEventUpdateListTypeRef), values)
} }
@ -170,7 +170,7 @@ export type CalendarEventUpdateList = {
} }
export const CalendarGroupRootTypeRef: TypeRef<CalendarGroupRoot> = new TypeRef("tutanota", "CalendarGroupRoot") export const CalendarGroupRootTypeRef: TypeRef<CalendarGroupRoot> = new TypeRef("tutanota", "CalendarGroupRoot")
export function createCalendarGroupRoot(values: Partial<CalendarGroupRoot>): CalendarGroupRoot { export function createCalendarGroupRoot(values: StrippedEntity<CalendarGroupRoot>): CalendarGroupRoot {
return Object.assign(create(typeModels.CalendarGroupRoot, CalendarGroupRootTypeRef), values) return Object.assign(create(typeModels.CalendarGroupRoot, CalendarGroupRootTypeRef), values)
} }
@ -190,7 +190,7 @@ export type CalendarGroupRoot = {
} }
export const CalendarRepeatRuleTypeRef: TypeRef<CalendarRepeatRule> = new TypeRef("tutanota", "CalendarRepeatRule") export const CalendarRepeatRuleTypeRef: TypeRef<CalendarRepeatRule> = new TypeRef("tutanota", "CalendarRepeatRule")
export function createCalendarRepeatRule(values: Partial<CalendarRepeatRule>): CalendarRepeatRule { export function createCalendarRepeatRule(values: StrippedEntity<CalendarRepeatRule>): CalendarRepeatRule {
return Object.assign(create(typeModels.CalendarRepeatRule, CalendarRepeatRuleTypeRef), values) return Object.assign(create(typeModels.CalendarRepeatRule, CalendarRepeatRuleTypeRef), values)
} }
@ -208,7 +208,7 @@ export type CalendarRepeatRule = {
} }
export const ContactTypeRef: TypeRef<Contact> = new TypeRef("tutanota", "Contact") export const ContactTypeRef: TypeRef<Contact> = new TypeRef("tutanota", "Contact")
export function createContact(values: Partial<Contact>): Contact { export function createContact(values: StrippedEntity<Contact>): Contact {
return Object.assign(create(typeModels.Contact, ContactTypeRef), values) return Object.assign(create(typeModels.Contact, ContactTypeRef), values)
} }
@ -244,7 +244,7 @@ export type Contact = {
} }
export const ContactAddressTypeRef: TypeRef<ContactAddress> = new TypeRef("tutanota", "ContactAddress") export const ContactAddressTypeRef: TypeRef<ContactAddress> = new TypeRef("tutanota", "ContactAddress")
export function createContactAddress(values: Partial<ContactAddress>): ContactAddress { export function createContactAddress(values: StrippedEntity<ContactAddress>): ContactAddress {
return Object.assign(create(typeModels.ContactAddress, ContactAddressTypeRef), values) return Object.assign(create(typeModels.ContactAddress, ContactAddressTypeRef), values)
} }
@ -258,7 +258,7 @@ export type ContactAddress = {
} }
export const ContactListTypeRef: TypeRef<ContactList> = new TypeRef("tutanota", "ContactList") export const ContactListTypeRef: TypeRef<ContactList> = new TypeRef("tutanota", "ContactList")
export function createContactList(values: Partial<ContactList>): ContactList { export function createContactList(values: StrippedEntity<ContactList>): ContactList {
return Object.assign(create(typeModels.ContactList, ContactListTypeRef), values) return Object.assign(create(typeModels.ContactList, ContactListTypeRef), values)
} }
@ -277,7 +277,7 @@ export type ContactList = {
} }
export const ContactListEntryTypeRef: TypeRef<ContactListEntry> = new TypeRef("tutanota", "ContactListEntry") export const ContactListEntryTypeRef: TypeRef<ContactListEntry> = new TypeRef("tutanota", "ContactListEntry")
export function createContactListEntry(values: Partial<ContactListEntry>): ContactListEntry { export function createContactListEntry(values: StrippedEntity<ContactListEntry>): ContactListEntry {
return Object.assign(create(typeModels.ContactListEntry, ContactListEntryTypeRef), values) return Object.assign(create(typeModels.ContactListEntry, ContactListEntryTypeRef), values)
} }
@ -294,7 +294,7 @@ export type ContactListEntry = {
} }
export const ContactListGroupRootTypeRef: TypeRef<ContactListGroupRoot> = new TypeRef("tutanota", "ContactListGroupRoot") export const ContactListGroupRootTypeRef: TypeRef<ContactListGroupRoot> = new TypeRef("tutanota", "ContactListGroupRoot")
export function createContactListGroupRoot(values: Partial<ContactListGroupRoot>): ContactListGroupRoot { export function createContactListGroupRoot(values: StrippedEntity<ContactListGroupRoot>): ContactListGroupRoot {
return Object.assign(create(typeModels.ContactListGroupRoot, ContactListGroupRootTypeRef), values) return Object.assign(create(typeModels.ContactListGroupRoot, ContactListGroupRootTypeRef), values)
} }
@ -312,7 +312,7 @@ export type ContactListGroupRoot = {
} }
export const ContactMailAddressTypeRef: TypeRef<ContactMailAddress> = new TypeRef("tutanota", "ContactMailAddress") export const ContactMailAddressTypeRef: TypeRef<ContactMailAddress> = new TypeRef("tutanota", "ContactMailAddress")
export function createContactMailAddress(values: Partial<ContactMailAddress>): ContactMailAddress { export function createContactMailAddress(values: StrippedEntity<ContactMailAddress>): ContactMailAddress {
return Object.assign(create(typeModels.ContactMailAddress, ContactMailAddressTypeRef), values) return Object.assign(create(typeModels.ContactMailAddress, ContactMailAddressTypeRef), values)
} }
@ -326,7 +326,7 @@ export type ContactMailAddress = {
} }
export const ContactPhoneNumberTypeRef: TypeRef<ContactPhoneNumber> = new TypeRef("tutanota", "ContactPhoneNumber") export const ContactPhoneNumberTypeRef: TypeRef<ContactPhoneNumber> = new TypeRef("tutanota", "ContactPhoneNumber")
export function createContactPhoneNumber(values: Partial<ContactPhoneNumber>): ContactPhoneNumber { export function createContactPhoneNumber(values: StrippedEntity<ContactPhoneNumber>): ContactPhoneNumber {
return Object.assign(create(typeModels.ContactPhoneNumber, ContactPhoneNumberTypeRef), values) return Object.assign(create(typeModels.ContactPhoneNumber, ContactPhoneNumberTypeRef), values)
} }
@ -340,7 +340,7 @@ export type ContactPhoneNumber = {
} }
export const ContactSocialIdTypeRef: TypeRef<ContactSocialId> = new TypeRef("tutanota", "ContactSocialId") export const ContactSocialIdTypeRef: TypeRef<ContactSocialId> = new TypeRef("tutanota", "ContactSocialId")
export function createContactSocialId(values: Partial<ContactSocialId>): ContactSocialId { export function createContactSocialId(values: StrippedEntity<ContactSocialId>): ContactSocialId {
return Object.assign(create(typeModels.ContactSocialId, ContactSocialIdTypeRef), values) return Object.assign(create(typeModels.ContactSocialId, ContactSocialIdTypeRef), values)
} }
@ -354,7 +354,7 @@ export type ContactSocialId = {
} }
export const ConversationEntryTypeRef: TypeRef<ConversationEntry> = new TypeRef("tutanota", "ConversationEntry") export const ConversationEntryTypeRef: TypeRef<ConversationEntry> = new TypeRef("tutanota", "ConversationEntry")
export function createConversationEntry(values: Partial<ConversationEntry>): ConversationEntry { export function createConversationEntry(values: StrippedEntity<ConversationEntry>): ConversationEntry {
return Object.assign(create(typeModels.ConversationEntry, ConversationEntryTypeRef), values) return Object.assign(create(typeModels.ConversationEntry, ConversationEntryTypeRef), values)
} }
@ -373,7 +373,7 @@ export type ConversationEntry = {
} }
export const CreateExternalUserGroupDataTypeRef: TypeRef<CreateExternalUserGroupData> = new TypeRef("tutanota", "CreateExternalUserGroupData") export const CreateExternalUserGroupDataTypeRef: TypeRef<CreateExternalUserGroupData> = new TypeRef("tutanota", "CreateExternalUserGroupData")
export function createCreateExternalUserGroupData(values: Partial<CreateExternalUserGroupData>): CreateExternalUserGroupData { export function createCreateExternalUserGroupData(values: StrippedEntity<CreateExternalUserGroupData>): CreateExternalUserGroupData {
return Object.assign(create(typeModels.CreateExternalUserGroupData, CreateExternalUserGroupDataTypeRef), values) return Object.assign(create(typeModels.CreateExternalUserGroupData, CreateExternalUserGroupDataTypeRef), values)
} }
@ -387,7 +387,7 @@ export type CreateExternalUserGroupData = {
} }
export const CreateGroupPostReturnTypeRef: TypeRef<CreateGroupPostReturn> = new TypeRef("tutanota", "CreateGroupPostReturn") export const CreateGroupPostReturnTypeRef: TypeRef<CreateGroupPostReturn> = new TypeRef("tutanota", "CreateGroupPostReturn")
export function createCreateGroupPostReturn(values: Partial<CreateGroupPostReturn>): CreateGroupPostReturn { export function createCreateGroupPostReturn(values: StrippedEntity<CreateGroupPostReturn>): CreateGroupPostReturn {
return Object.assign(create(typeModels.CreateGroupPostReturn, CreateGroupPostReturnTypeRef), values) return Object.assign(create(typeModels.CreateGroupPostReturn, CreateGroupPostReturnTypeRef), values)
} }
@ -401,7 +401,7 @@ export type CreateGroupPostReturn = {
} }
export const CreateLocalAdminGroupDataTypeRef: TypeRef<CreateLocalAdminGroupData> = new TypeRef("tutanota", "CreateLocalAdminGroupData") export const CreateLocalAdminGroupDataTypeRef: TypeRef<CreateLocalAdminGroupData> = new TypeRef("tutanota", "CreateLocalAdminGroupData")
export function createCreateLocalAdminGroupData(values: Partial<CreateLocalAdminGroupData>): CreateLocalAdminGroupData { export function createCreateLocalAdminGroupData(values: StrippedEntity<CreateLocalAdminGroupData>): CreateLocalAdminGroupData {
return Object.assign(create(typeModels.CreateLocalAdminGroupData, CreateLocalAdminGroupDataTypeRef), values) return Object.assign(create(typeModels.CreateLocalAdminGroupData, CreateLocalAdminGroupDataTypeRef), values)
} }
@ -415,7 +415,7 @@ export type CreateLocalAdminGroupData = {
} }
export const CreateMailFolderDataTypeRef: TypeRef<CreateMailFolderData> = new TypeRef("tutanota", "CreateMailFolderData") export const CreateMailFolderDataTypeRef: TypeRef<CreateMailFolderData> = new TypeRef("tutanota", "CreateMailFolderData")
export function createCreateMailFolderData(values: Partial<CreateMailFolderData>): CreateMailFolderData { export function createCreateMailFolderData(values: StrippedEntity<CreateMailFolderData>): CreateMailFolderData {
return Object.assign(create(typeModels.CreateMailFolderData, CreateMailFolderDataTypeRef), values) return Object.assign(create(typeModels.CreateMailFolderData, CreateMailFolderDataTypeRef), values)
} }
@ -432,7 +432,7 @@ export type CreateMailFolderData = {
} }
export const CreateMailFolderReturnTypeRef: TypeRef<CreateMailFolderReturn> = new TypeRef("tutanota", "CreateMailFolderReturn") export const CreateMailFolderReturnTypeRef: TypeRef<CreateMailFolderReturn> = new TypeRef("tutanota", "CreateMailFolderReturn")
export function createCreateMailFolderReturn(values: Partial<CreateMailFolderReturn>): CreateMailFolderReturn { export function createCreateMailFolderReturn(values: StrippedEntity<CreateMailFolderReturn>): CreateMailFolderReturn {
return Object.assign(create(typeModels.CreateMailFolderReturn, CreateMailFolderReturnTypeRef), values) return Object.assign(create(typeModels.CreateMailFolderReturn, CreateMailFolderReturnTypeRef), values)
} }
@ -446,7 +446,7 @@ export type CreateMailFolderReturn = {
} }
export const CreateMailGroupDataTypeRef: TypeRef<CreateMailGroupData> = new TypeRef("tutanota", "CreateMailGroupData") export const CreateMailGroupDataTypeRef: TypeRef<CreateMailGroupData> = new TypeRef("tutanota", "CreateMailGroupData")
export function createCreateMailGroupData(values: Partial<CreateMailGroupData>): CreateMailGroupData { export function createCreateMailGroupData(values: StrippedEntity<CreateMailGroupData>): CreateMailGroupData {
return Object.assign(create(typeModels.CreateMailGroupData, CreateMailGroupDataTypeRef), values) return Object.assign(create(typeModels.CreateMailGroupData, CreateMailGroupDataTypeRef), values)
} }
@ -462,7 +462,7 @@ export type CreateMailGroupData = {
} }
export const CustomerAccountCreateDataTypeRef: TypeRef<CustomerAccountCreateData> = new TypeRef("tutanota", "CustomerAccountCreateData") export const CustomerAccountCreateDataTypeRef: TypeRef<CustomerAccountCreateData> = new TypeRef("tutanota", "CustomerAccountCreateData")
export function createCustomerAccountCreateData(values: Partial<CustomerAccountCreateData>): CustomerAccountCreateData { export function createCustomerAccountCreateData(values: StrippedEntity<CustomerAccountCreateData>): CustomerAccountCreateData {
return Object.assign(create(typeModels.CustomerAccountCreateData, CustomerAccountCreateDataTypeRef), values) return Object.assign(create(typeModels.CustomerAccountCreateData, CustomerAccountCreateDataTypeRef), values)
} }
@ -487,7 +487,7 @@ export type CustomerAccountCreateData = {
} }
export const DeleteGroupDataTypeRef: TypeRef<DeleteGroupData> = new TypeRef("tutanota", "DeleteGroupData") export const DeleteGroupDataTypeRef: TypeRef<DeleteGroupData> = new TypeRef("tutanota", "DeleteGroupData")
export function createDeleteGroupData(values: Partial<DeleteGroupData>): DeleteGroupData { export function createDeleteGroupData(values: StrippedEntity<DeleteGroupData>): DeleteGroupData {
return Object.assign(create(typeModels.DeleteGroupData, DeleteGroupDataTypeRef), values) return Object.assign(create(typeModels.DeleteGroupData, DeleteGroupDataTypeRef), values)
} }
@ -501,7 +501,7 @@ export type DeleteGroupData = {
} }
export const DeleteMailDataTypeRef: TypeRef<DeleteMailData> = new TypeRef("tutanota", "DeleteMailData") export const DeleteMailDataTypeRef: TypeRef<DeleteMailData> = new TypeRef("tutanota", "DeleteMailData")
export function createDeleteMailData(values: Partial<DeleteMailData>): DeleteMailData { export function createDeleteMailData(values: StrippedEntity<DeleteMailData>): DeleteMailData {
return Object.assign(create(typeModels.DeleteMailData, DeleteMailDataTypeRef), values) return Object.assign(create(typeModels.DeleteMailData, DeleteMailDataTypeRef), values)
} }
@ -515,7 +515,7 @@ export type DeleteMailData = {
} }
export const DeleteMailFolderDataTypeRef: TypeRef<DeleteMailFolderData> = new TypeRef("tutanota", "DeleteMailFolderData") export const DeleteMailFolderDataTypeRef: TypeRef<DeleteMailFolderData> = new TypeRef("tutanota", "DeleteMailFolderData")
export function createDeleteMailFolderData(values: Partial<DeleteMailFolderData>): DeleteMailFolderData { export function createDeleteMailFolderData(values: StrippedEntity<DeleteMailFolderData>): DeleteMailFolderData {
return Object.assign(create(typeModels.DeleteMailFolderData, DeleteMailFolderDataTypeRef), values) return Object.assign(create(typeModels.DeleteMailFolderData, DeleteMailFolderDataTypeRef), values)
} }
@ -529,7 +529,7 @@ export type DeleteMailFolderData = {
} }
export const DraftAttachmentTypeRef: TypeRef<DraftAttachment> = new TypeRef("tutanota", "DraftAttachment") export const DraftAttachmentTypeRef: TypeRef<DraftAttachment> = new TypeRef("tutanota", "DraftAttachment")
export function createDraftAttachment(values: Partial<DraftAttachment>): DraftAttachment { export function createDraftAttachment(values: StrippedEntity<DraftAttachment>): DraftAttachment {
return Object.assign(create(typeModels.DraftAttachment, DraftAttachmentTypeRef), values) return Object.assign(create(typeModels.DraftAttachment, DraftAttachmentTypeRef), values)
} }
@ -544,7 +544,7 @@ export type DraftAttachment = {
} }
export const DraftCreateDataTypeRef: TypeRef<DraftCreateData> = new TypeRef("tutanota", "DraftCreateData") export const DraftCreateDataTypeRef: TypeRef<DraftCreateData> = new TypeRef("tutanota", "DraftCreateData")
export function createDraftCreateData(values: Partial<DraftCreateData>): DraftCreateData { export function createDraftCreateData(values: StrippedEntity<DraftCreateData>): DraftCreateData {
return Object.assign(create(typeModels.DraftCreateData, DraftCreateDataTypeRef), values) return Object.assign(create(typeModels.DraftCreateData, DraftCreateDataTypeRef), values)
} }
@ -562,7 +562,7 @@ export type DraftCreateData = {
} }
export const DraftCreateReturnTypeRef: TypeRef<DraftCreateReturn> = new TypeRef("tutanota", "DraftCreateReturn") export const DraftCreateReturnTypeRef: TypeRef<DraftCreateReturn> = new TypeRef("tutanota", "DraftCreateReturn")
export function createDraftCreateReturn(values: Partial<DraftCreateReturn>): DraftCreateReturn { export function createDraftCreateReturn(values: StrippedEntity<DraftCreateReturn>): DraftCreateReturn {
return Object.assign(create(typeModels.DraftCreateReturn, DraftCreateReturnTypeRef), values) return Object.assign(create(typeModels.DraftCreateReturn, DraftCreateReturnTypeRef), values)
} }
@ -575,7 +575,7 @@ export type DraftCreateReturn = {
} }
export const DraftDataTypeRef: TypeRef<DraftData> = new TypeRef("tutanota", "DraftData") export const DraftDataTypeRef: TypeRef<DraftData> = new TypeRef("tutanota", "DraftData")
export function createDraftData(values: Partial<DraftData>): DraftData { export function createDraftData(values: StrippedEntity<DraftData>): DraftData {
return Object.assign(create(typeModels.DraftData, DraftDataTypeRef), values) return Object.assign(create(typeModels.DraftData, DraftDataTypeRef), values)
} }
@ -600,7 +600,7 @@ export type DraftData = {
} }
export const DraftRecipientTypeRef: TypeRef<DraftRecipient> = new TypeRef("tutanota", "DraftRecipient") export const DraftRecipientTypeRef: TypeRef<DraftRecipient> = new TypeRef("tutanota", "DraftRecipient")
export function createDraftRecipient(values: Partial<DraftRecipient>): DraftRecipient { export function createDraftRecipient(values: StrippedEntity<DraftRecipient>): DraftRecipient {
return Object.assign(create(typeModels.DraftRecipient, DraftRecipientTypeRef), values) return Object.assign(create(typeModels.DraftRecipient, DraftRecipientTypeRef), values)
} }
@ -613,7 +613,7 @@ export type DraftRecipient = {
} }
export const DraftUpdateDataTypeRef: TypeRef<DraftUpdateData> = new TypeRef("tutanota", "DraftUpdateData") export const DraftUpdateDataTypeRef: TypeRef<DraftUpdateData> = new TypeRef("tutanota", "DraftUpdateData")
export function createDraftUpdateData(values: Partial<DraftUpdateData>): DraftUpdateData { export function createDraftUpdateData(values: StrippedEntity<DraftUpdateData>): DraftUpdateData {
return Object.assign(create(typeModels.DraftUpdateData, DraftUpdateDataTypeRef), values) return Object.assign(create(typeModels.DraftUpdateData, DraftUpdateDataTypeRef), values)
} }
@ -628,7 +628,7 @@ export type DraftUpdateData = {
} }
export const DraftUpdateReturnTypeRef: TypeRef<DraftUpdateReturn> = new TypeRef("tutanota", "DraftUpdateReturn") export const DraftUpdateReturnTypeRef: TypeRef<DraftUpdateReturn> = new TypeRef("tutanota", "DraftUpdateReturn")
export function createDraftUpdateReturn(values: Partial<DraftUpdateReturn>): DraftUpdateReturn { export function createDraftUpdateReturn(values: StrippedEntity<DraftUpdateReturn>): DraftUpdateReturn {
return Object.assign(create(typeModels.DraftUpdateReturn, DraftUpdateReturnTypeRef), values) return Object.assign(create(typeModels.DraftUpdateReturn, DraftUpdateReturnTypeRef), values)
} }
@ -642,7 +642,7 @@ export type DraftUpdateReturn = {
} }
export const EmailTemplateTypeRef: TypeRef<EmailTemplate> = new TypeRef("tutanota", "EmailTemplate") export const EmailTemplateTypeRef: TypeRef<EmailTemplate> = new TypeRef("tutanota", "EmailTemplate")
export function createEmailTemplate(values: Partial<EmailTemplate>): EmailTemplate { export function createEmailTemplate(values: StrippedEntity<EmailTemplate>): EmailTemplate {
return Object.assign(create(typeModels.EmailTemplate, EmailTemplateTypeRef), values) return Object.assign(create(typeModels.EmailTemplate, EmailTemplateTypeRef), values)
} }
@ -662,7 +662,7 @@ export type EmailTemplate = {
} }
export const EmailTemplateContentTypeRef: TypeRef<EmailTemplateContent> = new TypeRef("tutanota", "EmailTemplateContent") export const EmailTemplateContentTypeRef: TypeRef<EmailTemplateContent> = new TypeRef("tutanota", "EmailTemplateContent")
export function createEmailTemplateContent(values: Partial<EmailTemplateContent>): EmailTemplateContent { export function createEmailTemplateContent(values: StrippedEntity<EmailTemplateContent>): EmailTemplateContent {
return Object.assign(create(typeModels.EmailTemplateContent, EmailTemplateContentTypeRef), values) return Object.assign(create(typeModels.EmailTemplateContent, EmailTemplateContentTypeRef), values)
} }
@ -675,7 +675,7 @@ export type EmailTemplateContent = {
} }
export const EncryptTutanotaPropertiesDataTypeRef: TypeRef<EncryptTutanotaPropertiesData> = new TypeRef("tutanota", "EncryptTutanotaPropertiesData") export const EncryptTutanotaPropertiesDataTypeRef: TypeRef<EncryptTutanotaPropertiesData> = new TypeRef("tutanota", "EncryptTutanotaPropertiesData")
export function createEncryptTutanotaPropertiesData(values: Partial<EncryptTutanotaPropertiesData>): EncryptTutanotaPropertiesData { export function createEncryptTutanotaPropertiesData(values: StrippedEntity<EncryptTutanotaPropertiesData>): EncryptTutanotaPropertiesData {
return Object.assign(create(typeModels.EncryptTutanotaPropertiesData, EncryptTutanotaPropertiesDataTypeRef), values) return Object.assign(create(typeModels.EncryptTutanotaPropertiesData, EncryptTutanotaPropertiesDataTypeRef), values)
} }
@ -689,7 +689,7 @@ export type EncryptTutanotaPropertiesData = {
} }
export const EncryptedMailAddressTypeRef: TypeRef<EncryptedMailAddress> = new TypeRef("tutanota", "EncryptedMailAddress") export const EncryptedMailAddressTypeRef: TypeRef<EncryptedMailAddress> = new TypeRef("tutanota", "EncryptedMailAddress")
export function createEncryptedMailAddress(values: Partial<EncryptedMailAddress>): EncryptedMailAddress { export function createEncryptedMailAddress(values: StrippedEntity<EncryptedMailAddress>): EncryptedMailAddress {
return Object.assign(create(typeModels.EncryptedMailAddress, EncryptedMailAddressTypeRef), values) return Object.assign(create(typeModels.EncryptedMailAddress, EncryptedMailAddressTypeRef), values)
} }
@ -702,7 +702,7 @@ export type EncryptedMailAddress = {
} }
export const EntropyDataTypeRef: TypeRef<EntropyData> = new TypeRef("tutanota", "EntropyData") export const EntropyDataTypeRef: TypeRef<EntropyData> = new TypeRef("tutanota", "EntropyData")
export function createEntropyData(values: Partial<EntropyData>): EntropyData { export function createEntropyData(values: StrippedEntity<EntropyData>): EntropyData {
return Object.assign(create(typeModels.EntropyData, EntropyDataTypeRef), values) return Object.assign(create(typeModels.EntropyData, EntropyDataTypeRef), values)
} }
@ -714,7 +714,7 @@ export type EntropyData = {
} }
export const ExternalUserDataTypeRef: TypeRef<ExternalUserData> = new TypeRef("tutanota", "ExternalUserData") export const ExternalUserDataTypeRef: TypeRef<ExternalUserData> = new TypeRef("tutanota", "ExternalUserData")
export function createExternalUserData(values: Partial<ExternalUserData>): ExternalUserData { export function createExternalUserData(values: StrippedEntity<ExternalUserData>): ExternalUserData {
return Object.assign(create(typeModels.ExternalUserData, ExternalUserDataTypeRef), values) return Object.assign(create(typeModels.ExternalUserData, ExternalUserDataTypeRef), values)
} }
@ -738,7 +738,7 @@ export type ExternalUserData = {
} }
export const FileTypeRef: TypeRef<File> = new TypeRef("tutanota", "File") export const FileTypeRef: TypeRef<File> = new TypeRef("tutanota", "File")
export function createFile(values: Partial<File>): File { export function createFile(values: StrippedEntity<File>): File {
return Object.assign(create(typeModels.File, FileTypeRef), values) return Object.assign(create(typeModels.File, FileTypeRef), values)
} }
@ -764,7 +764,7 @@ export type File = {
} }
export const FileSystemTypeRef: TypeRef<FileSystem> = new TypeRef("tutanota", "FileSystem") export const FileSystemTypeRef: TypeRef<FileSystem> = new TypeRef("tutanota", "FileSystem")
export function createFileSystem(values: Partial<FileSystem>): FileSystem { export function createFileSystem(values: StrippedEntity<FileSystem>): FileSystem {
return Object.assign(create(typeModels.FileSystem, FileSystemTypeRef), values) return Object.assign(create(typeModels.FileSystem, FileSystemTypeRef), values)
} }
@ -782,7 +782,7 @@ export type FileSystem = {
} }
export const GroupInvitationDeleteDataTypeRef: TypeRef<GroupInvitationDeleteData> = new TypeRef("tutanota", "GroupInvitationDeleteData") export const GroupInvitationDeleteDataTypeRef: TypeRef<GroupInvitationDeleteData> = new TypeRef("tutanota", "GroupInvitationDeleteData")
export function createGroupInvitationDeleteData(values: Partial<GroupInvitationDeleteData>): GroupInvitationDeleteData { export function createGroupInvitationDeleteData(values: StrippedEntity<GroupInvitationDeleteData>): GroupInvitationDeleteData {
return Object.assign(create(typeModels.GroupInvitationDeleteData, GroupInvitationDeleteDataTypeRef), values) return Object.assign(create(typeModels.GroupInvitationDeleteData, GroupInvitationDeleteDataTypeRef), values)
} }
@ -795,7 +795,7 @@ export type GroupInvitationDeleteData = {
} }
export const GroupInvitationPostDataTypeRef: TypeRef<GroupInvitationPostData> = new TypeRef("tutanota", "GroupInvitationPostData") export const GroupInvitationPostDataTypeRef: TypeRef<GroupInvitationPostData> = new TypeRef("tutanota", "GroupInvitationPostData")
export function createGroupInvitationPostData(values: Partial<GroupInvitationPostData>): GroupInvitationPostData { export function createGroupInvitationPostData(values: StrippedEntity<GroupInvitationPostData>): GroupInvitationPostData {
return Object.assign(create(typeModels.GroupInvitationPostData, GroupInvitationPostDataTypeRef), values) return Object.assign(create(typeModels.GroupInvitationPostData, GroupInvitationPostDataTypeRef), values)
} }
@ -809,7 +809,7 @@ export type GroupInvitationPostData = {
} }
export const GroupInvitationPostReturnTypeRef: TypeRef<GroupInvitationPostReturn> = new TypeRef("tutanota", "GroupInvitationPostReturn") export const GroupInvitationPostReturnTypeRef: TypeRef<GroupInvitationPostReturn> = new TypeRef("tutanota", "GroupInvitationPostReturn")
export function createGroupInvitationPostReturn(values: Partial<GroupInvitationPostReturn>): GroupInvitationPostReturn { export function createGroupInvitationPostReturn(values: StrippedEntity<GroupInvitationPostReturn>): GroupInvitationPostReturn {
return Object.assign(create(typeModels.GroupInvitationPostReturn, GroupInvitationPostReturnTypeRef), values) return Object.assign(create(typeModels.GroupInvitationPostReturn, GroupInvitationPostReturnTypeRef), values)
} }
@ -824,7 +824,7 @@ export type GroupInvitationPostReturn = {
} }
export const GroupInvitationPutDataTypeRef: TypeRef<GroupInvitationPutData> = new TypeRef("tutanota", "GroupInvitationPutData") export const GroupInvitationPutDataTypeRef: TypeRef<GroupInvitationPutData> = new TypeRef("tutanota", "GroupInvitationPutData")
export function createGroupInvitationPutData(values: Partial<GroupInvitationPutData>): GroupInvitationPutData { export function createGroupInvitationPutData(values: StrippedEntity<GroupInvitationPutData>): GroupInvitationPutData {
return Object.assign(create(typeModels.GroupInvitationPutData, GroupInvitationPutDataTypeRef), values) return Object.assign(create(typeModels.GroupInvitationPutData, GroupInvitationPutDataTypeRef), values)
} }
@ -839,7 +839,7 @@ export type GroupInvitationPutData = {
} }
export const GroupSettingsTypeRef: TypeRef<GroupSettings> = new TypeRef("tutanota", "GroupSettings") export const GroupSettingsTypeRef: TypeRef<GroupSettings> = new TypeRef("tutanota", "GroupSettings")
export function createGroupSettings(values: Partial<GroupSettings>): GroupSettings { export function createGroupSettings(values: StrippedEntity<GroupSettings>): GroupSettings {
return Object.assign(create(typeModels.GroupSettings, GroupSettingsTypeRef), values) return Object.assign(create(typeModels.GroupSettings, GroupSettingsTypeRef), values)
} }
@ -854,7 +854,7 @@ export type GroupSettings = {
} }
export const HeaderTypeRef: TypeRef<Header> = new TypeRef("tutanota", "Header") export const HeaderTypeRef: TypeRef<Header> = new TypeRef("tutanota", "Header")
export function createHeader(values: Partial<Header>): Header { export function createHeader(values: StrippedEntity<Header>): Header {
return Object.assign(create(typeModels.Header, HeaderTypeRef), values) return Object.assign(create(typeModels.Header, HeaderTypeRef), values)
} }
@ -867,7 +867,7 @@ export type Header = {
} }
export const ImapFolderTypeRef: TypeRef<ImapFolder> = new TypeRef("tutanota", "ImapFolder") export const ImapFolderTypeRef: TypeRef<ImapFolder> = new TypeRef("tutanota", "ImapFolder")
export function createImapFolder(values: Partial<ImapFolder>): ImapFolder { export function createImapFolder(values: StrippedEntity<ImapFolder>): ImapFolder {
return Object.assign(create(typeModels.ImapFolder, ImapFolderTypeRef), values) return Object.assign(create(typeModels.ImapFolder, ImapFolderTypeRef), values)
} }
@ -883,7 +883,7 @@ export type ImapFolder = {
} }
export const ImapSyncConfigurationTypeRef: TypeRef<ImapSyncConfiguration> = new TypeRef("tutanota", "ImapSyncConfiguration") export const ImapSyncConfigurationTypeRef: TypeRef<ImapSyncConfiguration> = new TypeRef("tutanota", "ImapSyncConfiguration")
export function createImapSyncConfiguration(values: Partial<ImapSyncConfiguration>): ImapSyncConfiguration { export function createImapSyncConfiguration(values: StrippedEntity<ImapSyncConfiguration>): ImapSyncConfiguration {
return Object.assign(create(typeModels.ImapSyncConfiguration, ImapSyncConfigurationTypeRef), values) return Object.assign(create(typeModels.ImapSyncConfiguration, ImapSyncConfigurationTypeRef), values)
} }
@ -900,7 +900,7 @@ export type ImapSyncConfiguration = {
} }
export const ImapSyncStateTypeRef: TypeRef<ImapSyncState> = new TypeRef("tutanota", "ImapSyncState") export const ImapSyncStateTypeRef: TypeRef<ImapSyncState> = new TypeRef("tutanota", "ImapSyncState")
export function createImapSyncState(values: Partial<ImapSyncState>): ImapSyncState { export function createImapSyncState(values: StrippedEntity<ImapSyncState>): ImapSyncState {
return Object.assign(create(typeModels.ImapSyncState, ImapSyncStateTypeRef), values) return Object.assign(create(typeModels.ImapSyncState, ImapSyncStateTypeRef), values)
} }
@ -916,7 +916,7 @@ export type ImapSyncState = {
} }
export const InboxRuleTypeRef: TypeRef<InboxRule> = new TypeRef("tutanota", "InboxRule") export const InboxRuleTypeRef: TypeRef<InboxRule> = new TypeRef("tutanota", "InboxRule")
export function createInboxRule(values: Partial<InboxRule>): InboxRule { export function createInboxRule(values: StrippedEntity<InboxRule>): InboxRule {
return Object.assign(create(typeModels.InboxRule, InboxRuleTypeRef), values) return Object.assign(create(typeModels.InboxRule, InboxRuleTypeRef), values)
} }
@ -931,7 +931,7 @@ export type InboxRule = {
} }
export const InternalGroupDataTypeRef: TypeRef<InternalGroupData> = new TypeRef("tutanota", "InternalGroupData") export const InternalGroupDataTypeRef: TypeRef<InternalGroupData> = new TypeRef("tutanota", "InternalGroupData")
export function createInternalGroupData(values: Partial<InternalGroupData>): InternalGroupData { export function createInternalGroupData(values: StrippedEntity<InternalGroupData>): InternalGroupData {
return Object.assign(create(typeModels.InternalGroupData, InternalGroupDataTypeRef), values) return Object.assign(create(typeModels.InternalGroupData, InternalGroupDataTypeRef), values)
} }
@ -948,7 +948,7 @@ export type InternalGroupData = {
} }
export const InternalRecipientKeyDataTypeRef: TypeRef<InternalRecipientKeyData> = new TypeRef("tutanota", "InternalRecipientKeyData") export const InternalRecipientKeyDataTypeRef: TypeRef<InternalRecipientKeyData> = new TypeRef("tutanota", "InternalRecipientKeyData")
export function createInternalRecipientKeyData(values: Partial<InternalRecipientKeyData>): InternalRecipientKeyData { export function createInternalRecipientKeyData(values: StrippedEntity<InternalRecipientKeyData>): InternalRecipientKeyData {
return Object.assign(create(typeModels.InternalRecipientKeyData, InternalRecipientKeyDataTypeRef), values) return Object.assign(create(typeModels.InternalRecipientKeyData, InternalRecipientKeyDataTypeRef), values)
} }
@ -962,7 +962,7 @@ export type InternalRecipientKeyData = {
} }
export const KnowledgeBaseEntryTypeRef: TypeRef<KnowledgeBaseEntry> = new TypeRef("tutanota", "KnowledgeBaseEntry") export const KnowledgeBaseEntryTypeRef: TypeRef<KnowledgeBaseEntry> = new TypeRef("tutanota", "KnowledgeBaseEntry")
export function createKnowledgeBaseEntry(values: Partial<KnowledgeBaseEntry>): KnowledgeBaseEntry { export function createKnowledgeBaseEntry(values: StrippedEntity<KnowledgeBaseEntry>): KnowledgeBaseEntry {
return Object.assign(create(typeModels.KnowledgeBaseEntry, KnowledgeBaseEntryTypeRef), values) return Object.assign(create(typeModels.KnowledgeBaseEntry, KnowledgeBaseEntryTypeRef), values)
} }
@ -982,7 +982,7 @@ export type KnowledgeBaseEntry = {
} }
export const KnowledgeBaseEntryKeywordTypeRef: TypeRef<KnowledgeBaseEntryKeyword> = new TypeRef("tutanota", "KnowledgeBaseEntryKeyword") export const KnowledgeBaseEntryKeywordTypeRef: TypeRef<KnowledgeBaseEntryKeyword> = new TypeRef("tutanota", "KnowledgeBaseEntryKeyword")
export function createKnowledgeBaseEntryKeyword(values: Partial<KnowledgeBaseEntryKeyword>): KnowledgeBaseEntryKeyword { export function createKnowledgeBaseEntryKeyword(values: StrippedEntity<KnowledgeBaseEntryKeyword>): KnowledgeBaseEntryKeyword {
return Object.assign(create(typeModels.KnowledgeBaseEntryKeyword, KnowledgeBaseEntryKeywordTypeRef), values) return Object.assign(create(typeModels.KnowledgeBaseEntryKeyword, KnowledgeBaseEntryKeywordTypeRef), values)
} }
@ -994,7 +994,7 @@ export type KnowledgeBaseEntryKeyword = {
} }
export const ListUnsubscribeDataTypeRef: TypeRef<ListUnsubscribeData> = new TypeRef("tutanota", "ListUnsubscribeData") export const ListUnsubscribeDataTypeRef: TypeRef<ListUnsubscribeData> = new TypeRef("tutanota", "ListUnsubscribeData")
export function createListUnsubscribeData(values: Partial<ListUnsubscribeData>): ListUnsubscribeData { export function createListUnsubscribeData(values: StrippedEntity<ListUnsubscribeData>): ListUnsubscribeData {
return Object.assign(create(typeModels.ListUnsubscribeData, ListUnsubscribeDataTypeRef), values) return Object.assign(create(typeModels.ListUnsubscribeData, ListUnsubscribeDataTypeRef), values)
} }
@ -1009,7 +1009,7 @@ export type ListUnsubscribeData = {
} }
export const MailTypeRef: TypeRef<Mail> = new TypeRef("tutanota", "Mail") export const MailTypeRef: TypeRef<Mail> = new TypeRef("tutanota", "Mail")
export function createMail(values: Partial<Mail>): Mail { export function createMail(values: StrippedEntity<Mail>): Mail {
return Object.assign(create(typeModels.Mail, MailTypeRef), values) return Object.assign(create(typeModels.Mail, MailTypeRef), values)
} }
@ -1053,7 +1053,7 @@ export type Mail = {
} }
export const MailAddressTypeRef: TypeRef<MailAddress> = new TypeRef("tutanota", "MailAddress") export const MailAddressTypeRef: TypeRef<MailAddress> = new TypeRef("tutanota", "MailAddress")
export function createMailAddress(values: Partial<MailAddress>): MailAddress { export function createMailAddress(values: StrippedEntity<MailAddress>): MailAddress {
return Object.assign(create(typeModels.MailAddress, MailAddressTypeRef), values) return Object.assign(create(typeModels.MailAddress, MailAddressTypeRef), values)
} }
@ -1068,7 +1068,7 @@ export type MailAddress = {
} }
export const MailAddressPropertiesTypeRef: TypeRef<MailAddressProperties> = new TypeRef("tutanota", "MailAddressProperties") export const MailAddressPropertiesTypeRef: TypeRef<MailAddressProperties> = new TypeRef("tutanota", "MailAddressProperties")
export function createMailAddressProperties(values: Partial<MailAddressProperties>): MailAddressProperties { export function createMailAddressProperties(values: StrippedEntity<MailAddressProperties>): MailAddressProperties {
return Object.assign(create(typeModels.MailAddressProperties, MailAddressPropertiesTypeRef), values) return Object.assign(create(typeModels.MailAddressProperties, MailAddressPropertiesTypeRef), values)
} }
@ -1081,7 +1081,7 @@ export type MailAddressProperties = {
} }
export const MailBodyTypeRef: TypeRef<MailBody> = new TypeRef("tutanota", "MailBody") export const MailBodyTypeRef: TypeRef<MailBody> = new TypeRef("tutanota", "MailBody")
export function createMailBody(values: Partial<MailBody>): MailBody { export function createMailBody(values: StrippedEntity<MailBody>): MailBody {
return Object.assign(create(typeModels.MailBody, MailBodyTypeRef), values) return Object.assign(create(typeModels.MailBody, MailBodyTypeRef), values)
} }
@ -1101,7 +1101,7 @@ export type MailBody = {
} }
export const MailBoxTypeRef: TypeRef<MailBox> = new TypeRef("tutanota", "MailBox") export const MailBoxTypeRef: TypeRef<MailBox> = new TypeRef("tutanota", "MailBox")
export function createMailBox(values: Partial<MailBox>): MailBox { export function createMailBox(values: StrippedEntity<MailBox>): MailBox {
return Object.assign(create(typeModels.MailBox, MailBoxTypeRef), values) return Object.assign(create(typeModels.MailBox, MailBoxTypeRef), values)
} }
@ -1126,7 +1126,7 @@ export type MailBox = {
} }
export const MailDetailsTypeRef: TypeRef<MailDetails> = new TypeRef("tutanota", "MailDetails") export const MailDetailsTypeRef: TypeRef<MailDetails> = new TypeRef("tutanota", "MailDetails")
export function createMailDetails(values: Partial<MailDetails>): MailDetails { export function createMailDetails(values: StrippedEntity<MailDetails>): MailDetails {
return Object.assign(create(typeModels.MailDetails, MailDetailsTypeRef), values) return Object.assign(create(typeModels.MailDetails, MailDetailsTypeRef), values)
} }
@ -1144,7 +1144,7 @@ export type MailDetails = {
} }
export const MailDetailsBlobTypeRef: TypeRef<MailDetailsBlob> = new TypeRef("tutanota", "MailDetailsBlob") export const MailDetailsBlobTypeRef: TypeRef<MailDetailsBlob> = new TypeRef("tutanota", "MailDetailsBlob")
export function createMailDetailsBlob(values: Partial<MailDetailsBlob>): MailDetailsBlob { export function createMailDetailsBlob(values: StrippedEntity<MailDetailsBlob>): MailDetailsBlob {
return Object.assign(create(typeModels.MailDetailsBlob, MailDetailsBlobTypeRef), values) return Object.assign(create(typeModels.MailDetailsBlob, MailDetailsBlobTypeRef), values)
} }
@ -1162,7 +1162,7 @@ export type MailDetailsBlob = {
} }
export const MailDetailsDraftTypeRef: TypeRef<MailDetailsDraft> = new TypeRef("tutanota", "MailDetailsDraft") export const MailDetailsDraftTypeRef: TypeRef<MailDetailsDraft> = new TypeRef("tutanota", "MailDetailsDraft")
export function createMailDetailsDraft(values: Partial<MailDetailsDraft>): MailDetailsDraft { export function createMailDetailsDraft(values: StrippedEntity<MailDetailsDraft>): MailDetailsDraft {
return Object.assign(create(typeModels.MailDetailsDraft, MailDetailsDraftTypeRef), values) return Object.assign(create(typeModels.MailDetailsDraft, MailDetailsDraftTypeRef), values)
} }
@ -1180,7 +1180,7 @@ export type MailDetailsDraft = {
} }
export const MailDetailsDraftsRefTypeRef: TypeRef<MailDetailsDraftsRef> = new TypeRef("tutanota", "MailDetailsDraftsRef") export const MailDetailsDraftsRefTypeRef: TypeRef<MailDetailsDraftsRef> = new TypeRef("tutanota", "MailDetailsDraftsRef")
export function createMailDetailsDraftsRef(values: Partial<MailDetailsDraftsRef>): MailDetailsDraftsRef { export function createMailDetailsDraftsRef(values: StrippedEntity<MailDetailsDraftsRef>): MailDetailsDraftsRef {
return Object.assign(create(typeModels.MailDetailsDraftsRef, MailDetailsDraftsRefTypeRef), values) return Object.assign(create(typeModels.MailDetailsDraftsRef, MailDetailsDraftsRefTypeRef), values)
} }
@ -1193,7 +1193,7 @@ export type MailDetailsDraftsRef = {
} }
export const MailFolderTypeRef: TypeRef<MailFolder> = new TypeRef("tutanota", "MailFolder") export const MailFolderTypeRef: TypeRef<MailFolder> = new TypeRef("tutanota", "MailFolder")
export function createMailFolder(values: Partial<MailFolder>): MailFolder { export function createMailFolder(values: StrippedEntity<MailFolder>): MailFolder {
return Object.assign(create(typeModels.MailFolder, MailFolderTypeRef), values) return Object.assign(create(typeModels.MailFolder, MailFolderTypeRef), values)
} }
@ -1215,7 +1215,7 @@ export type MailFolder = {
} }
export const MailFolderRefTypeRef: TypeRef<MailFolderRef> = new TypeRef("tutanota", "MailFolderRef") export const MailFolderRefTypeRef: TypeRef<MailFolderRef> = new TypeRef("tutanota", "MailFolderRef")
export function createMailFolderRef(values: Partial<MailFolderRef>): MailFolderRef { export function createMailFolderRef(values: StrippedEntity<MailFolderRef>): MailFolderRef {
return Object.assign(create(typeModels.MailFolderRef, MailFolderRefTypeRef), values) return Object.assign(create(typeModels.MailFolderRef, MailFolderRefTypeRef), values)
} }
@ -1228,7 +1228,7 @@ export type MailFolderRef = {
} }
export const MailHeadersTypeRef: TypeRef<MailHeaders> = new TypeRef("tutanota", "MailHeaders") export const MailHeadersTypeRef: TypeRef<MailHeaders> = new TypeRef("tutanota", "MailHeaders")
export function createMailHeaders(values: Partial<MailHeaders>): MailHeaders { export function createMailHeaders(values: StrippedEntity<MailHeaders>): MailHeaders {
return Object.assign(create(typeModels.MailHeaders, MailHeadersTypeRef), values) return Object.assign(create(typeModels.MailHeaders, MailHeadersTypeRef), values)
} }
@ -1246,7 +1246,7 @@ export type MailHeaders = {
} }
export const MailboxGroupRootTypeRef: TypeRef<MailboxGroupRoot> = new TypeRef("tutanota", "MailboxGroupRoot") export const MailboxGroupRootTypeRef: TypeRef<MailboxGroupRoot> = new TypeRef("tutanota", "MailboxGroupRoot")
export function createMailboxGroupRoot(values: Partial<MailboxGroupRoot>): MailboxGroupRoot { export function createMailboxGroupRoot(values: StrippedEntity<MailboxGroupRoot>): MailboxGroupRoot {
return Object.assign(create(typeModels.MailboxGroupRoot, MailboxGroupRootTypeRef), values) return Object.assign(create(typeModels.MailboxGroupRoot, MailboxGroupRootTypeRef), values)
} }
@ -1268,7 +1268,7 @@ export type MailboxGroupRoot = {
} }
export const MailboxPropertiesTypeRef: TypeRef<MailboxProperties> = new TypeRef("tutanota", "MailboxProperties") export const MailboxPropertiesTypeRef: TypeRef<MailboxProperties> = new TypeRef("tutanota", "MailboxProperties")
export function createMailboxProperties(values: Partial<MailboxProperties>): MailboxProperties { export function createMailboxProperties(values: StrippedEntity<MailboxProperties>): MailboxProperties {
return Object.assign(create(typeModels.MailboxProperties, MailboxPropertiesTypeRef), values) return Object.assign(create(typeModels.MailboxProperties, MailboxPropertiesTypeRef), values)
} }
@ -1287,7 +1287,7 @@ export type MailboxProperties = {
} }
export const MailboxServerPropertiesTypeRef: TypeRef<MailboxServerProperties> = new TypeRef("tutanota", "MailboxServerProperties") export const MailboxServerPropertiesTypeRef: TypeRef<MailboxServerProperties> = new TypeRef("tutanota", "MailboxServerProperties")
export function createMailboxServerProperties(values: Partial<MailboxServerProperties>): MailboxServerProperties { export function createMailboxServerProperties(values: StrippedEntity<MailboxServerProperties>): MailboxServerProperties {
return Object.assign(create(typeModels.MailboxServerProperties, MailboxServerPropertiesTypeRef), values) return Object.assign(create(typeModels.MailboxServerProperties, MailboxServerPropertiesTypeRef), values)
} }
@ -1302,7 +1302,7 @@ export type MailboxServerProperties = {
} }
export const MoveMailDataTypeRef: TypeRef<MoveMailData> = new TypeRef("tutanota", "MoveMailData") export const MoveMailDataTypeRef: TypeRef<MoveMailData> = new TypeRef("tutanota", "MoveMailData")
export function createMoveMailData(values: Partial<MoveMailData>): MoveMailData { export function createMoveMailData(values: StrippedEntity<MoveMailData>): MoveMailData {
return Object.assign(create(typeModels.MoveMailData, MoveMailDataTypeRef), values) return Object.assign(create(typeModels.MoveMailData, MoveMailDataTypeRef), values)
} }
@ -1316,7 +1316,7 @@ export type MoveMailData = {
} }
export const NewDraftAttachmentTypeRef: TypeRef<NewDraftAttachment> = new TypeRef("tutanota", "NewDraftAttachment") export const NewDraftAttachmentTypeRef: TypeRef<NewDraftAttachment> = new TypeRef("tutanota", "NewDraftAttachment")
export function createNewDraftAttachment(values: Partial<NewDraftAttachment>): NewDraftAttachment { export function createNewDraftAttachment(values: StrippedEntity<NewDraftAttachment>): NewDraftAttachment {
return Object.assign(create(typeModels.NewDraftAttachment, NewDraftAttachmentTypeRef), values) return Object.assign(create(typeModels.NewDraftAttachment, NewDraftAttachmentTypeRef), values)
} }
@ -1332,7 +1332,7 @@ export type NewDraftAttachment = {
} }
export const NewsIdTypeRef: TypeRef<NewsId> = new TypeRef("tutanota", "NewsId") export const NewsIdTypeRef: TypeRef<NewsId> = new TypeRef("tutanota", "NewsId")
export function createNewsId(values: Partial<NewsId>): NewsId { export function createNewsId(values: StrippedEntity<NewsId>): NewsId {
return Object.assign(create(typeModels.NewsId, NewsIdTypeRef), values) return Object.assign(create(typeModels.NewsId, NewsIdTypeRef), values)
} }
@ -1345,7 +1345,7 @@ export type NewsId = {
} }
export const NewsInTypeRef: TypeRef<NewsIn> = new TypeRef("tutanota", "NewsIn") export const NewsInTypeRef: TypeRef<NewsIn> = new TypeRef("tutanota", "NewsIn")
export function createNewsIn(values: Partial<NewsIn>): NewsIn { export function createNewsIn(values: StrippedEntity<NewsIn>): NewsIn {
return Object.assign(create(typeModels.NewsIn, NewsInTypeRef), values) return Object.assign(create(typeModels.NewsIn, NewsInTypeRef), values)
} }
@ -1357,7 +1357,7 @@ export type NewsIn = {
} }
export const NewsOutTypeRef: TypeRef<NewsOut> = new TypeRef("tutanota", "NewsOut") export const NewsOutTypeRef: TypeRef<NewsOut> = new TypeRef("tutanota", "NewsOut")
export function createNewsOut(values: Partial<NewsOut>): NewsOut { export function createNewsOut(values: StrippedEntity<NewsOut>): NewsOut {
return Object.assign(create(typeModels.NewsOut, NewsOutTypeRef), values) return Object.assign(create(typeModels.NewsOut, NewsOutTypeRef), values)
} }
@ -1370,7 +1370,7 @@ export type NewsOut = {
} }
export const NotificationMailTypeRef: TypeRef<NotificationMail> = new TypeRef("tutanota", "NotificationMail") export const NotificationMailTypeRef: TypeRef<NotificationMail> = new TypeRef("tutanota", "NotificationMail")
export function createNotificationMail(values: Partial<NotificationMail>): NotificationMail { export function createNotificationMail(values: StrippedEntity<NotificationMail>): NotificationMail {
return Object.assign(create(typeModels.NotificationMail, NotificationMailTypeRef), values) return Object.assign(create(typeModels.NotificationMail, NotificationMailTypeRef), values)
} }
@ -1386,7 +1386,7 @@ export type NotificationMail = {
} }
export const OutOfOfficeNotificationTypeRef: TypeRef<OutOfOfficeNotification> = new TypeRef("tutanota", "OutOfOfficeNotification") export const OutOfOfficeNotificationTypeRef: TypeRef<OutOfOfficeNotification> = new TypeRef("tutanota", "OutOfOfficeNotification")
export function createOutOfOfficeNotification(values: Partial<OutOfOfficeNotification>): OutOfOfficeNotification { export function createOutOfOfficeNotification(values: StrippedEntity<OutOfOfficeNotification>): OutOfOfficeNotification {
return Object.assign(create(typeModels.OutOfOfficeNotification, OutOfOfficeNotificationTypeRef), values) return Object.assign(create(typeModels.OutOfOfficeNotification, OutOfOfficeNotificationTypeRef), values)
} }
@ -1405,7 +1405,7 @@ export type OutOfOfficeNotification = {
} }
export const OutOfOfficeNotificationMessageTypeRef: TypeRef<OutOfOfficeNotificationMessage> = new TypeRef("tutanota", "OutOfOfficeNotificationMessage") export const OutOfOfficeNotificationMessageTypeRef: TypeRef<OutOfOfficeNotificationMessage> = new TypeRef("tutanota", "OutOfOfficeNotificationMessage")
export function createOutOfOfficeNotificationMessage(values: Partial<OutOfOfficeNotificationMessage>): OutOfOfficeNotificationMessage { export function createOutOfOfficeNotificationMessage(values: StrippedEntity<OutOfOfficeNotificationMessage>): OutOfOfficeNotificationMessage {
return Object.assign(create(typeModels.OutOfOfficeNotificationMessage, OutOfOfficeNotificationMessageTypeRef), values) return Object.assign(create(typeModels.OutOfOfficeNotificationMessage, OutOfOfficeNotificationMessageTypeRef), values)
} }
@ -1419,7 +1419,7 @@ export type OutOfOfficeNotificationMessage = {
} }
export const OutOfOfficeNotificationRecipientListTypeRef: TypeRef<OutOfOfficeNotificationRecipientList> = new TypeRef("tutanota", "OutOfOfficeNotificationRecipientList") export const OutOfOfficeNotificationRecipientListTypeRef: TypeRef<OutOfOfficeNotificationRecipientList> = new TypeRef("tutanota", "OutOfOfficeNotificationRecipientList")
export function createOutOfOfficeNotificationRecipientList(values: Partial<OutOfOfficeNotificationRecipientList>): OutOfOfficeNotificationRecipientList { export function createOutOfOfficeNotificationRecipientList(values: StrippedEntity<OutOfOfficeNotificationRecipientList>): OutOfOfficeNotificationRecipientList {
return Object.assign(create(typeModels.OutOfOfficeNotificationRecipientList, OutOfOfficeNotificationRecipientListTypeRef), values) return Object.assign(create(typeModels.OutOfOfficeNotificationRecipientList, OutOfOfficeNotificationRecipientListTypeRef), values)
} }
@ -1432,7 +1432,7 @@ export type OutOfOfficeNotificationRecipientList = {
} }
export const PasswordAutoAuthenticationReturnTypeRef: TypeRef<PasswordAutoAuthenticationReturn> = new TypeRef("tutanota", "PasswordAutoAuthenticationReturn") export const PasswordAutoAuthenticationReturnTypeRef: TypeRef<PasswordAutoAuthenticationReturn> = new TypeRef("tutanota", "PasswordAutoAuthenticationReturn")
export function createPasswordAutoAuthenticationReturn(values: Partial<PasswordAutoAuthenticationReturn>): PasswordAutoAuthenticationReturn { export function createPasswordAutoAuthenticationReturn(values: StrippedEntity<PasswordAutoAuthenticationReturn>): PasswordAutoAuthenticationReturn {
return Object.assign(create(typeModels.PasswordAutoAuthenticationReturn, PasswordAutoAuthenticationReturnTypeRef), values) return Object.assign(create(typeModels.PasswordAutoAuthenticationReturn, PasswordAutoAuthenticationReturnTypeRef), values)
} }
@ -1443,7 +1443,7 @@ export type PasswordAutoAuthenticationReturn = {
} }
export const PasswordChannelPhoneNumberTypeRef: TypeRef<PasswordChannelPhoneNumber> = new TypeRef("tutanota", "PasswordChannelPhoneNumber") export const PasswordChannelPhoneNumberTypeRef: TypeRef<PasswordChannelPhoneNumber> = new TypeRef("tutanota", "PasswordChannelPhoneNumber")
export function createPasswordChannelPhoneNumber(values: Partial<PasswordChannelPhoneNumber>): PasswordChannelPhoneNumber { export function createPasswordChannelPhoneNumber(values: StrippedEntity<PasswordChannelPhoneNumber>): PasswordChannelPhoneNumber {
return Object.assign(create(typeModels.PasswordChannelPhoneNumber, PasswordChannelPhoneNumberTypeRef), values) return Object.assign(create(typeModels.PasswordChannelPhoneNumber, PasswordChannelPhoneNumberTypeRef), values)
} }
@ -1455,7 +1455,7 @@ export type PasswordChannelPhoneNumber = {
} }
export const PasswordChannelReturnTypeRef: TypeRef<PasswordChannelReturn> = new TypeRef("tutanota", "PasswordChannelReturn") export const PasswordChannelReturnTypeRef: TypeRef<PasswordChannelReturn> = new TypeRef("tutanota", "PasswordChannelReturn")
export function createPasswordChannelReturn(values: Partial<PasswordChannelReturn>): PasswordChannelReturn { export function createPasswordChannelReturn(values: StrippedEntity<PasswordChannelReturn>): PasswordChannelReturn {
return Object.assign(create(typeModels.PasswordChannelReturn, PasswordChannelReturnTypeRef), values) return Object.assign(create(typeModels.PasswordChannelReturn, PasswordChannelReturnTypeRef), values)
} }
@ -1468,7 +1468,7 @@ export type PasswordChannelReturn = {
} }
export const PasswordMessagingDataTypeRef: TypeRef<PasswordMessagingData> = new TypeRef("tutanota", "PasswordMessagingData") export const PasswordMessagingDataTypeRef: TypeRef<PasswordMessagingData> = new TypeRef("tutanota", "PasswordMessagingData")
export function createPasswordMessagingData(values: Partial<PasswordMessagingData>): PasswordMessagingData { export function createPasswordMessagingData(values: StrippedEntity<PasswordMessagingData>): PasswordMessagingData {
return Object.assign(create(typeModels.PasswordMessagingData, PasswordMessagingDataTypeRef), values) return Object.assign(create(typeModels.PasswordMessagingData, PasswordMessagingDataTypeRef), values)
} }
@ -1482,7 +1482,7 @@ export type PasswordMessagingData = {
} }
export const PasswordMessagingReturnTypeRef: TypeRef<PasswordMessagingReturn> = new TypeRef("tutanota", "PasswordMessagingReturn") export const PasswordMessagingReturnTypeRef: TypeRef<PasswordMessagingReturn> = new TypeRef("tutanota", "PasswordMessagingReturn")
export function createPasswordMessagingReturn(values: Partial<PasswordMessagingReturn>): PasswordMessagingReturn { export function createPasswordMessagingReturn(values: StrippedEntity<PasswordMessagingReturn>): PasswordMessagingReturn {
return Object.assign(create(typeModels.PasswordMessagingReturn, PasswordMessagingReturnTypeRef), values) return Object.assign(create(typeModels.PasswordMessagingReturn, PasswordMessagingReturnTypeRef), values)
} }
@ -1494,7 +1494,7 @@ export type PasswordMessagingReturn = {
} }
export const PasswordRetrievalDataTypeRef: TypeRef<PasswordRetrievalData> = new TypeRef("tutanota", "PasswordRetrievalData") export const PasswordRetrievalDataTypeRef: TypeRef<PasswordRetrievalData> = new TypeRef("tutanota", "PasswordRetrievalData")
export function createPasswordRetrievalData(values: Partial<PasswordRetrievalData>): PasswordRetrievalData { export function createPasswordRetrievalData(values: StrippedEntity<PasswordRetrievalData>): PasswordRetrievalData {
return Object.assign(create(typeModels.PasswordRetrievalData, PasswordRetrievalDataTypeRef), values) return Object.assign(create(typeModels.PasswordRetrievalData, PasswordRetrievalDataTypeRef), values)
} }
@ -1506,7 +1506,7 @@ export type PasswordRetrievalData = {
} }
export const PasswordRetrievalReturnTypeRef: TypeRef<PasswordRetrievalReturn> = new TypeRef("tutanota", "PasswordRetrievalReturn") export const PasswordRetrievalReturnTypeRef: TypeRef<PasswordRetrievalReturn> = new TypeRef("tutanota", "PasswordRetrievalReturn")
export function createPasswordRetrievalReturn(values: Partial<PasswordRetrievalReturn>): PasswordRetrievalReturn { export function createPasswordRetrievalReturn(values: StrippedEntity<PasswordRetrievalReturn>): PasswordRetrievalReturn {
return Object.assign(create(typeModels.PasswordRetrievalReturn, PasswordRetrievalReturnTypeRef), values) return Object.assign(create(typeModels.PasswordRetrievalReturn, PasswordRetrievalReturnTypeRef), values)
} }
@ -1518,7 +1518,7 @@ export type PasswordRetrievalReturn = {
} }
export const PhishingMarkerWebsocketDataTypeRef: TypeRef<PhishingMarkerWebsocketData> = new TypeRef("tutanota", "PhishingMarkerWebsocketData") export const PhishingMarkerWebsocketDataTypeRef: TypeRef<PhishingMarkerWebsocketData> = new TypeRef("tutanota", "PhishingMarkerWebsocketData")
export function createPhishingMarkerWebsocketData(values: Partial<PhishingMarkerWebsocketData>): PhishingMarkerWebsocketData { export function createPhishingMarkerWebsocketData(values: StrippedEntity<PhishingMarkerWebsocketData>): PhishingMarkerWebsocketData {
return Object.assign(create(typeModels.PhishingMarkerWebsocketData, PhishingMarkerWebsocketDataTypeRef), values) return Object.assign(create(typeModels.PhishingMarkerWebsocketData, PhishingMarkerWebsocketDataTypeRef), values)
} }
@ -1532,7 +1532,7 @@ export type PhishingMarkerWebsocketData = {
} }
export const PhotosRefTypeRef: TypeRef<PhotosRef> = new TypeRef("tutanota", "PhotosRef") export const PhotosRefTypeRef: TypeRef<PhotosRef> = new TypeRef("tutanota", "PhotosRef")
export function createPhotosRef(values: Partial<PhotosRef>): PhotosRef { export function createPhotosRef(values: StrippedEntity<PhotosRef>): PhotosRef {
return Object.assign(create(typeModels.PhotosRef, PhotosRefTypeRef), values) return Object.assign(create(typeModels.PhotosRef, PhotosRefTypeRef), values)
} }
@ -1545,7 +1545,7 @@ export type PhotosRef = {
} }
export const ReceiveInfoServiceDataTypeRef: TypeRef<ReceiveInfoServiceData> = new TypeRef("tutanota", "ReceiveInfoServiceData") export const ReceiveInfoServiceDataTypeRef: TypeRef<ReceiveInfoServiceData> = new TypeRef("tutanota", "ReceiveInfoServiceData")
export function createReceiveInfoServiceData(values: Partial<ReceiveInfoServiceData>): ReceiveInfoServiceData { export function createReceiveInfoServiceData(values: StrippedEntity<ReceiveInfoServiceData>): ReceiveInfoServiceData {
return Object.assign(create(typeModels.ReceiveInfoServiceData, ReceiveInfoServiceDataTypeRef), values) return Object.assign(create(typeModels.ReceiveInfoServiceData, ReceiveInfoServiceDataTypeRef), values)
} }
@ -1557,7 +1557,7 @@ export type ReceiveInfoServiceData = {
} }
export const RecipientsTypeRef: TypeRef<Recipients> = new TypeRef("tutanota", "Recipients") export const RecipientsTypeRef: TypeRef<Recipients> = new TypeRef("tutanota", "Recipients")
export function createRecipients(values: Partial<Recipients>): Recipients { export function createRecipients(values: StrippedEntity<Recipients>): Recipients {
return Object.assign(create(typeModels.Recipients, RecipientsTypeRef), values) return Object.assign(create(typeModels.Recipients, RecipientsTypeRef), values)
} }
@ -1572,7 +1572,7 @@ export type Recipients = {
} }
export const RemoteImapSyncInfoTypeRef: TypeRef<RemoteImapSyncInfo> = new TypeRef("tutanota", "RemoteImapSyncInfo") export const RemoteImapSyncInfoTypeRef: TypeRef<RemoteImapSyncInfo> = new TypeRef("tutanota", "RemoteImapSyncInfo")
export function createRemoteImapSyncInfo(values: Partial<RemoteImapSyncInfo>): RemoteImapSyncInfo { export function createRemoteImapSyncInfo(values: StrippedEntity<RemoteImapSyncInfo>): RemoteImapSyncInfo {
return Object.assign(create(typeModels.RemoteImapSyncInfo, RemoteImapSyncInfoTypeRef), values) return Object.assign(create(typeModels.RemoteImapSyncInfo, RemoteImapSyncInfoTypeRef), values)
} }
@ -1589,7 +1589,7 @@ export type RemoteImapSyncInfo = {
} }
export const ReportMailPostDataTypeRef: TypeRef<ReportMailPostData> = new TypeRef("tutanota", "ReportMailPostData") export const ReportMailPostDataTypeRef: TypeRef<ReportMailPostData> = new TypeRef("tutanota", "ReportMailPostData")
export function createReportMailPostData(values: Partial<ReportMailPostData>): ReportMailPostData { export function createReportMailPostData(values: StrippedEntity<ReportMailPostData>): ReportMailPostData {
return Object.assign(create(typeModels.ReportMailPostData, ReportMailPostDataTypeRef), values) return Object.assign(create(typeModels.ReportMailPostData, ReportMailPostDataTypeRef), values)
} }
@ -1604,7 +1604,7 @@ export type ReportMailPostData = {
} }
export const ReportedMailFieldMarkerTypeRef: TypeRef<ReportedMailFieldMarker> = new TypeRef("tutanota", "ReportedMailFieldMarker") export const ReportedMailFieldMarkerTypeRef: TypeRef<ReportedMailFieldMarker> = new TypeRef("tutanota", "ReportedMailFieldMarker")
export function createReportedMailFieldMarker(values: Partial<ReportedMailFieldMarker>): ReportedMailFieldMarker { export function createReportedMailFieldMarker(values: StrippedEntity<ReportedMailFieldMarker>): ReportedMailFieldMarker {
return Object.assign(create(typeModels.ReportedMailFieldMarker, ReportedMailFieldMarkerTypeRef), values) return Object.assign(create(typeModels.ReportedMailFieldMarker, ReportedMailFieldMarkerTypeRef), values)
} }
@ -1617,7 +1617,7 @@ export type ReportedMailFieldMarker = {
} }
export const SecureExternalRecipientKeyDataTypeRef: TypeRef<SecureExternalRecipientKeyData> = new TypeRef("tutanota", "SecureExternalRecipientKeyData") export const SecureExternalRecipientKeyDataTypeRef: TypeRef<SecureExternalRecipientKeyData> = new TypeRef("tutanota", "SecureExternalRecipientKeyData")
export function createSecureExternalRecipientKeyData(values: Partial<SecureExternalRecipientKeyData>): SecureExternalRecipientKeyData { export function createSecureExternalRecipientKeyData(values: StrippedEntity<SecureExternalRecipientKeyData>): SecureExternalRecipientKeyData {
return Object.assign(create(typeModels.SecureExternalRecipientKeyData, SecureExternalRecipientKeyDataTypeRef), values) return Object.assign(create(typeModels.SecureExternalRecipientKeyData, SecureExternalRecipientKeyDataTypeRef), values)
} }
@ -1639,7 +1639,7 @@ export type SecureExternalRecipientKeyData = {
} }
export const SendDraftDataTypeRef: TypeRef<SendDraftData> = new TypeRef("tutanota", "SendDraftData") export const SendDraftDataTypeRef: TypeRef<SendDraftData> = new TypeRef("tutanota", "SendDraftData")
export function createSendDraftData(values: Partial<SendDraftData>): SendDraftData { export function createSendDraftData(values: StrippedEntity<SendDraftData>): SendDraftData {
return Object.assign(create(typeModels.SendDraftData, SendDraftDataTypeRef), values) return Object.assign(create(typeModels.SendDraftData, SendDraftDataTypeRef), values)
} }
@ -1661,7 +1661,7 @@ export type SendDraftData = {
} }
export const SendDraftReturnTypeRef: TypeRef<SendDraftReturn> = new TypeRef("tutanota", "SendDraftReturn") export const SendDraftReturnTypeRef: TypeRef<SendDraftReturn> = new TypeRef("tutanota", "SendDraftReturn")
export function createSendDraftReturn(values: Partial<SendDraftReturn>): SendDraftReturn { export function createSendDraftReturn(values: StrippedEntity<SendDraftReturn>): SendDraftReturn {
return Object.assign(create(typeModels.SendDraftReturn, SendDraftReturnTypeRef), values) return Object.assign(create(typeModels.SendDraftReturn, SendDraftReturnTypeRef), values)
} }
@ -1677,7 +1677,7 @@ export type SendDraftReturn = {
} }
export const SharedGroupDataTypeRef: TypeRef<SharedGroupData> = new TypeRef("tutanota", "SharedGroupData") export const SharedGroupDataTypeRef: TypeRef<SharedGroupData> = new TypeRef("tutanota", "SharedGroupData")
export function createSharedGroupData(values: Partial<SharedGroupData>): SharedGroupData { export function createSharedGroupData(values: StrippedEntity<SharedGroupData>): SharedGroupData {
return Object.assign(create(typeModels.SharedGroupData, SharedGroupDataTypeRef), values) return Object.assign(create(typeModels.SharedGroupData, SharedGroupDataTypeRef), values)
} }
@ -1696,7 +1696,7 @@ export type SharedGroupData = {
} }
export const SpamResultsTypeRef: TypeRef<SpamResults> = new TypeRef("tutanota", "SpamResults") export const SpamResultsTypeRef: TypeRef<SpamResults> = new TypeRef("tutanota", "SpamResults")
export function createSpamResults(values: Partial<SpamResults>): SpamResults { export function createSpamResults(values: StrippedEntity<SpamResults>): SpamResults {
return Object.assign(create(typeModels.SpamResults, SpamResultsTypeRef), values) return Object.assign(create(typeModels.SpamResults, SpamResultsTypeRef), values)
} }
@ -1709,7 +1709,7 @@ export type SpamResults = {
} }
export const SubfilesTypeRef: TypeRef<Subfiles> = new TypeRef("tutanota", "Subfiles") export const SubfilesTypeRef: TypeRef<Subfiles> = new TypeRef("tutanota", "Subfiles")
export function createSubfiles(values: Partial<Subfiles>): Subfiles { export function createSubfiles(values: StrippedEntity<Subfiles>): Subfiles {
return Object.assign(create(typeModels.Subfiles, SubfilesTypeRef), values) return Object.assign(create(typeModels.Subfiles, SubfilesTypeRef), values)
} }
@ -1722,7 +1722,7 @@ export type Subfiles = {
} }
export const TemplateGroupRootTypeRef: TypeRef<TemplateGroupRoot> = new TypeRef("tutanota", "TemplateGroupRoot") export const TemplateGroupRootTypeRef: TypeRef<TemplateGroupRoot> = new TypeRef("tutanota", "TemplateGroupRoot")
export function createTemplateGroupRoot(values: Partial<TemplateGroupRoot>): TemplateGroupRoot { export function createTemplateGroupRoot(values: StrippedEntity<TemplateGroupRoot>): TemplateGroupRoot {
return Object.assign(create(typeModels.TemplateGroupRoot, TemplateGroupRootTypeRef), values) return Object.assign(create(typeModels.TemplateGroupRoot, TemplateGroupRootTypeRef), values)
} }
@ -1741,7 +1741,7 @@ export type TemplateGroupRoot = {
} }
export const TutanotaPropertiesTypeRef: TypeRef<TutanotaProperties> = new TypeRef("tutanota", "TutanotaProperties") export const TutanotaPropertiesTypeRef: TypeRef<TutanotaProperties> = new TypeRef("tutanota", "TutanotaProperties")
export function createTutanotaProperties(values: Partial<TutanotaProperties>): TutanotaProperties { export function createTutanotaProperties(values: StrippedEntity<TutanotaProperties>): TutanotaProperties {
return Object.assign(create(typeModels.TutanotaProperties, TutanotaPropertiesTypeRef), values) return Object.assign(create(typeModels.TutanotaProperties, TutanotaPropertiesTypeRef), values)
} }
@ -1770,7 +1770,7 @@ export type TutanotaProperties = {
} }
export const UpdateMailFolderDataTypeRef: TypeRef<UpdateMailFolderData> = new TypeRef("tutanota", "UpdateMailFolderData") export const UpdateMailFolderDataTypeRef: TypeRef<UpdateMailFolderData> = new TypeRef("tutanota", "UpdateMailFolderData")
export function createUpdateMailFolderData(values: Partial<UpdateMailFolderData>): UpdateMailFolderData { export function createUpdateMailFolderData(values: StrippedEntity<UpdateMailFolderData>): UpdateMailFolderData {
return Object.assign(create(typeModels.UpdateMailFolderData, UpdateMailFolderDataTypeRef), values) return Object.assign(create(typeModels.UpdateMailFolderData, UpdateMailFolderDataTypeRef), values)
} }
@ -1784,7 +1784,7 @@ export type UpdateMailFolderData = {
} }
export const UserAccountCreateDataTypeRef: TypeRef<UserAccountCreateData> = new TypeRef("tutanota", "UserAccountCreateData") export const UserAccountCreateDataTypeRef: TypeRef<UserAccountCreateData> = new TypeRef("tutanota", "UserAccountCreateData")
export function createUserAccountCreateData(values: Partial<UserAccountCreateData>): UserAccountCreateData { export function createUserAccountCreateData(values: StrippedEntity<UserAccountCreateData>): UserAccountCreateData {
return Object.assign(create(typeModels.UserAccountCreateData, UserAccountCreateDataTypeRef), values) return Object.assign(create(typeModels.UserAccountCreateData, UserAccountCreateDataTypeRef), values)
} }
@ -1799,7 +1799,7 @@ export type UserAccountCreateData = {
} }
export const UserAccountUserDataTypeRef: TypeRef<UserAccountUserData> = new TypeRef("tutanota", "UserAccountUserData") export const UserAccountUserDataTypeRef: TypeRef<UserAccountUserData> = new TypeRef("tutanota", "UserAccountUserData")
export function createUserAccountUserData(values: Partial<UserAccountUserData>): UserAccountUserData { export function createUserAccountUserData(values: StrippedEntity<UserAccountUserData>): UserAccountUserData {
return Object.assign(create(typeModels.UserAccountUserData, UserAccountUserDataTypeRef), values) return Object.assign(create(typeModels.UserAccountUserData, UserAccountUserDataTypeRef), values)
} }
@ -1832,7 +1832,7 @@ export type UserAccountUserData = {
} }
export const UserAreaGroupDataTypeRef: TypeRef<UserAreaGroupData> = new TypeRef("tutanota", "UserAreaGroupData") export const UserAreaGroupDataTypeRef: TypeRef<UserAreaGroupData> = new TypeRef("tutanota", "UserAreaGroupData")
export function createUserAreaGroupData(values: Partial<UserAreaGroupData>): UserAreaGroupData { export function createUserAreaGroupData(values: StrippedEntity<UserAreaGroupData>): UserAreaGroupData {
return Object.assign(create(typeModels.UserAreaGroupData, UserAreaGroupDataTypeRef), values) return Object.assign(create(typeModels.UserAreaGroupData, UserAreaGroupDataTypeRef), values)
} }
@ -1850,7 +1850,7 @@ export type UserAreaGroupData = {
} }
export const UserAreaGroupDeleteDataTypeRef: TypeRef<UserAreaGroupDeleteData> = new TypeRef("tutanota", "UserAreaGroupDeleteData") export const UserAreaGroupDeleteDataTypeRef: TypeRef<UserAreaGroupDeleteData> = new TypeRef("tutanota", "UserAreaGroupDeleteData")
export function createUserAreaGroupDeleteData(values: Partial<UserAreaGroupDeleteData>): UserAreaGroupDeleteData { export function createUserAreaGroupDeleteData(values: StrippedEntity<UserAreaGroupDeleteData>): UserAreaGroupDeleteData {
return Object.assign(create(typeModels.UserAreaGroupDeleteData, UserAreaGroupDeleteDataTypeRef), values) return Object.assign(create(typeModels.UserAreaGroupDeleteData, UserAreaGroupDeleteDataTypeRef), values)
} }
@ -1863,7 +1863,7 @@ export type UserAreaGroupDeleteData = {
} }
export const UserAreaGroupPostDataTypeRef: TypeRef<UserAreaGroupPostData> = new TypeRef("tutanota", "UserAreaGroupPostData") export const UserAreaGroupPostDataTypeRef: TypeRef<UserAreaGroupPostData> = new TypeRef("tutanota", "UserAreaGroupPostData")
export function createUserAreaGroupPostData(values: Partial<UserAreaGroupPostData>): UserAreaGroupPostData { export function createUserAreaGroupPostData(values: StrippedEntity<UserAreaGroupPostData>): UserAreaGroupPostData {
return Object.assign(create(typeModels.UserAreaGroupPostData, UserAreaGroupPostDataTypeRef), values) return Object.assign(create(typeModels.UserAreaGroupPostData, UserAreaGroupPostDataTypeRef), values)
} }
@ -1876,7 +1876,7 @@ export type UserAreaGroupPostData = {
} }
export const UserSettingsGroupRootTypeRef: TypeRef<UserSettingsGroupRoot> = new TypeRef("tutanota", "UserSettingsGroupRoot") export const UserSettingsGroupRootTypeRef: TypeRef<UserSettingsGroupRoot> = new TypeRef("tutanota", "UserSettingsGroupRoot")
export function createUserSettingsGroupRoot(values: Partial<UserSettingsGroupRoot>): UserSettingsGroupRoot { export function createUserSettingsGroupRoot(values: StrippedEntity<UserSettingsGroupRoot>): UserSettingsGroupRoot {
return Object.assign(create(typeModels.UserSettingsGroupRoot, UserSettingsGroupRootTypeRef), values) return Object.assign(create(typeModels.UserSettingsGroupRoot, UserSettingsGroupRootTypeRef), values)
} }

View file

@ -1,11 +1,11 @@
import {create} from "../../common/utils/EntityUtils.js" import { create, Stripped, StrippedEntity } from "../../common/utils/EntityUtils.js"
import {TypeRef} from "@tutao/tutanota-utils" import {TypeRef} from "@tutao/tutanota-utils"
import {typeModels} from "./TypeModels.js" import {typeModels} from "./TypeModels.js"
export const UsageTestAssignmentTypeRef: TypeRef<UsageTestAssignment> = new TypeRef("usage", "UsageTestAssignment") export const UsageTestAssignmentTypeRef: TypeRef<UsageTestAssignment> = new TypeRef("usage", "UsageTestAssignment")
export function createUsageTestAssignment(values: Partial<UsageTestAssignment>): UsageTestAssignment { export function createUsageTestAssignment(values: StrippedEntity<UsageTestAssignment>): UsageTestAssignment {
return Object.assign(create(typeModels.UsageTestAssignment, UsageTestAssignmentTypeRef), values) return Object.assign(create(typeModels.UsageTestAssignment, UsageTestAssignmentTypeRef), values)
} }
@ -22,7 +22,7 @@ export type UsageTestAssignment = {
} }
export const UsageTestAssignmentInTypeRef: TypeRef<UsageTestAssignmentIn> = new TypeRef("usage", "UsageTestAssignmentIn") export const UsageTestAssignmentInTypeRef: TypeRef<UsageTestAssignmentIn> = new TypeRef("usage", "UsageTestAssignmentIn")
export function createUsageTestAssignmentIn(values: Partial<UsageTestAssignmentIn>): UsageTestAssignmentIn { export function createUsageTestAssignmentIn(values: StrippedEntity<UsageTestAssignmentIn>): UsageTestAssignmentIn {
return Object.assign(create(typeModels.UsageTestAssignmentIn, UsageTestAssignmentInTypeRef), values) return Object.assign(create(typeModels.UsageTestAssignmentIn, UsageTestAssignmentInTypeRef), values)
} }
@ -34,7 +34,7 @@ export type UsageTestAssignmentIn = {
} }
export const UsageTestAssignmentOutTypeRef: TypeRef<UsageTestAssignmentOut> = new TypeRef("usage", "UsageTestAssignmentOut") export const UsageTestAssignmentOutTypeRef: TypeRef<UsageTestAssignmentOut> = new TypeRef("usage", "UsageTestAssignmentOut")
export function createUsageTestAssignmentOut(values: Partial<UsageTestAssignmentOut>): UsageTestAssignmentOut { export function createUsageTestAssignmentOut(values: StrippedEntity<UsageTestAssignmentOut>): UsageTestAssignmentOut {
return Object.assign(create(typeModels.UsageTestAssignmentOut, UsageTestAssignmentOutTypeRef), values) return Object.assign(create(typeModels.UsageTestAssignmentOut, UsageTestAssignmentOutTypeRef), values)
} }
@ -48,7 +48,7 @@ export type UsageTestAssignmentOut = {
} }
export const UsageTestMetricConfigTypeRef: TypeRef<UsageTestMetricConfig> = new TypeRef("usage", "UsageTestMetricConfig") export const UsageTestMetricConfigTypeRef: TypeRef<UsageTestMetricConfig> = new TypeRef("usage", "UsageTestMetricConfig")
export function createUsageTestMetricConfig(values: Partial<UsageTestMetricConfig>): UsageTestMetricConfig { export function createUsageTestMetricConfig(values: StrippedEntity<UsageTestMetricConfig>): UsageTestMetricConfig {
return Object.assign(create(typeModels.UsageTestMetricConfig, UsageTestMetricConfigTypeRef), values) return Object.assign(create(typeModels.UsageTestMetricConfig, UsageTestMetricConfigTypeRef), values)
} }
@ -63,7 +63,7 @@ export type UsageTestMetricConfig = {
} }
export const UsageTestMetricConfigValueTypeRef: TypeRef<UsageTestMetricConfigValue> = new TypeRef("usage", "UsageTestMetricConfigValue") export const UsageTestMetricConfigValueTypeRef: TypeRef<UsageTestMetricConfigValue> = new TypeRef("usage", "UsageTestMetricConfigValue")
export function createUsageTestMetricConfigValue(values: Partial<UsageTestMetricConfigValue>): UsageTestMetricConfigValue { export function createUsageTestMetricConfigValue(values: StrippedEntity<UsageTestMetricConfigValue>): UsageTestMetricConfigValue {
return Object.assign(create(typeModels.UsageTestMetricConfigValue, UsageTestMetricConfigValueTypeRef), values) return Object.assign(create(typeModels.UsageTestMetricConfigValue, UsageTestMetricConfigValueTypeRef), values)
} }
@ -76,7 +76,7 @@ export type UsageTestMetricConfigValue = {
} }
export const UsageTestMetricDataTypeRef: TypeRef<UsageTestMetricData> = new TypeRef("usage", "UsageTestMetricData") export const UsageTestMetricDataTypeRef: TypeRef<UsageTestMetricData> = new TypeRef("usage", "UsageTestMetricData")
export function createUsageTestMetricData(values: Partial<UsageTestMetricData>): UsageTestMetricData { export function createUsageTestMetricData(values: StrippedEntity<UsageTestMetricData>): UsageTestMetricData {
return Object.assign(create(typeModels.UsageTestMetricData, UsageTestMetricDataTypeRef), values) return Object.assign(create(typeModels.UsageTestMetricData, UsageTestMetricDataTypeRef), values)
} }
@ -89,7 +89,7 @@ export type UsageTestMetricData = {
} }
export const UsageTestParticipationInTypeRef: TypeRef<UsageTestParticipationIn> = new TypeRef("usage", "UsageTestParticipationIn") export const UsageTestParticipationInTypeRef: TypeRef<UsageTestParticipationIn> = new TypeRef("usage", "UsageTestParticipationIn")
export function createUsageTestParticipationIn(values: Partial<UsageTestParticipationIn>): UsageTestParticipationIn { export function createUsageTestParticipationIn(values: StrippedEntity<UsageTestParticipationIn>): UsageTestParticipationIn {
return Object.assign(create(typeModels.UsageTestParticipationIn, UsageTestParticipationInTypeRef), values) return Object.assign(create(typeModels.UsageTestParticipationIn, UsageTestParticipationInTypeRef), values)
} }
@ -105,7 +105,7 @@ export type UsageTestParticipationIn = {
} }
export const UsageTestStageTypeRef: TypeRef<UsageTestStage> = new TypeRef("usage", "UsageTestStage") export const UsageTestStageTypeRef: TypeRef<UsageTestStage> = new TypeRef("usage", "UsageTestStage")
export function createUsageTestStage(values: Partial<UsageTestStage>): UsageTestStage { export function createUsageTestStage(values: StrippedEntity<UsageTestStage>): UsageTestStage {
return Object.assign(create(typeModels.UsageTestStage, UsageTestStageTypeRef), values) return Object.assign(create(typeModels.UsageTestStage, UsageTestStageTypeRef), values)
} }

View file

@ -382,15 +382,22 @@ export async function initUserController({ user, userGroupInfo, sessionId, acces
const entityClient = locator.entityClient const entityClient = locator.entityClient
const [props, userSettingsGroupRoot] = await Promise.all([ const [props, userSettingsGroupRoot] = await Promise.all([
entityClient.loadRoot(TutanotaPropertiesTypeRef, user.userGroup.group), entityClient.loadRoot(TutanotaPropertiesTypeRef, user.userGroup.group),
entityClient entityClient.load(UserSettingsGroupRootTypeRef, user.userGroup.group).catch(
.load(UserSettingsGroupRootTypeRef, user.userGroup.group) ofClass(NotFoundError, () =>
.catch( entityClient
ofClass(NotFoundError, () => .setup(
entityClient null,
.setup(null, createUserSettingsGroupRoot({ _ownerGroup: user.userGroup.group })) createUserSettingsGroupRoot({
.then(() => entityClient.load(UserSettingsGroupRootTypeRef, user.userGroup.group)), _ownerGroup: user.userGroup.group,
), startOfTheWeek: "0",
timeFormat: "0",
groupSettings: [],
usageDataOptedIn: null,
}),
)
.then(() => entityClient.load(UserSettingsGroupRootTypeRef, user.userGroup.group)),
), ),
),
]) ])
return new UserController(user, userGroupInfo, sessionId, props, accessToken, userSettingsGroupRoot, sessionType, entityClient, locator.serviceExecutor) return new UserController(user, userGroupInfo, sessionId, props, accessToken, userSettingsGroupRoot, sessionType, entityClient, locator.serviceExecutor)
} }

View file

@ -63,6 +63,7 @@ export class BlobAccessTokenFacade {
write: createBlobWriteData({ write: createBlobWriteData({
archiveOwnerGroup: ownerGroupId, archiveOwnerGroup: ownerGroupId,
}), }),
read: null,
}) })
const { blobAccessInfo } = await this.serviceExecutor.post(BlobAccessTokenService, tokenRequest) const { blobAccessInfo } = await this.serviceExecutor.post(BlobAccessTokenService, tokenRequest)
return blobAccessInfo return blobAccessInfo
@ -104,6 +105,7 @@ export class BlobAccessTokenFacade {
instanceListId, instanceListId,
instanceIds, instanceIds,
}), }),
write: null,
}) })
const { blobAccessInfo } = await this.serviceExecutor.post(BlobAccessTokenService, tokenRequest) const { blobAccessInfo } = await this.serviceExecutor.post(BlobAccessTokenService, tokenRequest)
return blobAccessInfo return blobAccessInfo
@ -130,7 +132,9 @@ export class BlobAccessTokenFacade {
read: createBlobReadData({ read: createBlobReadData({
archiveId, archiveId,
instanceIds: [], instanceIds: [],
instanceListId: null,
}), }),
write: null,
}) })
const { blobAccessInfo } = await this.serviceExecutor.post(BlobAccessTokenService, tokenRequest) const { blobAccessInfo } = await this.serviceExecutor.post(BlobAccessTokenService, tokenRequest)
return blobAccessInfo return blobAccessInfo

View file

@ -215,9 +215,13 @@ export class LoginFacade {
// the verifier is always sent as url parameter, so it must be url encoded // the verifier is always sent as url parameter, so it must be url encoded
const authVerifier = createAuthVerifierAsBase64Url(userPassphraseKey) const authVerifier = createAuthVerifierAsBase64Url(userPassphraseKey)
const createSessionData = createCreateSessionData({ const createSessionData = createCreateSessionData({
mailAddress: mailAddress.toLowerCase().trim(), accessKey: null,
clientIdentifier, authToken: null,
authVerifier, authVerifier,
clientIdentifier,
mailAddress: mailAddress.toLowerCase().trim(),
recoverCodeVerifier: null,
user: null,
}) })
let accessKey: Aes128Key | null = null let accessKey: Aes128Key | null = null
@ -342,10 +346,13 @@ export class LoginFacade {
const authVerifier = createAuthVerifierAsBase64Url(userPassphraseKey) const authVerifier = createAuthVerifierAsBase64Url(userPassphraseKey)
const authToken = base64ToBase64Url(uint8ArrayToBase64(sha256Hash(salt))) const authToken = base64ToBase64Url(uint8ArrayToBase64(sha256Hash(salt)))
const sessionData = createCreateSessionData({ const sessionData = createCreateSessionData({
user: userId, accessKey: null,
authToken, authToken,
clientIdentifier,
authVerifier, authVerifier,
clientIdentifier,
mailAddress: null,
recoverCodeVerifier: null,
user: userId,
}) })
let accessKey: Aes128Key | null = null let accessKey: Aes128Key | null = null
@ -795,11 +802,13 @@ export class LoginFacade {
const pwEncUserGroupKey = encryptKey(newUserPassphraseKey, this.userFacade.getUserGroupKey()) const pwEncUserGroupKey = encryptKey(newUserPassphraseKey, this.userFacade.getUserGroupKey())
const authVerifier = createAuthVerifier(newUserPassphraseKey) const authVerifier = createAuthVerifier(newUserPassphraseKey)
const service = createChangePasswordData({ const service = createChangePasswordData({
code: null,
kdfVersion: newKdfType, kdfVersion: newKdfType,
oldVerifier: currentAuthVerifier, oldVerifier: currentAuthVerifier,
pwEncUserGroupKey: pwEncUserGroupKey,
recoverCodeVerifier: null,
salt: salt, salt: salt,
verifier: authVerifier, verifier: authVerifier,
pwEncUserGroupKey: pwEncUserGroupKey,
}) })
await this.serviceExecutor.post(ChangePasswordService, service) await this.serviceExecutor.post(ChangePasswordService, service)
@ -811,9 +820,10 @@ export class LoginFacade {
const passwordKey = await this.deriveUserPassphraseKey(asKdfType(this.userFacade.getLoggedInUser().kdfVersion), password, userSalt) const passwordKey = await this.deriveUserPassphraseKey(asKdfType(this.userFacade.getLoggedInUser().kdfVersion), password, userSalt)
const deleteCustomerData = createDeleteCustomerData({ const deleteCustomerData = createDeleteCustomerData({
authVerifier: createAuthVerifier(passwordKey), authVerifier: createAuthVerifier(passwordKey),
reason: reason,
takeoverMailAddress: null,
undelete: false, undelete: false,
customer: neverNull(neverNull(this.userFacade.getLoggedInUser()).customer), customer: neverNull(neverNull(this.userFacade.getLoggedInUser()).customer),
reason: reason,
}) })
if (takeover !== "") { if (takeover !== "") {
@ -830,9 +840,13 @@ export class LoginFacade {
const recoverCodeVerifier = createAuthVerifier(recoverCodeKey) const recoverCodeVerifier = createAuthVerifier(recoverCodeKey)
const recoverCodeVerifierBase64 = base64ToBase64Url(uint8ArrayToBase64(recoverCodeVerifier)) const recoverCodeVerifierBase64 = base64ToBase64Url(uint8ArrayToBase64(recoverCodeVerifier))
const sessionData = createCreateSessionData({ const sessionData = createCreateSessionData({
mailAddress: mailAddress.toLowerCase().trim(), accessKey: null,
authToken: null,
authVerifier: null,
clientIdentifier: clientIdentifier, clientIdentifier: clientIdentifier,
mailAddress: mailAddress.toLowerCase().trim(),
recoverCodeVerifier: recoverCodeVerifierBase64, recoverCodeVerifier: recoverCodeVerifierBase64,
user: null,
}) })
// we need a separate entity rest client because to avoid caching of the user instance which is updated on password change. the web socket is not connected because we // we need a separate entity rest client because to avoid caching of the user instance which is updated on password change. the web socket is not connected because we
// don't do a normal login and therefore we would not get any user update events. we can not use permanentLogin=false with initSession because caching would be enabled // don't do a normal login and therefore we would not get any user update events. we can not use permanentLogin=false with initSession because caching would be enabled
@ -878,8 +892,10 @@ export class LoginFacade {
const pwEncUserGroupKey = encryptKey(userPassphraseKey, groupKey) const pwEncUserGroupKey = encryptKey(userPassphraseKey, groupKey)
const newPasswordVerifier = createAuthVerifier(userPassphraseKey) const newPasswordVerifier = createAuthVerifier(userPassphraseKey)
const postData = createChangePasswordData({ const postData = createChangePasswordData({
salt: salt, code: null,
kdfVersion: newKdfType, kdfVersion: newKdfType,
oldVerifier: null,
salt: salt,
pwEncUserGroupKey: pwEncUserGroupKey, pwEncUserGroupKey: pwEncUserGroupKey,
verifier: newPasswordVerifier, verifier: newPasswordVerifier,
recoverCodeVerifier: recoverCodeVerifier, recoverCodeVerifier: recoverCodeVerifier,

View file

@ -250,6 +250,7 @@ export class BlobFacade {
const getData = createBlobGetIn({ const getData = createBlobGetIn({
archiveId, archiveId,
blobId, blobId,
blobIds: [],
}) })
const BlobGetInTypeModel = await resolveTypeReference(BlobGetInTypeRef) const BlobGetInTypeModel = await resolveTypeReference(BlobGetInTypeRef)
const literalGetData = await this.instanceMapper.encryptAndMapToLiteral(BlobGetInTypeModel, getData, null) const literalGetData = await this.instanceMapper.encryptAndMapToLiteral(BlobGetInTypeModel, getData, null)
@ -276,6 +277,7 @@ export class BlobFacade {
const getData = createBlobGetIn({ const getData = createBlobGetIn({
archiveId, archiveId,
blobId, blobId,
blobIds: [],
}) })
const BlobGetInTypeModel = await resolveTypeReference(BlobGetInTypeRef) const BlobGetInTypeModel = await resolveTypeReference(BlobGetInTypeRef)
const literalGetData = await this.instanceMapper.encryptAndMapToLiteral(BlobGetInTypeModel, getData, null) const literalGetData = await this.instanceMapper.encryptAndMapToLiteral(BlobGetInTypeModel, getData, null)

View file

@ -40,7 +40,10 @@ export class BookingFacade {
* @return Resolves to PriceServiceReturn or an exception if the loading failed. * @return Resolves to PriceServiceReturn or an exception if the loading failed.
*/ */
getCurrentPrice(): Promise<PriceServiceReturn> { getCurrentPrice(): Promise<PriceServiceReturn> {
const serviceData = createPriceServiceData({}) const serviceData = createPriceServiceData({
date: null,
priceRequest: null,
})
return this.serviceExecutor.get(PriceService, serviceData) return this.serviceExecutor.get(PriceService, serviceData)
} }

View file

@ -23,6 +23,7 @@ export class CounterFacade {
const counterData = createReadCounterData({ const counterData = createReadCounterData({
counterType, counterType,
rowName: customerId, rowName: customerId,
columnName: null,
}) })
const counterReturn = await this.serviceExecutor.get(CounterService, counterData) const counterReturn = await this.serviceExecutor.get(CounterService, counterData)
return counterReturn.counterValues return counterReturn.counterValues

View file

@ -83,6 +83,7 @@ export class CustomerFacade {
addDomain(domainName: string): Promise<CustomDomainReturn> { addDomain(domainName: string): Promise<CustomDomainReturn> {
const data = createCustomDomainData({ const data = createCustomDomainData({
domain: domainName.trim().toLowerCase(), domain: domainName.trim().toLowerCase(),
catchAllMailGroup: null,
}) })
return this.serviceExecutor.post(CustomDomainService, data) return this.serviceExecutor.post(CustomDomainService, data)
} }
@ -90,6 +91,7 @@ export class CustomerFacade {
async removeDomain(domainName: string): Promise<void> { async removeDomain(domainName: string): Promise<void> {
const data = createCustomDomainData({ const data = createCustomDomainData({
domain: domainName.trim().toLowerCase(), domain: domainName.trim().toLowerCase(),
catchAllMailGroup: null,
}) })
await this.serviceExecutor.delete(CustomDomainService, data) await this.serviceExecutor.delete(CustomDomainService, data)
} }
@ -115,6 +117,8 @@ export class CustomerFacade {
const data = createBrandingDomainData({ const data = createBrandingDomainData({
domain: domainName, domain: domainName,
systemAdminPubEncSessionKey: systemAdminPubEncAccountingInfoSessionKey, systemAdminPubEncSessionKey: systemAdminPubEncAccountingInfoSessionKey,
sessionEncPemPrivateKey: null,
sessionEncPemCertificateChain: null,
}) })
if (existingBrandingDomain) { if (existingBrandingDomain) {
await this.serviceExecutor.put(BrandingDomainService, data) await this.serviceExecutor.put(BrandingDomainService, data)
@ -303,6 +307,7 @@ export class CustomerFacade {
adminEncAccountingInfoSessionKey: encryptKey(adminGroupKey, accountingInfoSessionKey), adminEncAccountingInfoSessionKey: encryptKey(adminGroupKey, accountingInfoSessionKey),
systemAdminPubEncAccountingInfoSessionKey, systemAdminPubEncAccountingInfoSessionKey,
adminEncCustomerServerPropertiesSessionKey: encryptKey(adminGroupKey, customerServerPropertiesSessionKey), adminEncCustomerServerPropertiesSessionKey: encryptKey(adminGroupKey, customerServerPropertiesSessionKey),
userEncAccountGroupKey: new Uint8Array(0),
}) })
await this.serviceExecutor.post(CustomerAccountService, data) await this.serviceExecutor.post(CustomerAccountService, data)
return recoverData.hexCode return recoverData.hexCode
@ -398,6 +403,7 @@ export class CustomerFacade {
async downloadInvoice(invoiceNumber: string): Promise<DataFile> { async downloadInvoice(invoiceNumber: string): Promise<DataFile> {
const data = createPdfInvoiceServiceData({ const data = createPdfInvoiceServiceData({
invoiceNumber, invoiceNumber,
invoice: null,
}) })
return this.serviceExecutor.get(PdfInvoiceService, data).then((returnData) => { return this.serviceExecutor.get(PdfInvoiceService, data).then((returnData) => {
return { return {

View file

@ -61,6 +61,7 @@ export class GiftCardFacade {
createGiftCardRedeemData({ createGiftCardRedeemData({
giftCardInfo: id, giftCardInfo: id,
keyHash: sha256Hash(bitArrayToUint8Array(base64ToKey(key))), keyHash: sha256Hash(bitArrayToUint8Array(base64ToKey(key))),
countryCode: "",
}), }),
{ {
sessionKey: base64ToKey(key), sessionKey: base64ToKey(key),

View file

@ -112,7 +112,10 @@ export class MailAddressFacade {
const mailboxProperties = await this.getOrCreateMailboxProperties(mailGroupId, viaUser) const mailboxProperties = await this.getOrCreateMailboxProperties(mailGroupId, viaUser)
let mailAddressProperty = mailboxProperties.mailAddressProperties.find((p) => p.mailAddress === mailAddress) let mailAddressProperty = mailboxProperties.mailAddressProperties.find((p) => p.mailAddress === mailAddress)
if (mailAddressProperty == null) { if (mailAddressProperty == null) {
mailAddressProperty = createMailAddressProperties({ mailAddress }) mailAddressProperty = createMailAddressProperties({
mailAddress,
senderName: "",
})
mailboxProperties.mailAddressProperties.push(mailAddressProperty) mailboxProperties.mailAddressProperties.push(mailAddressProperty)
} }
mailAddressProperty.senderName = senderName mailAddressProperty.senderName = senderName
@ -181,12 +184,13 @@ export class MailAddressFacade {
} }
private async createMailboxProperties(mailboxGroupRoot: MailboxGroupRoot, groupKey: Aes128Key): Promise<Id> { private async createMailboxProperties(mailboxGroupRoot: MailboxGroupRoot, groupKey: Aes128Key): Promise<Id> {
// Using non-caching entityClient because we are not a member of the user's mail group and we won't receive updates for it const _ownerGroup = mailboxGroupRoot._ownerGroup
const mailboxProperties = createMailboxProperties({ const mailboxProperties = createMailboxProperties({
_ownerGroup: mailboxGroupRoot._ownerGroup, ...(_ownerGroup != null ? { _ownerGroup } : null), // only set it if it is not null
reportMovedMails: "", reportMovedMails: "",
mailAddressProperties: [], mailAddressProperties: [],
}) })
// Using non-caching entityClient because we are not a member of the user's mail group and we won't receive updates for it
return this.nonCachingEntityClient.setup(null, mailboxProperties, undefined, { ownerKey: groupKey }).catch( return this.nonCachingEntityClient.setup(null, mailboxProperties, undefined, { ownerKey: groupKey }).catch(
ofClass(PreconditionFailedError, (e) => { ofClass(PreconditionFailedError, (e) => {
// in admin case it is much harder to run into it because we use non-caching entityClient but it is still possible // in admin case it is much harder to run into it because we use non-caching entityClient but it is still possible

View file

@ -260,6 +260,8 @@ export class MailFacade {
bccRecipients: bccRecipients.map(recipientToDraftRecipient), bccRecipients: bccRecipients.map(recipientToDraftRecipient),
replyTos: replyTos.map(recipientToEncryptedMailAddress), replyTos: replyTos.map(recipientToEncryptedMailAddress),
addedAttachments: await this._createAddedAttachments(attachments, [], senderMailGroupId, mailGroupKey), addedAttachments: await this._createAddedAttachments(attachments, [], senderMailGroupId, mailGroupKey),
bodyText: "",
removedAttachments: [],
}), }),
}) })
const createDraftReturn = await this.serviceExecutor.post(DraftService, service, { sessionKey: sk }) const createDraftReturn = await this.serviceExecutor.post(DraftService, service, { sessionKey: sk })
@ -318,6 +320,7 @@ export class MailFacade {
replyTos: replyTos, replyTos: replyTos,
removedAttachments: this._getRemovedAttachments(attachments, currentAttachments), removedAttachments: this._getRemovedAttachments(attachments, currentAttachments),
addedAttachments: await this._createAddedAttachments(attachments, currentAttachments, senderMailGroupId, mailGroupKey), addedAttachments: await this._createAddedAttachments(attachments, currentAttachments, senderMailGroupId, mailGroupKey),
bodyText: "",
}), }),
}) })
this.deferredDraftId = draft._id this.deferredDraftId = draft._id
@ -417,6 +420,7 @@ export class MailFacade {
const attachment = createDraftAttachment({ const attachment = createDraftAttachment({
existingFile: getLetId(providedFile), existingFile: getLetId(providedFile),
ownerEncFileSessionKey: encryptKey(mailGroupKey, assertNotNull(fileSessionKey, "filesessionkey was not resolved")), ownerEncFileSessionKey: encryptKey(mailGroupKey, assertNotNull(fileSessionKey, "filesessionkey was not resolved")),
newFile: null,
}) })
return attachment return attachment
}) })
@ -449,6 +453,7 @@ export class MailFacade {
encCid: providedFile.cid == null ? null : encryptString(fileSessionKey, providedFile.cid), encCid: providedFile.cid == null ? null : encryptString(fileSessionKey, providedFile.cid),
}), }),
ownerEncFileSessionKey: encryptKey(mailGroupKey, fileSessionKey), ownerEncFileSessionKey: encryptKey(mailGroupKey, fileSessionKey),
existingFile: null,
}) })
} }
@ -458,6 +463,14 @@ export class MailFacade {
const sendDraftData = createSendDraftData({ const sendDraftData = createSendDraftData({
language: language, language: language,
mail: draft._id, mail: draft._id,
mailSessionKey: null,
attachmentKeyData: [],
calendarMethod: false,
internalRecipientKeyData: [],
plaintext: false,
bucketEncMailSessionKey: null,
senderNameUnencrypted: null,
secureExternalRecipientKeyData: [],
}) })
const attachments = await this.getAttachmentIds(draft) const attachments = await this.getAttachmentIds(draft)
@ -466,6 +479,8 @@ export class MailFacade {
const fileSessionKey = assertNotNull(await this.crypto.resolveSessionKeyForInstance(file), "fileSessionKey was null") const fileSessionKey = assertNotNull(await this.crypto.resolveSessionKeyForInstance(file), "fileSessionKey was null")
const data = createAttachmentKeyData({ const data = createAttachmentKeyData({
file: fileId, file: fileId,
fileSessionKey: null,
bucketEncFileSessionKey: null,
}) })
if (draft.confidential) { if (draft.confidential) {
@ -650,6 +665,8 @@ export class MailFacade {
salt: salt, salt: salt,
saltHash: sha256Hash(salt), saltHash: sha256Hash(salt),
pwEncCommunicationKey: encryptKey(passwordKey, externalGroupKeys.externalUserGroupKey), pwEncCommunicationKey: encryptKey(passwordKey, externalGroupKeys.externalUserGroupKey),
autoTransmitPassword: null,
passwordChannelPhoneNumbers: [],
}) })
service.secureExternalRecipientKeyData.push(data) service.secureExternalRecipientKeyData.push(data)
} else { } else {
@ -742,6 +759,7 @@ export class MailFacade {
externalUserEncTutanotaPropertiesSessionKey: encryptKey(externalUserGroupKey, tutanotaPropertiesSessionKey), externalUserEncTutanotaPropertiesSessionKey: encryptKey(externalUserGroupKey, tutanotaPropertiesSessionKey),
externalMailEncMailBoxSessionKey: encryptKey(externalMailGroupKey, mailboxSessionKey), externalMailEncMailBoxSessionKey: encryptKey(externalMailGroupKey, mailboxSessionKey),
userGroupData: userGroupData, userGroupData: userGroupData,
kdfVersion: "0",
}) })
return this.serviceExecutor.post(ExternalUserService, d).then(() => { return this.serviceExecutor.post(ExternalUserService, d).then(() => {
return { return {
@ -824,6 +842,7 @@ export class MailFacade {
async clearFolder(folderId: IdTuple) { async clearFolder(folderId: IdTuple) {
const deleteMailData = createDeleteMailData({ const deleteMailData = createDeleteMailData({
folder: folderId, folder: folderId,
mails: [],
}) })
await this.serviceExecutor.delete(MailService, deleteMailData) await this.serviceExecutor.delete(MailService, deleteMailData)
} }

View file

@ -180,6 +180,7 @@ function attendeesLine(event: CalendarEvent): string {
organizer, organizer,
createCalendarEventAttendee({ createCalendarEventAttendee({
address: organizer, address: organizer,
status: "0",
}), }),
) )
} }

View file

@ -251,12 +251,14 @@ export class DefaultDateProvider implements DateProvider {
} }
export function createRepeatRuleWithValues(frequency: RepeatPeriod, interval: number, timeZone: string = getTimeZone()): CalendarRepeatRule { export function createRepeatRuleWithValues(frequency: RepeatPeriod, interval: number, timeZone: string = getTimeZone()): CalendarRepeatRule {
const rule = createCalendarRepeatRule({ return createCalendarRepeatRule({
timeZone: timeZone, timeZone: timeZone,
frequency: frequency, frequency: frequency,
interval: String(interval), interval: String(interval),
endValue: null,
endType: "0",
excludedDates: [],
}) })
return rule
} }
export function colorForBg(color: string): string { export function colorForBg(color: string): string {

View file

@ -65,6 +65,8 @@ export class CalendarEventAlarmModel {
return createAlarmInfo({ return createAlarmInfo({
alarmIdentifier: generateEventElementId(this.dateProvider.now()), alarmIdentifier: generateEventElementId(this.dateProvider.now()),
trigger: serializeAlarmInterval(alarmInterval), trigger: serializeAlarmInterval(alarmInterval),
// @ts-ignore
calendarRef: null, // FIXME
}) })
} }

View file

@ -95,7 +95,7 @@ import { CalendarEventWhenModel } from "./CalendarEventWhenModel.js"
import { CalendarEventWhoModel } from "./CalendarEventWhoModel.js" import { CalendarEventWhoModel } from "./CalendarEventWhoModel.js"
import { CalendarEventAlarmModel } from "./CalendarEventAlarmModel.js" import { CalendarEventAlarmModel } from "./CalendarEventAlarmModel.js"
import { SanitizedTextViewModel } from "../../../misc/SanitizedTextViewModel.js" import { SanitizedTextViewModel } from "../../../misc/SanitizedTextViewModel.js"
import { getStrippedClone, Stripped } from "../../../api/common/utils/EntityUtils.js" import { getStrippedClone, Stripped, StrippedEntity } from "../../../api/common/utils/EntityUtils.js"
import { UserController } from "../../../api/main/UserController.js" import { UserController } from "../../../api/main/UserController.js"
import { CalendarNotificationModel, CalendarNotificationSendModels } from "./CalendarNotificationModel.js" import { CalendarNotificationModel, CalendarNotificationSendModels } from "./CalendarNotificationModel.js"
import { CalendarEventApplyStrategies, CalendarEventModelStrategy } from "./CalendarEventModelStrategy.js" import { CalendarEventApplyStrategies, CalendarEventModelStrategy } from "./CalendarEventModelStrategy.js"
@ -186,7 +186,6 @@ export async function makeCalendarEventModel(
initialValues = index.progenitor initialValues = index.progenitor
} }
} }
const cleanInitialValues = cleanupInitialValuesForEditing(initialValues)
const user = logins.getUserController().user const user = logins.getUserController().user
const [alarms, calendars] = await Promise.all([ const [alarms, calendars] = await Promise.all([
@ -231,18 +230,27 @@ export async function makeCalendarEventModel(
uid == null ? [] : (await calendarModel.getEventsByUid(uid))?.alteredInstances.map((i) => i.recurrenceId) ?? [] uid == null ? [] : (await calendarModel.getEventsByUid(uid))?.alteredInstances.map((i) => i.recurrenceId) ?? []
const notificationModel = new CalendarNotificationModel(notificationSender, logins) const notificationModel = new CalendarNotificationModel(notificationSender, logins)
const applyStrategies = new CalendarEventApplyStrategies(calendarModel, logins, notificationModel, recurrenceIds, showProgress, zone) const applyStrategies = new CalendarEventApplyStrategies(calendarModel, logins, notificationModel, recurrenceIds, showProgress, zone)
const initialOrDefaultValues = Object.assign(makeEmptyCalendarEvent(), initialValues)
const cleanInitialValues = cleanupInitialValuesForEditing(initialOrDefaultValues)
const progenitor = () => calendarModel.resolveCalendarEventProgenitor(cleanInitialValues) const progenitor = () => calendarModel.resolveCalendarEventProgenitor(cleanInitialValues)
const strategy = await selectStrategy(makeEditModels, applyStrategies, operation, progenitor, createCalendarEvent(initialValues), cleanInitialValues) const strategy = await selectStrategy(
makeEditModels,
applyStrategies,
operation,
progenitor,
createCalendarEvent(initialOrDefaultValues),
cleanInitialValues,
)
return strategy && new CalendarEventModel(strategy, eventType, operation, logins.getUserController(), notificationSender, entityClient, calendars) return strategy && new CalendarEventModel(strategy, eventType, operation, logins.getUserController(), notificationSender, entityClient, calendars)
} }
async function selectStrategy( async function selectStrategy(
makeEditModels: (i: CalendarEvent) => CalendarEventEditModels, makeEditModels: (i: StrippedEntity<CalendarEvent>) => CalendarEventEditModels,
applyStrategies: CalendarEventApplyStrategies, applyStrategies: CalendarEventApplyStrategies,
operation: CalendarOperation, operation: CalendarOperation,
resolveProgenitor: () => Promise<CalendarEvent | null>, resolveProgenitor: () => Promise<CalendarEvent | null>,
existingInstanceIdentity: CalendarEvent, existingInstanceIdentity: CalendarEvent,
cleanInitialValues: CalendarEvent, cleanInitialValues: StrippedEntity<CalendarEvent>,
): Promise<CalendarEventModelStrategy | null> { ): Promise<CalendarEventModelStrategy | null> {
let editModels: CalendarEventEditModels let editModels: CalendarEventEditModels
let apply: () => Promise<void> let apply: () => Promise<void>
@ -540,11 +548,27 @@ export function assembleEditResultAndAssignFromExisting(existingEvent: CalendarE
* @param identity sequence (default "0") and recurrenceId (default null) are optional, but the uid must be specified. * @param identity sequence (default "0") and recurrenceId (default null) are optional, but the uid must be specified.
*/ */
export function assignEventIdentity(values: CalendarEventValues, identity: Require<"uid", Partial<CalendarEventIdentity>>): CalendarEvent { export function assignEventIdentity(values: CalendarEventValues, identity: Require<"uid", Partial<CalendarEventIdentity>>): CalendarEvent {
return createCalendarEvent({ return Object.assign(
...values, createCalendarEvent({
sequence: "0", sequence: "0",
...identity, organizer: null,
}) attendees: [],
description: "",
repeatRule: null,
location: "",
summary: "",
endTime: new Date(),
uid: null,
startTime: new Date(),
recurrenceId: null,
invitedConfidentially: null,
// @ts-ignore
alarmInfos: null, // FIXME
hashedUid: null,
}),
values,
identity,
)
} }
async function resolveAlarmsForEvent(alarms: CalendarEvent["alarmInfos"], calendarModel: CalendarModel, user: User): Promise<Array<AlarmInterval>> { async function resolveAlarmsForEvent(alarms: CalendarEvent["alarmInfos"], calendarModel: CalendarModel, user: User): Promise<Array<AlarmInterval>> {
@ -552,7 +576,27 @@ async function resolveAlarmsForEvent(alarms: CalendarEvent["alarmInfos"], calend
return alarmInfos.map(({ alarmInfo }) => parseAlarmInterval(alarmInfo.trigger)) return alarmInfos.map(({ alarmInfo }) => parseAlarmInterval(alarmInfo.trigger))
} }
function cleanupInitialValuesForEditing(initialValues: Partial<CalendarEvent>): CalendarEvent { function makeEmptyCalendarEvent(): StrippedEntity<CalendarEvent> {
return {
// @ts-ignore
alarmInfos: null, // FIXME
invitedConfidentially: null,
hashedUid: null,
uid: null,
recurrenceId: null,
endTime: new Date(),
summary: "",
startTime: new Date(),
location: "",
repeatRule: null,
description: "",
attendees: [],
organizer: null,
sequence: "",
}
}
function cleanupInitialValuesForEditing(initialValues: StrippedEntity<CalendarEvent>): CalendarEvent {
// the event we got passed may already have some technical fields assigned, so we remove them. // the event we got passed may already have some technical fields assigned, so we remove them.
const stripped = getStrippedClone<CalendarEvent>(initialValues) const stripped = getStrippedClone<CalendarEvent>(initialValues)
const result = createCalendarEvent(stripped) const result = createCalendarEvent(stripped)

View file

@ -266,6 +266,7 @@ export class CalendarEventWhenModel {
endValue: "1", endValue: "1",
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
excludedDates: [], excludedDates: [],
timeZone: "",
}) })
this.repeatRule.frequency = repeatPeriod this.repeatRule.frequency = repeatPeriod
} }
@ -468,7 +469,20 @@ export class CalendarEventWhenModel {
get result(): CalendarEventWhenModelResult { get result(): CalendarEventWhenModelResult {
// we got a stripped repeat rule, so we re-create a fresh one with all fields but overwrite it with our values. // we got a stripped repeat rule, so we re-create a fresh one with all fields but overwrite it with our values.
const repeatRule: RepeatRule | null = this.repeatRule ? { ...createRepeatRule({}), ...this.repeatRule, timeZone: this.zone } : null const repeatRule: RepeatRule | null = this.repeatRule
? {
...createRepeatRule({
timeZone: "",
excludedDates: [],
endType: "0",
endValue: null,
interval: "0",
frequency: "0",
}),
...this.repeatRule,
timeZone: this.zone,
}
: null
this.deleteExcludedDatesIfNecessary(repeatRule) this.deleteExcludedDatesIfNecessary(repeatRule)
const { startTime, endTime } = this.getTimes() const { startTime, endTime } = this.getTimes()
return { startTime, endTime, repeatRule } return { startTime, endTime, repeatRule }

View file

@ -56,6 +56,10 @@ export function makeInvitationCalendarFile(event: CalendarEvent, method: Calenda
name: `${method.toLowerCase()}-${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}.ics`, name: `${method.toLowerCase()}-${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}.ics`,
mimeType: CALENDAR_MIME_TYPE, mimeType: CALENDAR_MIME_TYPE,
size: String(data.byteLength), size: String(data.byteLength),
cid: null,
blobs: [],
parent: null,
subFiles: null,
}) })
return convertToDataFile(tmpFile, data) return convertToDataFile(tmpFile, data)
} }

View file

@ -219,6 +219,10 @@ function exportCalendarEvents(
name: calendarName === "" ? "export.ics" : calendarName + "-export.ics", name: calendarName === "" ? "export.ics" : calendarName + "-export.ics",
mimeType: CALENDAR_MIME_TYPE, mimeType: CALENDAR_MIME_TYPE,
size: String(data.byteLength), size: String(data.byteLength),
subFiles: null,
parent: null,
cid: null,
blobs: [],
}) })
return locator.fileController.saveDataFile(convertToDataFile(tmpFile, data)) return locator.fileController.saveDataFile(convertToDataFile(tmpFile, data))
} }

View file

@ -271,6 +271,9 @@ function parseAlarm(alarmObject: ICalObject, event: CalendarEvent): AlarmInfo |
return alarmInterval != null return alarmInterval != null
? createAlarmInfo({ ? createAlarmInfo({
trigger: serializeAlarmInterval(alarmInterval), trigger: serializeAlarmInterval(alarmInterval),
alarmIdentifier: "",
// @ts-ignore
calendarRef: null, // FIXME
}) })
: null : null
} }
@ -350,6 +353,8 @@ export function parseRrule(rruleProp: Property, tzId: string | null): RepeatRule
endType: endType, endType: endType,
interval: String(interval), interval: String(interval),
frequency: frequency, frequency: frequency,
excludedDates: [],
timeZone: "",
}) })
if (typeof tzId === "string") { if (typeof tzId === "string") {
@ -628,6 +633,9 @@ export function parseCalendarEvents(icalObject: ICalObject, zone: string): Parse
sequence, sequence,
attendees, attendees,
organizer, organizer,
hashedUid: null,
invitedConfidentially: null,
alarmInfos: [],
}) as Require<"uid", CalendarEvent> }) as Require<"uid", CalendarEvent>
const alarms: AlarmInfo[] = [] const alarms: AlarmInfo[] = []

View file

@ -193,6 +193,7 @@ export class CalendarModel {
const newGroupSettings = createGroupSettings({ const newGroupSettings = createGroupSettings({
group: group._id, group: group._id,
color: color, color: color,
name: null,
}) })
userSettingsGroupRoot.groupSettings.push(newGroupSettings) userSettingsGroupRoot.groupSettings.push(newGroupSettings)
await this.entityClient.update(userSettingsGroupRoot) await this.entityClient.update(userSettingsGroupRoot)

View file

@ -305,6 +305,7 @@ function prepareAttendees(attendees: Array<CalendarEventAttendee>, organizer: En
createCalendarEventAttendee({ createCalendarEventAttendee({
address: createEncryptedMailAddress({ address: createEncryptedMailAddress({
address: organizer.address, address: organizer.address,
name: "",
}), }),
status: CalendarAttendeeStatus.ADDED, // We don't know whether the organizer will be attending or not in this case status: CalendarAttendeeStatus.ADDED, // We don't know whether the organizer will be attending or not in this case
}), }),

View file

@ -76,7 +76,27 @@ export class ContactEditor {
listId?: Id, listId?: Id,
private readonly newContactIdReceiver: ((contactId: Id) => unknown) | null = null, private readonly newContactIdReceiver: ((contactId: Id) => unknown) | null = null,
) { ) {
this.contact = contact ? clone(contact) : createContact({}) this.contact = contact
? clone(contact)
: createContact({
mailAddresses: [],
title: null,
socialIds: [],
role: "",
presharedPassword: null,
photo: null,
phoneNumbers: [],
oldBirthdayDate: null,
nickname: null,
lastName: "",
firstName: "",
company: "",
comment: "",
birthdayIso: null,
addresses: [],
autoTransmitPassword: "",
oldBirthdayAggregate: null,
})
this.isNewContact = contact?._id == null this.isNewContact = contact?._id == null
if (this.isNewContact && listId == null) { if (this.isNewContact && listId == null) {

View file

@ -1,8 +1,8 @@
import { convertToDataFile } from "../api/common/DataFile" import { convertToDataFile } from "../api/common/DataFile"
import type { Contact, ContactAddress, ContactMailAddress, ContactPhoneNumber, ContactSocialId } from "../api/entities/tutanota/TypeRefs.js"
import { createFile } from "../api/entities/tutanota/TypeRefs.js" import { createFile } from "../api/entities/tutanota/TypeRefs.js"
import { stringToUtf8Uint8Array } from "@tutao/tutanota-utils" import { stringToUtf8Uint8Array } from "@tutao/tutanota-utils"
import { ContactAddressType, ContactPhoneNumberType } from "../api/common/TutanotaConstants" import { ContactAddressType, ContactPhoneNumberType } from "../api/common/TutanotaConstants"
import type { Contact, ContactSocialId, ContactPhoneNumber, ContactAddress, ContactMailAddress } from "../api/entities/tutanota/TypeRefs.js"
import { assertMainOrNode } from "../api/common/Env" import { assertMainOrNode } from "../api/common/Env"
import { locator } from "../api/main/MainLocator" import { locator } from "../api/main/MainLocator"
import { getSocialUrl } from "./model/ContactUtils.js" import { getSocialUrl } from "./model/ContactUtils.js"
@ -16,10 +16,13 @@ export function exportContacts(contacts: Contact[]): Promise<void> {
name: "vCard3.0.vcf", name: "vCard3.0.vcf",
mimeType: "vCard/rfc2426", mimeType: "vCard/rfc2426",
size: String(data.byteLength), size: String(data.byteLength),
blobs: [],
cid: null,
parent: null,
subFiles: null,
}) })
return locator.fileController.saveDataFile(convertToDataFile(tmpFile, data)) return locator.fileController.saveDataFile(convertToDataFile(tmpFile, data))
} }
/** /**
* Converts an array of contacts to a vCard 3.0 compatible string. * Converts an array of contacts to a vCard 3.0 compatible string.
* *

View file

@ -165,6 +165,7 @@ export function vCardListToContacts(vCardList: string[], ownerGroupId: Id): Cont
bDayDetails = createBirthday({ bDayDetails = createBirthday({
month: tagValue.substring(2, 4), month: tagValue.substring(2, 4),
day: tagValue.substring(4, 6), day: tagValue.substring(4, 6),
year: null,
}) })
} else if (tagValue.match(/\d{4}-\d{2}-\d{2}/g)) { } else if (tagValue.match(/\d{4}-\d{2}-\d{2}/g)) {
let bDay = tagValue.substring(0, indexOfT !== -1 ? indexOfT : tagValue.length).split("-") let bDay = tagValue.substring(0, indexOfT !== -1 ? indexOfT : tagValue.length).split("-")
@ -310,6 +311,10 @@ export function vCardListToContacts(vCardList: string[], ownerGroupId: Id): Cont
mailAddresses, mailAddresses,
phoneNumbers, phoneNumbers,
socialIds, socialIds,
presharedPassword: null,
photo: null,
oldBirthdayDate: null,
oldBirthdayAggregate: null,
}) })
} }

View file

@ -63,6 +63,22 @@ export class ContactListEntryViewer implements Component<ContactListEntryViewerA
address: attrs.entry.emailAddress, address: attrs.entry.emailAddress,
}), }),
], ],
oldBirthdayAggregate: null,
autoTransmitPassword: "",
addresses: [],
birthdayIso: null,
comment: "",
company: "",
firstName: "",
lastName: "",
nickname: null,
oldBirthdayDate: null,
phoneNumbers: [],
photo: null,
role: "",
presharedPassword: null,
socialIds: [],
title: null,
}) })
attrs.contactCreate(newContact) attrs.contactCreate(newContact)
}, },

View file

@ -5,7 +5,7 @@ import { AppHeaderAttrs, Header } from "../../gui/Header.js"
import { Button, ButtonColor, ButtonType } from "../../gui/base/Button.js" import { Button, ButtonColor, ButtonType } from "../../gui/base/Button.js"
import { ContactEditor } from "../ContactEditor" import { ContactEditor } from "../ContactEditor"
import type { Contact } from "../../api/entities/tutanota/TypeRefs.js" import type { Contact } from "../../api/entities/tutanota/TypeRefs.js"
import { ContactTypeRef, createGroupSettings } from "../../api/entities/tutanota/TypeRefs.js" import { ContactTypeRef } from "../../api/entities/tutanota/TypeRefs.js"
import { ContactListView } from "./ContactListView" import { ContactListView } from "./ContactListView"
import { lang } from "../../misc/LanguageViewModel" import { lang } from "../../misc/LanguageViewModel"
import { assertNotNull, clear, getFirstOrThrow, noOp, ofClass } from "@tutao/tutanota-utils" import { assertNotNull, clear, getFirstOrThrow, noOp, ofClass } from "@tutao/tutanota-utils"
@ -657,11 +657,6 @@ export class ContactView extends BaseTopLevelView implements TopLevelView<Contac
if (existingGroupSettings) { if (existingGroupSettings) {
existingGroupSettings.name = newName existingGroupSettings.name = newName
} else {
const newGroupSettings = createGroupSettings({
group: contactListInfo.group._id,
name: newName,
})
} }
locator.entityClient.update(userSettingsGroupRoot) locator.entityClient.update(userSettingsGroupRoot)

View file

@ -937,6 +937,9 @@ export class SendMailModel {
_id: [listId, stringToCustomId(this.senderAddress)], _id: [listId, stringToCustomId(this.senderAddress)],
_ownerGroup: this.user().user.userGroup.group, _ownerGroup: this.user().user.userGroup.group,
text: `Subject: ${this.getSubject()}<br>${body}`, text: `Subject: ${this.getSubject()}<br>${body}`,
date: null,
range: null,
customer: null,
}) })
return this.entity.setup(listId, m).catch(ofClass(NotAuthorizedError, (e) => console.log("not authorized for approval message"))) return this.entity.setup(listId, m).catch(ofClass(NotAuthorizedError, (e) => console.log("not authorized for approval message")))
} }

View file

@ -518,7 +518,9 @@ export class MailModel {
.setup( .setup(
null, null,
createMailboxProperties({ createMailboxProperties({
_ownerGroup: mailboxGroupRoot._ownerGroup, _ownerGroup: mailboxGroupRoot._ownerGroup ?? "",
reportMovedMails: "0",
mailAddressProperties: [],
}), }),
) )
.catch( .catch(

View file

@ -1,5 +1,10 @@
import type { Contact, EncryptedMailAddress, InboxRule, Mail, MailFolder, TutanotaProperties } from "../../api/entities/tutanota/TypeRefs.js" import type { Contact, EncryptedMailAddress, InboxRule, Mail, MailFolder, TutanotaProperties } from "../../api/entities/tutanota/TypeRefs.js"
import { import {
Birthday,
ContactAddress,
ContactMailAddress,
ContactPhoneNumber,
ContactSocialId,
createContact, createContact,
createContactMailAddress, createContactMailAddress,
createEncryptedMailAddress, createEncryptedMailAddress,
@ -72,6 +77,20 @@ export function createNewContact(user: User, mailAddress: string, name: string):
customTypeName: "", customTypeName: "",
}), }),
], ],
autoTransmitPassword: "",
birthdayIso: null,
comment: "",
company: "",
nickname: null,
oldBirthdayDate: null,
presharedPassword: null,
role: "",
title: null,
addresses: [],
oldBirthdayAggregate: null,
phoneNumbers: [],
photo: null,
socialIds: [],
}) })
return contact return contact
} }

View file

@ -6,7 +6,7 @@ import { FeatureType, InboxRuleType, Keys, MailFolderType, SpamRuleFieldType, Sp
import type { Mail } from "../../api/entities/tutanota/TypeRefs.js" import type { Mail } from "../../api/entities/tutanota/TypeRefs.js"
import { lang } from "../../misc/LanguageViewModel" import { lang } from "../../misc/LanguageViewModel"
import { assertMainOrNode } from "../../api/common/Env" import { assertMainOrNode } from "../../api/common/Env"
import { assertNonNull, assertNotNull, defer, DeferredObject, noOp, ofClass } from "@tutao/tutanota-utils" import { assertNonNull, assertNotNull, defer, DeferredObject, noOp, ofClass, stringToUtf8Uint8Array, uint8ArrayToBase64 } from "@tutao/tutanota-utils"
import { createNewContact, getExistingRuleForType, isTutanotaTeamMail } from "../model/MailUtils" import { createNewContact, getExistingRuleForType, isTutanotaTeamMail } from "../model/MailUtils"
import { IconMessageBox } from "../../gui/base/ColumnEmptyMessageBox" import { IconMessageBox } from "../../gui/base/ColumnEmptyMessageBox"
import type { Shortcut } from "../../misc/KeyManager" import type { Shortcut } from "../../misc/KeyManager"
@ -671,12 +671,14 @@ export class MailViewer implements Component<MailViewerAttrs> {
break break
} }
import("../../settings/AddSpamRuleDialog").then(({ showAddSpamRuleDialog }) => { Promise.all([import("../../settings/AddSpamRuleDialog"), import("@tutao/tutanota-crypto")]).then(([{ showAddSpamRuleDialog }, { sha256Hash }]) => {
const value = address.trim().toLowerCase()
showAddSpamRuleDialog( showAddSpamRuleDialog(
createEmailSenderListElement({ createEmailSenderListElement({
value: address.trim().toLowerCase(), value,
type: spamRuleType, type: spamRuleType,
field: spamRuleField, field: spamRuleField,
hashedValue: uint8ArrayToBase64(sha256Hash(stringToUtf8Uint8Array(value))),
}), }),
) )
}) })

View file

@ -936,6 +936,7 @@ export class MailViewerViewModel {
const recipient = createMailAddress({ const recipient = createMailAddress({
address: neverNull(userGroupInfo.mailAddress), address: neverNull(userGroupInfo.mailAddress),
name: userGroupInfo.name, name: userGroupInfo.name,
contact: null,
}) })
let newReplyTos let newReplyTos

View file

@ -150,6 +150,8 @@ export class SecondFactorAuthDialog {
type: SecondFactorType.totp, type: SecondFactorType.totp,
session: this.authData.sessionId, session: this.authData.sessionId,
otpCode: this.otpState.code.replace(/ /g, ""), otpCode: this.otpState.code.replace(/ /g, ""),
u2f: null,
webauthn: null,
}) })
try { try {
@ -190,6 +192,8 @@ export class SecondFactorAuthDialog {
type: SecondFactorType.webauthn, type: SecondFactorType.webauthn,
session: sessionId, session: sessionId,
webauthn: responseData, webauthn: responseData,
u2f: null,
otpCode: null,
}) })
await this.loginFacade.authenticateWithSecondFactor(authData, apiBaseUrl) await this.loginFacade.authenticateWithSecondFactor(authData, apiBaseUrl)
} catch (e) { } catch (e) {

View file

@ -137,6 +137,9 @@ export class SecondFactorHandler {
createSecondFactorAuthData({ createSecondFactorAuthData({
session: session._id, session: session._id,
type: null, // Marker for confirming another session type: null, // Marker for confirming another session
otpCode: null,
u2f: null,
webauthn: null,
}), }),
) )

View file

@ -115,6 +115,9 @@ export class NativePushServiceApp {
pushServiceType: pushServiceType, pushServiceType: pushServiceType,
identifier, identifier,
language: lang.code, language: lang.code,
disabled: false,
lastUsageTime: new Date(),
lastNotificationDate: null,
}) })
const id = await this.entityClient.setup(list, pushIdentifier) const id = await this.entityClient.setup(list, pushIdentifier)
return this.entityClient.load(PushIdentifierTypeRef, [list, id]) return this.entityClient.load(PushIdentifierTypeRef, [list, id])

View file

@ -111,6 +111,8 @@ export function createInboxRuleTemplate(ruleType: string | null, value: string |
return createInboxRule({ return createInboxRule({
type: ruleType || InboxRuleType.FROM_EQUALS, type: ruleType || InboxRuleType.FROM_EQUALS,
value: getCleanedValue(neverNull(ruleType), value || ""), value: getCleanedValue(neverNull(ruleType), value || ""),
// @ts-ignore
targetFolder: null, // FIXME
}) })
} }

View file

@ -54,7 +54,12 @@ export class EditOutOfOfficeNotificationDialogModel {
if (!outOfOfficeNotification) { if (!outOfOfficeNotification) {
this.startDate(getStartOfDay(new Date())) this.startDate(getStartOfDay(new Date()))
this.outOfOfficeNotification = createOutOfOfficeNotification({}) this.outOfOfficeNotification = createOutOfOfficeNotification({
notifications: [],
enabled: false,
endDate: null,
startDate: null,
})
} else { } else {
this.outOfOfficeNotification = outOfOfficeNotification this.outOfOfficeNotification = outOfOfficeNotification
this.enabled(outOfOfficeNotification.enabled) this.enabled(outOfOfficeNotification.enabled)

View file

@ -403,6 +403,7 @@ export class GlobalSettingsViewer implements UpdatableSettingsViewer {
value: domainPart ? domainPart : "", value: domainPart ? domainPart : "",
type: SpamRuleType.WHITELIST, type: SpamRuleType.WHITELIST,
field: SpamRuleFieldType.FROM, field: SpamRuleFieldType.FROM,
hashedValue: "",
}), }),
) )
}, },

View file

@ -210,6 +210,9 @@ export class IdentifierListViewer {
identifier: assertNotNull(getCleanedMailAddress(mailAddress)), identifier: assertNotNull(getCleanedMailAddress(mailAddress)),
language: lang.code, language: lang.code,
pushServiceType: PushServiceType.EMAIL, pushServiceType: PushServiceType.EMAIL,
lastUsageTime: new Date(),
lastNotificationDate: null,
disabled: false,
}) })
let p = locator.entityClient.setup(assertNotNull(user.pushIdentifierList).list, pushIdentifier) let p = locator.entityClient.setup(assertNotNull(user.pushIdentifierList).list, pushIdentifier)

View file

@ -26,7 +26,7 @@ export class KnowledgeBaseEditorModel {
this.keywords = stream(entry ? keywordsToString(entry.keywords) : "") this.keywords = stream(entry ? keywordsToString(entry.keywords) : "")
this._entityClient = entityClient this._entityClient = entityClient
this._templateGroupRoot = templateGroupInstances this._templateGroupRoot = templateGroupInstances
this.entry = entry ? clone(entry) : createKnowledgeBaseEntry({}) this.entry = entry ? clone(entry) : createKnowledgeBaseEntry({ description: "", title: "", keywords: [] })
this._descriptionProvider = null this._descriptionProvider = null
this.availableTemplates = new LazyLoaded(() => { this.availableTemplates = new LazyLoaded(() => {
return this._entityClient.loadAll(EmailTemplateTypeRef, this._templateGroupRoot.templates) return this._entityClient.loadAll(EmailTemplateTypeRef, this._templateGroupRoot.templates)

View file

@ -23,7 +23,7 @@ export class TemplateEditorModel {
_contentProvider: (() => string) | null _contentProvider: (() => string) | null
constructor(template: EmailTemplate | null, templateGroupRoot: TemplateGroupRoot, entityClient: EntityClient) { constructor(template: EmailTemplate | null, templateGroupRoot: TemplateGroupRoot, entityClient: EntityClient) {
this.template = template ? clone(template) : createEmailTemplate({}) this.template = template ? clone(template) : createEmailTemplate({ tag: "", title: "", contents: [] })
this.title = stream("") this.title = stream("")
this.tag = stream("") this.tag = stream("")
const contents = this.template.contents const contents = this.template.contents

View file

@ -29,7 +29,9 @@ export function showAddDomainWizard(domain: string, customerInfo: CustomerInfo,
const domainData: AddDomainData = { const domainData: AddDomainData = {
domain: stream(domain), domain: stream(domain),
customerInfo: customerInfo, customerInfo: customerInfo,
expectedVerificationRecord: createDnsRecord({}), // will be filled oncreate by the page
// not actually spf, but the type TXT only matters here
expectedVerificationRecord: createDnsRecord({ subdomain: null, type: DnsRecordType.DNS_RECORD_TYPE_TXT_SPF, value: "" }),
editAliasFormAttrs: { editAliasFormAttrs: {
model: mailAddressTableModel, model: mailAddressTableModel,
expanded: mailAddressTableExpanded, expanded: mailAddressTableExpanded,
@ -37,10 +39,6 @@ export function showAddDomainWizard(domain: string, customerInfo: CustomerInfo,
}, },
domainStatus: new DomainDnsStatus(domain), domainStatus: new DomainDnsStatus(domain),
} }
domainData.expectedVerificationRecord.type = DnsRecordType.DNS_RECORD_TYPE_TXT_SPF // not actually spf, but the type TXT only matters here
domainData.expectedVerificationRecord.subdomain = null
domainData.expectedVerificationRecord.value = "" // will be filled oncreate by the page
const wizardPages = [ const wizardPages = [
wizardPageWrapper(EnterDomainPage, new EnterDomainPageAttrs(domainData)), wizardPageWrapper(EnterDomainPage, new EnterDomainPageAttrs(domainData)),

View file

@ -70,7 +70,7 @@ export class SecondFactorEditModel {
width: 150, width: 150,
content: url, content: url,
padding: 2, padding: 2,
// We don't want <xml> around the content, we actually enforce <svg> namespace and we want it to be parsed as such. // We don't want <xml> around the content, we actually enforce <svg> namespace, and we want it to be parsed as such.
xmlDeclaration: false, xmlDeclaration: false,
}) })
totpQRCodeSvg = htmlSanitizer.sanitizeSVG(qrcodeGenerator.svg()).html totpQRCodeSvg = htmlSanitizer.sanitizeSVG(qrcodeGenerator.svg()).html
@ -181,17 +181,19 @@ export class SecondFactorEditModel {
} }
this.updateViewCallback() this.updateViewCallback()
const sf = createSecondFactor({
_ownerGroup: this.user._ownerGroup,
name: this.name,
})
if (this.selectedType === SecondFactorType.u2f) { if (this.selectedType === SecondFactorType.u2f) {
throw new ProgrammingError(`invalid factor type: ${this.selectedType}`) throw new ProgrammingError(`invalid factor type: ${this.selectedType}`)
} else {
sf.type = this.selectedType
} }
const sf = createSecondFactor({
_ownerGroup: this.user._ownerGroup!,
name: this.name,
type: this.selectedType,
otpSecret: null,
u2f: null,
})
if (this.selectedType === SecondFactorType.webauthn) { if (this.selectedType === SecondFactorType.webauthn) {
if (this.verificationStatus !== VerificationStatus.Success) { if (this.verificationStatus !== VerificationStatus.Success) {
throw new UserError("unrecognizedU2fDevice_msg") throw new UserError("unrecognizedU2fDevice_msg")

View file

@ -18,10 +18,11 @@ export class OwnMailAddressNameChanger implements MailAddressNameChanger {
const mailboxProperties = await this.mailModel.getMailboxProperties(mailboxDetails.mailboxGroupRoot) const mailboxProperties = await this.mailModel.getMailboxProperties(mailboxDetails.mailboxGroupRoot)
let aliasConfig = mailboxProperties.mailAddressProperties.find((p) => p.mailAddress === address) let aliasConfig = mailboxProperties.mailAddressProperties.find((p) => p.mailAddress === address)
if (aliasConfig == null) { if (aliasConfig == null) {
aliasConfig = createMailAddressProperties({ mailAddress: address }) aliasConfig = createMailAddressProperties({ mailAddress: address, senderName: name })
mailboxProperties.mailAddressProperties.push(aliasConfig) mailboxProperties.mailAddressProperties.push(aliasConfig)
} else {
aliasConfig.senderName = name
} }
aliasConfig.senderName = name
await this.entityClient.update(mailboxProperties) await this.entityClient.update(mailboxProperties)
return this.collectMap(mailboxProperties) return this.collectMap(mailboxProperties)
} }

View file

@ -1,8 +1,7 @@
import m, { Children, Component } from "mithril" import m, { Children, Component } from "mithril"
import { px, size } from "../../gui/size" import { px, size } from "../../gui/size"
import { Button, ButtonType } from "../../gui/base/Button.js" import { Button, ButtonType } from "../../gui/base/Button.js"
import { createMail } from "../../api/entities/tutanota/TypeRefs.js" import { createMail, createMailAddress } from "../../api/entities/tutanota/TypeRefs.js"
import { createMailAddress } from "../../api/entities/tutanota/TypeRefs.js"
import { MailRow } from "../../mail/view/MailRow" import { MailRow } from "../../mail/view/MailRow"
import { noOp } from "@tutao/tutanota-utils" import { noOp } from "@tutao/tutanota-utils"
import { IconButton } from "../../gui/base/IconButton.js" import { IconButton } from "../../gui/base/IconButton.js"
@ -78,6 +77,7 @@ export class CustomColorEditorPreview implements Component {
sender: createMailAddress({ sender: createMailAddress({
address: "m.mustermann@example.com", address: "m.mustermann@example.com",
name: "Max Mustermann", name: "Max Mustermann",
contact: null,
}), }),
receivedDate: new Date(), receivedDate: new Date(),
subject: "Mail 1", subject: "Mail 1",
@ -86,11 +86,33 @@ export class CustomColorEditorPreview implements Component {
confidential: true, confidential: true,
attachments: [], attachments: [],
state: "2", state: "2",
mailDetails: null,
body: null,
authStatus: null,
method: "0",
bccRecipients: [],
bucketKey: null,
ccRecipients: [],
headers: null,
// @ts-ignore
conversationEntry: null, // FIXME
differentEnvelopeSender: null,
firstRecipient: null,
listUnsubscribe: false,
mailDetailsDraft: null,
movedTime: null,
phishingStatus: "0",
recipientCount: "0",
replyTos: [],
restrictions: null,
sentDate: null,
toRecipients: [],
}) })
const mail2 = createMail({ const mail2 = createMail({
sender: createMailAddress({ sender: createMailAddress({
address: "m.mustermann@example.com", address: "m.mustermann@example.com",
name: "Max Mustermann", name: "Max Mustermann",
contact: null,
}), }),
receivedDate: new Date(), receivedDate: new Date(),
subject: "Mail 2", subject: "Mail 2",
@ -99,6 +121,14 @@ export class CustomColorEditorPreview implements Component {
confidential: false, confidential: false,
attachments: [], attachments: [],
state: "2", state: "2",
authStatus: null,
sentDate: null,
phishingStatus: "0",
mailDetailsDraft: null,
// @ts-ignore
conversationEntry: null, // FIXME
headers: null,
mailDetails: null,
}) })
return m( return m(
".rel", ".rel",

View file

@ -355,7 +355,7 @@ export class PaymentViewer implements UpdatableSettingsViewer {
return showProgressDialog( return showProgressDialog(
"pleaseWait_msg", "pleaseWait_msg",
locator.serviceExecutor locator.serviceExecutor
.put(DebitService, createDebitServicePutData({})) .put(DebitService, createDebitServicePutData({ invoice: null }))
.catch(ofClass(LockedError, () => "operationStillActive_msg" as TranslationKey)) .catch(ofClass(LockedError, () => "operationStillActive_msg" as TranslationKey))
.catch( .catch(
ofClass(PreconditionFailedError, (error) => { ofClass(PreconditionFailedError, (error) => {

View file

@ -258,6 +258,8 @@ async function cancelSubscription(dialog: Dialog, currentPlanInfo: CurrentPlanIn
date: Const.CURRENT_DATE, date: Const.CURRENT_DATE,
customer: customer._id, customer: customer._id,
specialPriceUserSingle: null, specialPriceUserSingle: null,
referralCode: null,
plan: PlanType.Free,
}) })
try { try {
await showProgressDialog( await showProgressDialog(

View file

@ -37,9 +37,11 @@ export class UpgradeConfirmSubscriptionPage implements WizardPageN<UpgradeSubscr
private upgrade(data: UpgradeSubscriptionData) { private upgrade(data: UpgradeSubscriptionData) {
const serviceData = createSwitchAccountTypePostIn({ const serviceData = createSwitchAccountTypePostIn({
accountType: AccountType.PAID, accountType: AccountType.PAID,
customer: null,
plan: data.type, plan: data.type,
date: Const.CURRENT_DATE, date: Const.CURRENT_DATE,
referralCode: data.referralCode, referralCode: data.referralCode,
specialPriceUserSingle: null,
}) })
showProgressDialog( showProgressDialog(
"pleaseWait_msg", "pleaseWait_msg",

View file

@ -129,7 +129,7 @@ export function createTestEntity<T extends Entity>(typeRef: TypeRef<T>, values?:
const typeModel = resolveTypeReference(typeRef as TypeRef<any>) const typeModel = resolveTypeReference(typeRef as TypeRef<any>)
const entity = create(typeModel, typeRef) const entity = create(typeModel, typeRef)
if (values) { if (values) {
return { ...entity, values } return Object.assign(entity, values)
} else { } else {
return entity return entity
} }

View file

@ -1,12 +1,13 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { createBirthday } from "../../../../../src/api/entities/tutanota/TypeRefs.js" import { BirthdayTypeRef, createBirthday } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
import { birthdayToIsoDate, isoDateToBirthday } from "../../../../../src/api/common/utils/BirthdayUtils.js" import { birthdayToIsoDate, isoDateToBirthday } from "../../../../../src/api/common/utils/BirthdayUtils.js"
import { ParsingError } from "../../../../../src/api/common/error/ParsingError.js" import { ParsingError } from "../../../../../src/api/common/error/ParsingError.js"
import { TutanotaError } from "../../../../../src/api/common/error/TutanotaError.js" import { TutanotaError } from "../../../../../src/api/common/error/TutanotaError.js"
import { createTestEntity } from "../../../TestUtils.js"
o.spec("BirthdayUtilsTest", function () { o.spec("BirthdayUtilsTest", function () {
o("birthdayToIsoDate", function () { o("birthdayToIsoDate", function () {
const bday = createBirthday({ const bday = createTestEntity(BirthdayTypeRef, {
day: "12", day: "12",
month: "10", month: "10",
year: null, year: null,
@ -23,28 +24,28 @@ o.spec("BirthdayUtilsTest", function () {
}) })
o("isoDateToBirthday", function () { o("isoDateToBirthday", function () {
o(isoDateToBirthday("--10-12")).deepEquals( o(isoDateToBirthday("--10-12")).deepEquals(
createBirthday({ createTestEntity(BirthdayTypeRef, {
day: "12", day: "12",
month: "10", month: "10",
year: null, year: null,
}), }),
) )
o(isoDateToBirthday("2009-10-12")).deepEquals( o(isoDateToBirthday("2009-10-12")).deepEquals(
createBirthday({ createTestEntity(BirthdayTypeRef, {
day: "12", day: "12",
month: "10", month: "10",
year: "2009", year: "2009",
}), }),
) )
o(isoDateToBirthday("2009-12-31")).deepEquals( o(isoDateToBirthday("2009-12-31")).deepEquals(
createBirthday({ createTestEntity(BirthdayTypeRef, {
day: "31", day: "31",
month: "12", month: "12",
year: "2009", year: "2009",
}), }),
) )
o(isoDateToBirthday("2009-01-01")).deepEquals( o(isoDateToBirthday("2009-01-01")).deepEquals(
createBirthday({ createTestEntity(BirthdayTypeRef, {
day: "01", day: "01",
month: "01", month: "01",
year: "2009", year: "2009",

View file

@ -11,9 +11,15 @@ import {
createWebsocketCounterValue, createWebsocketCounterValue,
createWebsocketEntityData, createWebsocketEntityData,
EntityEventBatchTypeRef, EntityEventBatchTypeRef,
EntityUpdateTypeRef,
GroupMembershipTypeRef,
User, User,
UserTypeRef,
WebsocketCounterData, WebsocketCounterData,
WebsocketCounterDataTypeRef,
WebsocketCounterValueTypeRef,
WebsocketEntityData, WebsocketEntityData,
WebsocketEntityDataTypeRef,
} from "../../../../src/api/entities/sys/TypeRefs.js" } from "../../../../src/api/entities/sys/TypeRefs.js"
import { EntityRestClientMock } from "./rest/EntityRestClientMock.js" import { EntityRestClientMock } from "./rest/EntityRestClientMock.js"
import { EntityClient } from "../../../../src/api/common/EntityClient.js" import { EntityClient } from "../../../../src/api/common/EntityClient.js"
@ -28,6 +34,7 @@ import { SleepDetector } from "../../../../src/api/worker/utils/SleepDetector.js
import { WsConnectionState } from "../../../../src/api/main/WorkerClient.js" import { WsConnectionState } from "../../../../src/api/main/WorkerClient.js"
import { UserFacade } from "../../../../src/api/worker/facades/UserFacade" import { UserFacade } from "../../../../src/api/worker/facades/UserFacade"
import { ExposedProgressTracker } from "../../../../src/api/main/ProgressTracker.js" import { ExposedProgressTracker } from "../../../../src/api/main/ProgressTracker.js"
import { createTestEntity } from "../../TestUtils.js"
o.spec("EventBusClient test", function () { o.spec("EventBusClient test", function () {
let ebc: EventBusClient let ebc: EventBusClient
@ -86,8 +93,8 @@ o.spec("EventBusClient test", function () {
}, },
} as DefaultEntityRestCache) } as DefaultEntityRestCache)
user = createUser({ user = createTestEntity(UserTypeRef, {
userGroup: createGroupMembership({ userGroup: createTestEntity(GroupMembershipTypeRef, {
group: "userGroupId", group: "userGroupId",
}), }),
}) })
@ -111,7 +118,7 @@ o.spec("EventBusClient test", function () {
o.beforeEach(function () { o.beforeEach(function () {
user.memberships = [ user.memberships = [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
groupType: GroupType.Mail, groupType: GroupType.Mail,
group: mailGroupId, group: mailGroupId,
}), }),
@ -121,7 +128,7 @@ o.spec("EventBusClient test", function () {
o("initial connect: when the cache is clean it downloads one batch and initializes cache", async function () { o("initial connect: when the cache is clean it downloads one batch and initializes cache", async function () {
when(cacheMock.getLastEntityEventBatchForGroup(mailGroupId)).thenResolve(null) when(cacheMock.getLastEntityEventBatchForGroup(mailGroupId)).thenResolve(null)
when(cacheMock.timeSinceLastSyncMs()).thenResolve(null) when(cacheMock.timeSinceLastSyncMs()).thenResolve(null)
const batch = createEntityEventBatch({ _id: [mailGroupId, "-----------1"] }) const batch = createTestEntity(EntityEventBatchTypeRef, { _id: [mailGroupId, "-----------1"] })
restClient.addListInstances(batch) restClient.addListInstances(batch)
await ebc.connect(ConnectMode.Initial) await ebc.connect(ConnectMode.Initial)
@ -136,13 +143,13 @@ o.spec("EventBusClient test", function () {
o("initial connect: when the cache is initialized, missed events are loaded", async function () { o("initial connect: when the cache is initialized, missed events are loaded", async function () {
when(cacheMock.getLastEntityEventBatchForGroup(mailGroupId)).thenResolve("------------") when(cacheMock.getLastEntityEventBatchForGroup(mailGroupId)).thenResolve("------------")
when(cacheMock.timeSinceLastSyncMs()).thenResolve(1) when(cacheMock.timeSinceLastSyncMs()).thenResolve(1)
const update = createEntityUpdate({ const update = createTestEntity(EntityUpdateTypeRef, {
type: "Mail", type: "Mail",
application: "tutanota", application: "tutanota",
instanceListId: mailGroupId, instanceListId: mailGroupId,
instanceId: "newBatchId", instanceId: "newBatchId",
}) })
const batch = createEntityEventBatch({ const batch = createTestEntity(EntityEventBatchTypeRef, {
_id: [mailGroupId, "-----------1"], _id: [mailGroupId, "-----------1"],
events: [update], events: [update],
}) })
@ -267,11 +274,11 @@ o.spec("EventBusClient test", function () {
}) })
function createEntityMessage(eventBatchId: number): string { function createEntityMessage(eventBatchId: number): string {
const event: WebsocketEntityData = createWebsocketEntityData({ const event: WebsocketEntityData = createTestEntity(WebsocketEntityDataTypeRef, {
eventBatchId: String(eventBatchId), eventBatchId: String(eventBatchId),
eventBatchOwner: "ownerId", eventBatchOwner: "ownerId",
eventBatch: [ eventBatch: [
createEntityUpdate({ createTestEntity(EntityUpdateTypeRef, {
_id: "eventbatchid", _id: "eventbatchid",
application: "tutanota", application: "tutanota",
type: "Mail", type: "Mail",
@ -287,11 +294,11 @@ o.spec("EventBusClient test", function () {
type CounterMessageParams = { mailGroupId: Id; counterValue: number; listId: Id } type CounterMessageParams = { mailGroupId: Id; counterValue: number; listId: Id }
function createCounterData({ mailGroupId, counterValue, listId }: CounterMessageParams): WebsocketCounterData { function createCounterData({ mailGroupId, counterValue, listId }: CounterMessageParams): WebsocketCounterData {
return createWebsocketCounterData({ return createTestEntity(WebsocketCounterDataTypeRef, {
_format: "0", _format: "0",
mailGroup: mailGroupId, mailGroup: mailGroupId,
counterValues: [ counterValues: [
createWebsocketCounterValue({ createTestEntity(WebsocketCounterValueTypeRef, {
_id: "counterupdateid", _id: "counterupdateid",
count: String(counterValue), count: String(counterValue),
mailListId: listId, mailListId: listId,

View file

@ -14,10 +14,9 @@ import { ProgrammingError } from "../../../../../src/api/common/error/Programmin
import { Cardinality, ValueType } from "../../../../../src/api/common/EntityConstants.js" import { Cardinality, ValueType } from "../../../../../src/api/common/EntityConstants.js"
import { BucketPermissionType, PermissionType } from "../../../../../src/api/common/TutanotaConstants.js" import { BucketPermissionType, PermissionType } from "../../../../../src/api/common/TutanotaConstants.js"
import { import {
BirthdayTypeRef,
ContactAddressTypeRef, ContactAddressTypeRef,
ContactTypeRef, ContactTypeRef,
createBirthday,
createContact,
FileTypeRef, FileTypeRef,
Mail, Mail,
MailAddressTypeRef, MailAddressTypeRef,
@ -29,20 +28,16 @@ import {
BucketKey, BucketKey,
BucketKeyTypeRef, BucketKeyTypeRef,
BucketPermissionTypeRef, BucketPermissionTypeRef,
createBucket, BucketTypeRef,
createBucketKey, GroupMembershipTypeRef,
createBucketPermission,
createGroup,
createGroupMembership,
createInstanceSessionKey,
createKeyPair,
createPermission,
createTypeInfo,
createUser,
GroupTypeRef, GroupTypeRef,
InstanceSessionKeyTypeRef,
KeyPairTypeRef,
PermissionTypeRef, PermissionTypeRef,
TypeInfoTypeRef,
UpdatePermissionKeyData, UpdatePermissionKeyData,
UserIdReturnTypeRef, UserIdReturnTypeRef,
UserTypeRef,
} from "../../../../../src/api/entities/sys/TypeRefs.js" } from "../../../../../src/api/entities/sys/TypeRefs.js"
import { assertThrows, spy } from "@tutao/tutanota-test-utils" import { assertThrows, spy } from "@tutao/tutanota-test-utils"
import { RestClient } from "../../../../../src/api/worker/rest/RestClient.js" import { RestClient } from "../../../../../src/api/worker/rest/RestClient.js"
@ -556,8 +551,8 @@ o.spec("crypto facade", function () {
const gk = aes128RandomKey() const gk = aes128RandomKey()
const sk = aes128RandomKey() const sk = aes128RandomKey()
when(userFacade.getGroupKey("mailGroupId")).thenReturn(gk) when(userFacade.getGroupKey("mailGroupId")).thenReturn(gk)
const user = createUser({ const user = createTestEntity(UserTypeRef, {
userGroup: createGroupMembership({ userGroup: createTestEntity(GroupMembershipTypeRef, {
group: "mailGroupId", group: "mailGroupId",
}), }),
}) })
@ -584,22 +579,22 @@ o.spec("crypto facade", function () {
let bk = aes128RandomKey() let bk = aes128RandomKey()
let privateKey = hexToPrivateKey(rsaPrivateHexKey) let privateKey = hexToPrivateKey(rsaPrivateHexKey)
let publicKey = hexToPublicKey(rsaPublicHexKey) let publicKey = hexToPublicKey(rsaPublicHexKey)
const keyPair = createKeyPair({ const keyPair = createTestEntity(KeyPairTypeRef, {
_id: "keyPairId", _id: "keyPairId",
symEncPrivKey: encryptRsaKey(gk, privateKey), symEncPrivKey: encryptRsaKey(gk, privateKey),
pubKey: hexToUint8Array(rsaPublicHexKey), pubKey: hexToUint8Array(rsaPublicHexKey),
}) })
const userGroup = createGroup({ const userGroup = createTestEntity(GroupTypeRef, {
_id: "userGroupId", _id: "userGroupId",
keys: [keyPair], keys: [keyPair],
}) })
const mail = createMailLiteral(gk, sk, subject, confidential, senderName, recipientName) const mail = createMailLiteral(gk, sk, subject, confidential, senderName, recipientName)
// @ts-ignore // @ts-ignore
mail._ownerEncSessionKey = null mail._ownerEncSessionKey = null
const bucket = createBucket({ const bucket = createTestEntity(BucketTypeRef, {
bucketPermissions: "bucketPermissionListId", bucketPermissions: "bucketPermissionListId",
}) })
const permission = createPermission({ const permission = createTestEntity(PermissionTypeRef, {
_id: ["permissionListId", "permissionId"], _id: ["permissionListId", "permissionId"],
_ownerGroup: userGroup._id, _ownerGroup: userGroup._id,
bucketEncSessionKey: encryptKey(bk, sk), bucketEncSessionKey: encryptKey(bk, sk),
@ -607,18 +602,18 @@ o.spec("crypto facade", function () {
type: PermissionType.Public, type: PermissionType.Public,
}) })
const pubEncBucketKey = await rsaEncrypt(publicKey, bitArrayToUint8Array(bk)) const pubEncBucketKey = await rsaEncrypt(publicKey, bitArrayToUint8Array(bk))
const bucketPermission = createBucketPermission({ const bucketPermission = createTestEntity(BucketPermissionTypeRef, {
_id: ["bucketPermissionListId", "bucketPermissionId"], _id: ["bucketPermissionListId", "bucketPermissionId"],
_ownerGroup: userGroup._id, _ownerGroup: userGroup._id,
type: BucketPermissionType.Public, type: BucketPermissionType.Public,
group: userGroup._id, group: userGroup._id,
pubEncBucketKey, pubEncBucketKey,
}) })
const mem = createGroupMembership({ const mem = createTestEntity(GroupMembershipTypeRef, {
group: userGroup._id, group: userGroup._id,
}) })
const user = createUser({ const user = createTestEntity(UserTypeRef, {
userGroup: mem, userGroup: mem,
}) })
when(userFacade.getLoggedInUser()).thenReturn(user) when(userFacade.getLoggedInUser()).thenReturn(user)
@ -671,7 +666,7 @@ o.spec("crypto facade", function () {
}) })
o("contact migration without existing birthday", async function () { o("contact migration without existing birthday", async function () {
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
birthdayIso: "2019-05-01", birthdayIso: "2019-05-01",
}) })
@ -682,7 +677,7 @@ o.spec("crypto facade", function () {
}) })
o("contact migration without existing birthday and oldBirthdayDate", async function () { o("contact migration without existing birthday and oldBirthdayDate", async function () {
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: ["listid", "id"], _id: ["listid", "id"],
birthdayIso: "2019-05-01", birthdayIso: "2019-05-01",
oldBirthdayDate: new Date(2000, 4, 1), oldBirthdayDate: new Date(2000, 4, 1),
@ -696,10 +691,10 @@ o.spec("crypto facade", function () {
}) })
o("contact migration with existing birthday and oldBirthdayAggregate", async function () { o("contact migration with existing birthday and oldBirthdayAggregate", async function () {
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: ["listid", "id"], _id: ["listid", "id"],
birthdayIso: "2019-05-01", birthdayIso: "2019-05-01",
oldBirthdayAggregate: createBirthday({ oldBirthdayAggregate: createTestEntity(BirthdayTypeRef, {
day: "01", day: "01",
month: "05", month: "05",
year: "2000", year: "2000",
@ -715,10 +710,10 @@ o.spec("crypto facade", function () {
}) })
o("contact migration from oldBirthdayAggregate", async function () { o("contact migration from oldBirthdayAggregate", async function () {
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: ["listid", "id"], _id: ["listid", "id"],
oldBirthdayDate: new Date(1800, 4, 1), oldBirthdayDate: new Date(1800, 4, 1),
oldBirthdayAggregate: createBirthday({ oldBirthdayAggregate: createTestEntity(BirthdayTypeRef, {
day: "01", day: "01",
month: "05", month: "05",
year: "2000", year: "2000",
@ -734,7 +729,7 @@ o.spec("crypto facade", function () {
}) })
o("contact migration from oldBirthdayDate", async function () { o("contact migration from oldBirthdayDate", async function () {
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: ["listid", "id"], _id: ["listid", "id"],
birthdayIso: null, birthdayIso: null,
oldBirthdayDate: new Date(1800, 4, 1), oldBirthdayDate: new Date(1800, 4, 1),
@ -750,11 +745,11 @@ o.spec("crypto facade", function () {
}) })
o("contact migration from oldBirthdayAggregate without year", async function () { o("contact migration from oldBirthdayAggregate without year", async function () {
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: ["listid", "id"], _id: ["listid", "id"],
birthdayIso: null, birthdayIso: null,
oldBirthdayDate: null, oldBirthdayDate: null,
oldBirthdayAggregate: createBirthday({ oldBirthdayAggregate: createTestEntity(BirthdayTypeRef, {
day: "01", day: "01",
month: "05", month: "05",
year: null, year: null,
@ -947,12 +942,12 @@ o.spec("crypto facade", function () {
let bk = aes128RandomKey() let bk = aes128RandomKey()
let privateKey = hexToPrivateKey(rsaPrivateHexKey) let privateKey = hexToPrivateKey(rsaPrivateHexKey)
let publicKey = hexToPublicKey(rsaPublicHexKey) let publicKey = hexToPublicKey(rsaPublicHexKey)
const keyPair = createKeyPair({ const keyPair = createTestEntity(KeyPairTypeRef, {
_id: "keyPairId", _id: "keyPairId",
symEncPrivKey: encryptRsaKey(userGk, privateKey), symEncPrivKey: encryptRsaKey(userGk, privateKey),
pubKey: hexToUint8Array(rsaPublicHexKey), pubKey: hexToUint8Array(rsaPublicHexKey),
}) })
const userGroup = createGroup({ const userGroup = createTestEntity(GroupTypeRef, {
_id: "userGroupId", _id: "userGroupId",
keys: [keyPair], keys: [keyPair],
}) })
@ -966,8 +961,8 @@ o.spec("crypto facade", function () {
const MailTypeModel = await resolveTypeReference(MailTypeRef) const MailTypeModel = await resolveTypeReference(MailTypeRef)
typeModels.tutanota typeModels.tutanota
const mailInstanceSessionKey = createInstanceSessionKey({ const mailInstanceSessionKey = createTestEntity(InstanceSessionKeyTypeRef, {
typeInfo: createTypeInfo({ typeInfo: createTestEntity(TypeInfoTypeRef, {
application: MailTypeModel.app, application: MailTypeModel.app,
typeId: String(MailTypeModel.id), typeId: String(MailTypeModel.id),
}), }),
@ -977,8 +972,8 @@ o.spec("crypto facade", function () {
}) })
const FileTypeModel = await resolveTypeReference(FileTypeRef) const FileTypeModel = await resolveTypeReference(FileTypeRef)
const bucketEncSessionKeys = fileSessionKeys.map((fileSessionKey, index) => { const bucketEncSessionKeys = fileSessionKeys.map((fileSessionKey, index) => {
return createInstanceSessionKey({ return createTestEntity(InstanceSessionKeyTypeRef, {
typeInfo: createTypeInfo({ typeInfo: createTestEntity(TypeInfoTypeRef, {
application: FileTypeModel.app, application: FileTypeModel.app,
typeId: String(FileTypeModel.id), typeId: String(FileTypeModel.id),
}), }),
@ -989,7 +984,7 @@ o.spec("crypto facade", function () {
}) })
bucketEncSessionKeys.push(mailInstanceSessionKey) bucketEncSessionKeys.push(mailInstanceSessionKey)
const bucketKey = createBucketKey({ const bucketKey = createTestEntity(BucketKeyTypeRef, {
pubEncBucketKey: pubEncBucketKey, pubEncBucketKey: pubEncBucketKey,
keyGroup: userGroup._id, keyGroup: userGroup._id,
bucketEncSessionKeys: bucketEncSessionKeys, bucketEncSessionKeys: bucketEncSessionKeys,
@ -999,11 +994,11 @@ o.spec("crypto facade", function () {
const bucketKeyLiteral = await instanceMapper.encryptAndMapToLiteral(BucketKeyModel, bucketKey, null) const bucketKeyLiteral = await instanceMapper.encryptAndMapToLiteral(BucketKeyModel, bucketKey, null)
Object.assign(mailLiteral, { bucketKey: bucketKeyLiteral }) Object.assign(mailLiteral, { bucketKey: bucketKeyLiteral })
const mem = createGroupMembership({ const mem = createTestEntity(GroupMembershipTypeRef, {
group: userGroup._id, group: userGroup._id,
}) })
const user = createUser({ const user = createTestEntity(UserTypeRef, {
userGroup: mem, userGroup: mem,
}) })
@ -1050,7 +1045,7 @@ o.spec("crypto facade", function () {
let bk = aes128RandomKey() let bk = aes128RandomKey()
const ugk = aes128RandomKey() const ugk = aes128RandomKey()
const userGroup = createGroup({ const userGroup = createTestEntity(GroupTypeRef, {
_id: "userGroupId", _id: "userGroupId",
keys: [], keys: [],
}) })
@ -1066,8 +1061,8 @@ o.spec("crypto facade", function () {
const MailTypeModel = await resolveTypeReference(MailTypeRef) const MailTypeModel = await resolveTypeReference(MailTypeRef)
typeModels.tutanota typeModels.tutanota
const mailInstanceSessionKey = createInstanceSessionKey({ const mailInstanceSessionKey = createTestEntity(InstanceSessionKeyTypeRef, {
typeInfo: createTypeInfo({ typeInfo: createTestEntity(TypeInfoTypeRef, {
application: MailTypeModel.app, application: MailTypeModel.app,
typeId: String(MailTypeModel.id), typeId: String(MailTypeModel.id),
}), }),
@ -1077,8 +1072,8 @@ o.spec("crypto facade", function () {
}) })
const FileTypeModel = await resolveTypeReference(FileTypeRef) const FileTypeModel = await resolveTypeReference(FileTypeRef)
const bucketEncSessionKeys = fileSessionKeys.map((fileSessionKey, index) => { const bucketEncSessionKeys = fileSessionKeys.map((fileSessionKey, index) => {
return createInstanceSessionKey({ return createTestEntity(InstanceSessionKeyTypeRef, {
typeInfo: createTypeInfo({ typeInfo: createTestEntity(TypeInfoTypeRef, {
application: FileTypeModel.app, application: FileTypeModel.app,
typeId: String(FileTypeModel.id), typeId: String(FileTypeModel.id),
}), }),
@ -1089,7 +1084,7 @@ o.spec("crypto facade", function () {
}) })
bucketEncSessionKeys.push(mailInstanceSessionKey) bucketEncSessionKeys.push(mailInstanceSessionKey)
const bucketKey = createBucketKey({ const bucketKey = createTestEntity(BucketKeyTypeRef, {
pubEncBucketKey: null, pubEncBucketKey: null,
keyGroup: externalUserGroupEncBucketKey ? userGroup._id : null, keyGroup: externalUserGroupEncBucketKey ? userGroup._id : null,
groupEncBucketKey: groupEncBucketKey, groupEncBucketKey: groupEncBucketKey,
@ -1100,11 +1095,11 @@ o.spec("crypto facade", function () {
const bucketKeyLiteral = await instanceMapper.encryptAndMapToLiteral(BucketKeyModel, bucketKey, null) const bucketKeyLiteral = await instanceMapper.encryptAndMapToLiteral(BucketKeyModel, bucketKey, null)
Object.assign(mailLiteral, { bucketKey: bucketKeyLiteral }) Object.assign(mailLiteral, { bucketKey: bucketKeyLiteral })
const mem = createGroupMembership({ const mem = createTestEntity(GroupMembershipTypeRef, {
group: userGroup._id, group: userGroup._id,
}) })
const user = createUser({ const user = createTestEntity(UserTypeRef, {
userGroup: mem, userGroup: mem,
}) })

View file

@ -26,13 +26,13 @@ o.spec("OwnerEncSessionKeysUpdateQueue", function () {
o.spec("updateInstanceSessionKeys", function () { o.spec("updateInstanceSessionKeys", function () {
o("send updates from queue", async function () { o("send updates from queue", async function () {
const updatableInstanceSessionKeys = [ const updatableInstanceSessionKeys = [
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceId: "mailInstanceId", instanceId: "mailInstanceId",
instanceList: "mailInstanceList", instanceList: "mailInstanceList",
typeInfo: createTestEntity(TypeInfoTypeRef), typeInfo: createTestEntity(TypeInfoTypeRef),
symEncSessionKey: new Uint8Array([1, 2, 3]), symEncSessionKey: new Uint8Array([1, 2, 3]),
}), }),
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceId: "fileInstanceId", instanceId: "fileInstanceId",
instanceList: "fileInstanceList", instanceList: "fileInstanceList",
typeInfo: createTestEntity(TypeInfoTypeRef), typeInfo: createTestEntity(TypeInfoTypeRef),
@ -64,13 +64,13 @@ o.spec("OwnerEncSessionKeysUpdateQueue", function () {
} }
}) })
const updatableInstanceSessionKeys = [ const updatableInstanceSessionKeys = [
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceId: "mailInstanceId", instanceId: "mailInstanceId",
instanceList: "mailInstanceList", instanceList: "mailInstanceList",
typeInfo: createTestEntity(TypeInfoTypeRef), typeInfo: createTestEntity(TypeInfoTypeRef),
symEncSessionKey: new Uint8Array([1, 2, 3]), symEncSessionKey: new Uint8Array([1, 2, 3]),
}), }),
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceId: "fileInstanceId", instanceId: "fileInstanceId",
instanceList: "fileInstanceList", instanceList: "fileInstanceList",
typeInfo: createTestEntity(TypeInfoTypeRef), typeInfo: createTestEntity(TypeInfoTypeRef),
@ -93,13 +93,13 @@ o.spec("OwnerEncSessionKeysUpdateQueue", function () {
o("debounced request sends entire queue", async function () { o("debounced request sends entire queue", async function () {
const updatableInstanceSessionKeys = [ const updatableInstanceSessionKeys = [
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceId: "mailInstanceId", instanceId: "mailInstanceId",
instanceList: "mailInstanceList", instanceList: "mailInstanceList",
typeInfo: createTestEntity(TypeInfoTypeRef), typeInfo: createTestEntity(TypeInfoTypeRef),
symEncSessionKey: new Uint8Array([1, 2, 3]), symEncSessionKey: new Uint8Array([1, 2, 3]),
}), }),
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceId: "fileInstanceId", instanceId: "fileInstanceId",
instanceList: "fileInstanceList", instanceList: "fileInstanceList",
typeInfo: createTestEntity(TypeInfoTypeRef), typeInfo: createTestEntity(TypeInfoTypeRef),

View file

@ -1,23 +1,24 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { ArchiveDataType } from "../../../../../src/api/common/TutanotaConstants.js" import { ArchiveDataType } from "../../../../../src/api/common/TutanotaConstants.js"
import { createBlob } from "../../../../../src/api/entities/sys/TypeRefs.js"
import { createFile, createMailBody } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
import { ServiceExecutor } from "../../../../../src/api/worker/rest/ServiceExecutor.js" import { ServiceExecutor } from "../../../../../src/api/worker/rest/ServiceExecutor.js"
import { matchers, object, verify, when } from "testdouble" import { matchers, object, verify, when } from "testdouble"
import { BlobAccessTokenService } from "../../../../../src/api/entities/storage/Services.js" import { BlobAccessTokenService } from "../../../../../src/api/entities/storage/Services.js"
import { getElementId, getEtId, getListId } from "../../../../../src/api/common/utils/EntityUtils.js" import { getElementId, getEtId, getListId } from "../../../../../src/api/common/utils/EntityUtils.js"
import { Mode } from "../../../../../src/api/common/Env.js" import { Mode } from "../../../../../src/api/common/Env.js"
import {
createBlobAccessTokenPostIn,
createBlobAccessTokenPostOut,
createBlobReadData,
createBlobServerAccessInfo,
createBlobWriteData,
createInstanceId,
} from "../../../../../src/api/entities/storage/TypeRefs.js"
import { BlobAccessTokenFacade, BlobReferencingInstance } from "../../../../../src/api/worker/facades/BlobAccessTokenFacade.js" import { BlobAccessTokenFacade, BlobReferencingInstance } from "../../../../../src/api/worker/facades/BlobAccessTokenFacade.js"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade.js" import { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade.js"
import {
BlobAccessTokenPostInTypeRef,
BlobAccessTokenPostOutTypeRef,
BlobReadDataTypeRef,
BlobServerAccessInfoTypeRef,
BlobWriteDataTypeRef,
InstanceIdTypeRef,
} from "../../../../../src/api/entities/storage/TypeRefs.js"
import { createTestEntity } from "../../../TestUtils.js"
import { FileTypeRef, MailBodyTypeRef } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
import { BlobTypeRef } from "../../../../../src/api/entities/sys/TypeRefs.js"
const { anything, captor } = matchers const { anything, captor } = matchers
@ -28,7 +29,12 @@ o.spec("BlobAccessTokenFacade test", function () {
let authDataProvider: AuthDataProvider let authDataProvider: AuthDataProvider
const archiveId = "archiveId1" const archiveId = "archiveId1"
const blobId1 = "blobId1" const blobId1 = "blobId1"
const blobs = [createBlob({ archiveId, blobId: blobId1 }), createBlob({ archiveId, blobId: "blobId2" }), createBlob({ archiveId })] // @ts-ignore
const blobs = [
createTestEntity(BlobTypeRef, { archiveId, blobId: blobId1 }),
createTestEntity(BlobTypeRef, { archiveId, blobId: "blobId2" }),
createTestEntity(BlobTypeRef, { archiveId }),
]
let now: DateTime let now: DateTime
o.beforeEach(function () { o.beforeEach(function () {
@ -48,8 +54,10 @@ o.spec("BlobAccessTokenFacade test", function () {
o.spec("evict Tokens", function () { o.spec("evict Tokens", function () {
o("evict blob specific read token", async function () { o("evict blob specific read token", async function () {
const file = createFile({ blobs, _id: ["listId", "elementId"] }) const file = createTestEntity(FileTypeRef, { blobs, _id: ["listId", "elementId"] })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "123" }) }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const referencingInstance: BlobReferencingInstance = { const referencingInstance: BlobReferencingInstance = {
blobs, blobs,
@ -60,35 +68,41 @@ o.spec("BlobAccessTokenFacade test", function () {
await blobAccessTokenFacade.requestReadTokenBlobs(archiveDataType, referencingInstance) await blobAccessTokenFacade.requestReadTokenBlobs(archiveDataType, referencingInstance)
blobAccessTokenFacade.evictReadBlobsToken(referencingInstance) blobAccessTokenFacade.evictReadBlobsToken(referencingInstance)
const newToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "456" }) }) const newToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "456" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(newToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(newToken)
const readToken = await blobAccessTokenFacade.requestReadTokenBlobs(archiveDataType, referencingInstance) const readToken = await blobAccessTokenFacade.requestReadTokenBlobs(archiveDataType, referencingInstance)
o(readToken).equals(newToken.blobAccessInfo) o(readToken).equals(newToken.blobAccessInfo)
}) })
o("evict archive read token", async function () { o("evict archive read token", async function () {
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123" }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, { blobAccessInfo })
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
await blobAccessTokenFacade.requestReadTokenArchive(archiveId) await blobAccessTokenFacade.requestReadTokenArchive(archiveId)
blobAccessTokenFacade.evictArchiveToken(archiveId) blobAccessTokenFacade.evictArchiveToken(archiveId)
const newToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "456" }) }) const newToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "456" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(newToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(newToken)
const readToken = await blobAccessTokenFacade.requestReadTokenArchive(archiveId) const readToken = await blobAccessTokenFacade.requestReadTokenArchive(archiveId)
o(readToken).equals(newToken.blobAccessInfo) o(readToken).equals(newToken.blobAccessInfo)
}) })
o("evict archive write token", async function () { o("evict archive write token", async function () {
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123" }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, { blobAccessInfo })
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const ownerGroupId = "ownerGroupId" const ownerGroupId = "ownerGroupId"
const archiveDataType = ArchiveDataType.Attachments const archiveDataType = ArchiveDataType.Attachments
await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroupId) await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroupId)
blobAccessTokenFacade.evictWriteToken(archiveDataType, ownerGroupId) blobAccessTokenFacade.evictWriteToken(archiveDataType, ownerGroupId)
const newToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "456" }) }) const newToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "456" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(newToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(newToken)
const readToken = await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroupId) const readToken = await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroupId)
o(readToken).equals(newToken.blobAccessInfo) o(readToken).equals(newToken.blobAccessInfo)
@ -98,8 +112,10 @@ o.spec("BlobAccessTokenFacade test", function () {
o.spec("request access tokens", function () { o.spec("request access tokens", function () {
o.spec("read token for specific blobs", function () { o.spec("read token for specific blobs", function () {
o("read token LET", async function () { o("read token LET", async function () {
const file = createFile({ blobs, _id: ["listId", "elementId"] }) const file = createTestEntity(FileTypeRef, { blobs, _id: ["listId", "elementId"] })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "123" }) }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const referencingInstance: BlobReferencingInstance = { const referencingInstance: BlobReferencingInstance = {
@ -112,11 +128,11 @@ o.spec("BlobAccessTokenFacade test", function () {
const tokenRequest = captor() const tokenRequest = captor()
verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture())) verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture()))
let instanceId = createInstanceId({ instanceId: getElementId(file) }) let instanceId = createTestEntity(InstanceIdTypeRef, { instanceId: getElementId(file) })
o(tokenRequest.value).deepEquals( o(tokenRequest.value).deepEquals(
createBlobAccessTokenPostIn({ createTestEntity(BlobAccessTokenPostInTypeRef, {
archiveDataType, archiveDataType,
read: createBlobReadData({ read: createTestEntity(BlobReadDataTypeRef, {
archiveId, archiveId,
instanceListId: getListId(file), instanceListId: getListId(file),
instanceIds: [instanceId], instanceIds: [instanceId],
@ -127,8 +143,10 @@ o.spec("BlobAccessTokenFacade test", function () {
}) })
o("read token ET", async function () { o("read token ET", async function () {
const mailBody = createMailBody({ _id: "elementId" }) const mailBody = createTestEntity(MailBodyTypeRef, { _id: "elementId" })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "123" }) }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const referencingInstance: BlobReferencingInstance = { const referencingInstance: BlobReferencingInstance = {
@ -141,11 +159,11 @@ o.spec("BlobAccessTokenFacade test", function () {
const tokenRequest = captor() const tokenRequest = captor()
verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture())) verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture()))
let instanceId = createInstanceId({ instanceId: getEtId(mailBody) }) let instanceId = createTestEntity(InstanceIdTypeRef, { instanceId: getEtId(mailBody) })
o(tokenRequest.value).deepEquals( o(tokenRequest.value).deepEquals(
createBlobAccessTokenPostIn({ createTestEntity(BlobAccessTokenPostInTypeRef, {
archiveDataType, archiveDataType,
read: createBlobReadData({ read: createTestEntity(BlobReadDataTypeRef, {
archiveId, archiveId,
instanceListId: null, instanceListId: null,
instanceIds: [instanceId], instanceIds: [instanceId],
@ -157,8 +175,8 @@ o.spec("BlobAccessTokenFacade test", function () {
}) })
o("request read token archive", async function () { o("request read token archive", async function () {
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123" }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, { blobAccessInfo })
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const readToken = await blobAccessTokenFacade.requestReadTokenArchive(archiveId) const readToken = await blobAccessTokenFacade.requestReadTokenArchive(archiveId)
@ -166,8 +184,8 @@ o.spec("BlobAccessTokenFacade test", function () {
const tokenRequest = captor() const tokenRequest = captor()
verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture())) verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture()))
o(tokenRequest.value).deepEquals( o(tokenRequest.value).deepEquals(
createBlobAccessTokenPostIn({ createTestEntity(BlobAccessTokenPostInTypeRef, {
read: createBlobReadData({ read: createTestEntity(BlobReadDataTypeRef, {
archiveId, archiveId,
instanceListId: null, instanceListId: null,
instanceIds: [], instanceIds: [],
@ -178,8 +196,8 @@ o.spec("BlobAccessTokenFacade test", function () {
}) })
o("cache read token for an entire archive", async function () { o("cache read token for an entire archive", async function () {
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123" }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" })
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, { blobAccessInfo })
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
await blobAccessTokenFacade.requestReadTokenArchive(archiveId) await blobAccessTokenFacade.requestReadTokenArchive(archiveId)
@ -194,14 +212,14 @@ o.spec("BlobAccessTokenFacade test", function () {
o("cache read token archive expired", async function () { o("cache read token archive expired", async function () {
let expires = new Date(now.toMillis() - 1) // date in the past, so the token is expired let expires = new Date(now.toMillis() - 1) // date in the past, so the token is expired
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123", expires }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123", expires })
let expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo }) let expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, { blobAccessInfo })
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
await blobAccessTokenFacade.requestReadTokenArchive(archiveId) await blobAccessTokenFacade.requestReadTokenArchive(archiveId)
blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "456" }) blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "456" })
expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo }) expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, { blobAccessInfo })
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
// request it twice and verify that there is only one network request // request it twice and verify that there is only one network request
@ -215,7 +233,9 @@ o.spec("BlobAccessTokenFacade test", function () {
o("request write token", async function () { o("request write token", async function () {
const ownerGroup = "ownerId" const ownerGroup = "ownerId"
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "123" }) }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const writeToken = await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup) const writeToken = await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup)
@ -223,9 +243,9 @@ o.spec("BlobAccessTokenFacade test", function () {
const tokenRequest = captor() const tokenRequest = captor()
verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture())) verify(serviceMock.post(BlobAccessTokenService, tokenRequest.capture()))
o(tokenRequest.value).deepEquals( o(tokenRequest.value).deepEquals(
createBlobAccessTokenPostIn({ createTestEntity(BlobAccessTokenPostInTypeRef, {
archiveDataType, archiveDataType,
write: createBlobWriteData({ write: createTestEntity(BlobWriteDataTypeRef, {
archiveOwnerGroup: ownerGroup, archiveOwnerGroup: ownerGroup,
}), }),
}), }),
@ -235,7 +255,9 @@ o.spec("BlobAccessTokenFacade test", function () {
o("cache write token", async function () { o("cache write token", async function () {
const ownerGroup = "ownerId" const ownerGroup = "ownerId"
const expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "123" }) }) const expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup) await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup)
@ -250,12 +272,16 @@ o.spec("BlobAccessTokenFacade test", function () {
o("cache write token expired", async function () { o("cache write token expired", async function () {
let expires = new Date(now.toMillis() - 1) // date in the past, so the token is expired let expires = new Date(now.toMillis() - 1) // date in the past, so the token is expired
const ownerGroup = "ownerId" const ownerGroup = "ownerId"
let expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "123", expires }) }) let expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "123", expires }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup) await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup)
expectedToken = createBlobAccessTokenPostOut({ blobAccessInfo: createBlobServerAccessInfo({ blobAccessToken: "456" }) }) expectedToken = createTestEntity(BlobAccessTokenPostOutTypeRef, {
blobAccessInfo: createTestEntity(BlobServerAccessInfoTypeRef, { blobAccessToken: "456" }),
})
when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken) when(serviceMock.post(BlobAccessTokenService, anything())).thenResolve(expectedToken)
const writeToken = await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup) const writeToken = await blobAccessTokenFacade.requestWriteToken(archiveDataType, ownerGroup)

View file

@ -6,8 +6,8 @@ import { NativeFileApp } from "../../../../../src/native/common/FileApp.js"
import { AesApp } from "../../../../../src/native/worker/AesApp.js" import { AesApp } from "../../../../../src/native/worker/AesApp.js"
import { InstanceMapper } from "../../../../../src/api/worker/crypto/InstanceMapper.js" import { InstanceMapper } from "../../../../../src/api/worker/crypto/InstanceMapper.js"
import { ArchiveDataType, MAX_BLOB_SIZE_BYTES } from "../../../../../src/api/common/TutanotaConstants.js" import { ArchiveDataType, MAX_BLOB_SIZE_BYTES } from "../../../../../src/api/common/TutanotaConstants.js"
import { BlobTypeRef, createBlob, createBlobReferenceTokenWrapper } from "../../../../../src/api/entities/sys/TypeRefs.js" import { BlobReferenceTokenWrapperTypeRef, BlobTypeRef, createBlob, createBlobReferenceTokenWrapper } from "../../../../../src/api/entities/sys/TypeRefs.js"
import { createFile, File as TutanotaFile } from "../../../../../src/api/entities/tutanota/TypeRefs.js" import { createFile, File as TutanotaFile, FileTypeRef } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
import { ServiceExecutor } from "../../../../../src/api/worker/rest/ServiceExecutor.js" import { ServiceExecutor } from "../../../../../src/api/worker/rest/ServiceExecutor.js"
import { instance, matchers, object, verify, when } from "testdouble" import { instance, matchers, object, verify, when } from "testdouble"
import { HttpMethod } from "../../../../../src/api/common/EntityFunctions.js" import { HttpMethod } from "../../../../../src/api/common/EntityFunctions.js"
@ -18,7 +18,14 @@ import { CryptoFacade } from "../../../../../src/api/worker/crypto/CryptoFacade.
import { FileReference } from "../../../../../src/api/common/utils/FileUtils.js" import { FileReference } from "../../../../../src/api/common/utils/FileUtils.js"
import { assertThrows } from "@tutao/tutanota-test-utils" import { assertThrows } from "@tutao/tutanota-test-utils"
import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js" import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js"
import { createBlobPostOut, createBlobServerAccessInfo, createBlobServerUrl } from "../../../../../src/api/entities/storage/TypeRefs.js" import {
BlobPostOutTypeRef,
BlobServerAccessInfoTypeRef,
BlobServerUrlTypeRef,
createBlobPostOut,
createBlobServerAccessInfo,
createBlobServerUrl,
} from "../../../../../src/api/entities/storage/TypeRefs.js"
import type { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade.js" import type { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade.js"
import { BlobAccessTokenFacade, BlobReferencingInstance } from "../../../../../src/api/worker/facades/BlobAccessTokenFacade.js" import { BlobAccessTokenFacade, BlobReferencingInstance } from "../../../../../src/api/worker/facades/BlobAccessTokenFacade.js"
import { DateProvider } from "../../../../../src/api/common/DateProvider.js" import { DateProvider } from "../../../../../src/api/common/DateProvider.js"
@ -39,7 +46,11 @@ o.spec("BlobFacade test", function () {
let instanceMapperMock: InstanceMapper let instanceMapperMock: InstanceMapper
const archiveId = "archiveId1" const archiveId = "archiveId1"
const blobId1 = "blobId1" const blobId1 = "blobId1"
const blobs = [createBlob({ archiveId, blobId: blobId1 }), createBlob({ archiveId, blobId: "blobId2" }), createBlob({ archiveId })] const blobs = [
createTestEntity(BlobTypeRef, { archiveId, blobId: blobId1 }),
createTestEntity(BlobTypeRef, { archiveId, blobId: "blobId2" }),
createTestEntity(BlobTypeRef, { archiveId }),
]
let archiveDataType = ArchiveDataType.Attachments let archiveDataType = ArchiveDataType.Attachments
let cryptoFacadeMock: CryptoFacade let cryptoFacadeMock: CryptoFacade
let dateProvider: DateProvider let dateProvider: DateProvider
@ -58,7 +69,7 @@ o.spec("BlobFacade test", function () {
const mimeType = "text/plain" const mimeType = "text/plain"
const name = "fileName" const name = "fileName"
file = createFile({ name, mimeType, _id: ["fileListId", "fileElementId"] }) file = createTestEntity(FileTypeRef, { name, mimeType, _id: ["fileListId", "fileElementId"] })
blobFacade = new BlobFacade( blobFacade = new BlobFacade(
authDataProvider, authDataProvider,
@ -83,11 +94,14 @@ o.spec("BlobFacade test", function () {
const sessionKey = aes128RandomKey() const sessionKey = aes128RandomKey()
const blobData = new Uint8Array([1, 2, 3]) const blobData = new Uint8Array([1, 2, 3])
const expectedReferenceTokens = [createBlobReferenceTokenWrapper({ blobReferenceToken: "blobRefToken" })] const expectedReferenceTokens = [createTestEntity(BlobReferenceTokenWrapperTypeRef, { blobReferenceToken: "blobRefToken" })]
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123", servers: [createBlobServerUrl({ url: "w1" })] }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken: "123",
servers: [createTestEntity(BlobServerUrlTypeRef, { url: "w1" })],
})
when(blobAccessTokenFacade.requestWriteToken(anything(), anything())).thenResolve(blobAccessInfo) when(blobAccessTokenFacade.requestWriteToken(anything(), anything())).thenResolve(blobAccessInfo)
let blobServiceResponse = createBlobPostOut({ blobReferenceToken: expectedReferenceTokens[0].blobReferenceToken }) let blobServiceResponse = createTestEntity(BlobPostOutTypeRef, { blobReferenceToken: expectedReferenceTokens[0].blobReferenceToken })
when(instanceMapperMock.decryptAndMapToInstance(anything(), anything(), anything())).thenResolve(blobServiceResponse) when(instanceMapperMock.decryptAndMapToInstance(anything(), anything(), anything())).thenResolve(blobServiceResponse)
when(restClientMock.request(BLOB_SERVICE_REST_PATH, HttpMethod.POST, anything())).thenResolve(JSON.stringify(blobServiceResponse)) when(restClientMock.request(BLOB_SERVICE_REST_PATH, HttpMethod.POST, anything())).thenResolve(JSON.stringify(blobServiceResponse))
@ -106,16 +120,16 @@ o.spec("BlobFacade test", function () {
const ownerGroup = "ownerId" const ownerGroup = "ownerId"
const sessionKey = aes128RandomKey() const sessionKey = aes128RandomKey()
const expectedReferenceTokens = [createBlobReferenceTokenWrapper({ blobReferenceToken: "blobRefToken" })] const expectedReferenceTokens = [createTestEntity(BlobReferenceTokenWrapperTypeRef, { blobReferenceToken: "blobRefToken" })]
const uploadedFileUri = "rawFileUri" const uploadedFileUri = "rawFileUri"
const chunkUris = ["uri1"] const chunkUris = ["uri1"]
let blobAccessInfo = createBlobServerAccessInfo({ let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken: "123", blobAccessToken: "123",
servers: [createBlobServerUrl({ url: "http://w1.api.tuta.com" })], servers: [createTestEntity(BlobServerUrlTypeRef, { url: "http://w1.api.tuta.com" })],
}) })
when(blobAccessTokenFacade.requestWriteToken(anything(), anything())).thenResolve(blobAccessInfo) when(blobAccessTokenFacade.requestWriteToken(anything(), anything())).thenResolve(blobAccessInfo)
let blobServiceResponse = createBlobPostOut({ blobReferenceToken: expectedReferenceTokens[0].blobReferenceToken }) let blobServiceResponse = createTestEntity(BlobPostOutTypeRef, { blobReferenceToken: expectedReferenceTokens[0].blobReferenceToken })
when(blobAccessTokenFacade.createQueryParams(blobAccessInfo, anything(), anything())).thenResolve({ test: "theseAreTheParamsIPromise" }) when(blobAccessTokenFacade.createQueryParams(blobAccessInfo, anything(), anything())).thenResolve({ test: "theseAreTheParamsIPromise" })
when(instanceMapperMock.decryptAndMapToInstance(anything(), anything(), anything())).thenResolve(blobServiceResponse) when(instanceMapperMock.decryptAndMapToInstance(anything(), anything(), anything())).thenResolve(blobServiceResponse)
@ -154,7 +168,10 @@ o.spec("BlobFacade test", function () {
file.blobs.push(createTestEntity(BlobTypeRef)) file.blobs.push(createTestEntity(BlobTypeRef))
const encryptedBlobData = aesEncrypt(sessionKey, blobData, generateIV(), true, true) const encryptedBlobData = aesEncrypt(sessionKey, blobData, generateIV(), true, true)
let blobAccessInfo = createBlobServerAccessInfo({ blobAccessToken: "123", servers: [createBlobServerUrl({ url: "someBaseUrl" })] }) let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken: "123",
servers: [createTestEntity(BlobServerUrlTypeRef, { url: "someBaseUrl" })],
})
when(blobAccessTokenFacade.requestReadTokenBlobs(anything(), anything())).thenResolve(blobAccessInfo) when(blobAccessTokenFacade.requestReadTokenBlobs(anything(), anything())).thenResolve(blobAccessInfo)
when(blobAccessTokenFacade.createQueryParams(blobAccessInfo, anything(), anything())).thenResolve({ when(blobAccessTokenFacade.createQueryParams(blobAccessInfo, anything(), anything())).thenResolve({
baseUrl: "someBaseUrl", baseUrl: "someBaseUrl",
@ -180,9 +197,9 @@ o.spec("BlobFacade test", function () {
file.blobs.push(blobs[0]) file.blobs.push(blobs[0])
let blobAccessInfo = createBlobServerAccessInfo({ let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken: "123", blobAccessToken: "123",
servers: [createBlobServerUrl({ url: "http://w1.api.tuta.com" })], servers: [createTestEntity(BlobServerUrlTypeRef, { url: "http://w1.api.tuta.com" })],
}) })
when(blobAccessTokenFacade.requestReadTokenBlobs(anything(), anything())).thenResolve(blobAccessInfo) when(blobAccessTokenFacade.requestReadTokenBlobs(anything(), anything())).thenResolve(blobAccessInfo)
when(blobAccessTokenFacade.createQueryParams(anything(), anything(), anything())).thenResolve({ test: "theseAreTheParamsIPromise" }) when(blobAccessTokenFacade.createQueryParams(anything(), anything(), anything())).thenResolve({ test: "theseAreTheParamsIPromise" })
@ -226,9 +243,9 @@ o.spec("BlobFacade test", function () {
file.blobs.push(blobs[0]) file.blobs.push(blobs[0])
file.blobs.push(blobs[1]) file.blobs.push(blobs[1])
let blobAccessInfo = createBlobServerAccessInfo({ let blobAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken: "123", blobAccessToken: "123",
servers: [createBlobServerUrl({ url: "http://w1.api.tuta.com" })], servers: [createTestEntity(BlobServerUrlTypeRef, { url: "http://w1.api.tuta.com" })],
}) })
when(blobAccessTokenFacade.requestReadTokenBlobs(anything(), anything())).thenResolve(blobAccessInfo) when(blobAccessTokenFacade.requestReadTokenBlobs(anything(), anything())).thenResolve(blobAccessInfo)
when(cryptoFacadeMock.resolveSessionKeyForInstance(file)).thenResolve(sessionKey) when(cryptoFacadeMock.resolveSessionKeyForInstance(file)).thenResolve(sessionKey)

View file

@ -6,14 +6,19 @@ import { DefaultEntityRestCache } from "../../../../../src/api/worker/rest/Defau
import { clone, downcast, isSameTypeRef, neverNull, noOp } from "@tutao/tutanota-utils" import { clone, downcast, isSameTypeRef, neverNull, noOp } from "@tutao/tutanota-utils"
import type { AlarmInfo, User, UserAlarmInfo } from "../../../../../src/api/entities/sys/TypeRefs.js" import type { AlarmInfo, User, UserAlarmInfo } from "../../../../../src/api/entities/sys/TypeRefs.js"
import { import {
AlarmInfoTypeRef,
CalendarEventRefTypeRef,
createAlarmInfo, createAlarmInfo,
createCalendarEventRef, createCalendarEventRef,
createPushIdentifierList, createPushIdentifierList,
createUser, createUser,
createUserAlarmInfo, createUserAlarmInfo,
createUserAlarmInfoListType, createUserAlarmInfoListType,
PushIdentifierListTypeRef,
PushIdentifierTypeRef, PushIdentifierTypeRef,
UserAlarmInfoListTypeTypeRef,
UserAlarmInfoTypeRef, UserAlarmInfoTypeRef,
UserTypeRef,
} from "../../../../../src/api/entities/sys/TypeRefs.js" } from "../../../../../src/api/entities/sys/TypeRefs.js"
import { getElementId, getLetId, getListId } from "../../../../../src/api/common/utils/EntityUtils.js" import { getElementId, getLetId, getListId } from "../../../../../src/api/common/utils/EntityUtils.js"
import type { CalendarEvent } from "../../../../../src/api/entities/tutanota/TypeRefs.js" import type { CalendarEvent } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
@ -31,6 +36,7 @@ import { UserFacade } from "../../../../../src/api/worker/facades/UserFacade"
import { InfoMessageHandler } from "../../../../../src/gui/InfoMessageHandler.js" import { InfoMessageHandler } from "../../../../../src/gui/InfoMessageHandler.js"
import { ConnectionError } from "../../../../../src/api/common/error/RestError.js" import { ConnectionError } from "../../../../../src/api/common/error/RestError.js"
import { EntityClient } from "../../../../../src/api/common/EntityClient.js" import { EntityClient } from "../../../../../src/api/common/EntityClient.js"
import { createTestEntity } from "../../../TestUtils.js"
o.spec("CalendarFacadeTest", async function () { o.spec("CalendarFacadeTest", async function () {
let userAlarmInfoListId: Id let userAlarmInfoListId: Id
@ -71,22 +77,22 @@ o.spec("CalendarFacadeTest", async function () {
} }
function makeEvent(listId: Id, elementId?: Id): CalendarEvent { function makeEvent(listId: Id, elementId?: Id): CalendarEvent {
return createCalendarEvent({ return createTestEntity(CalendarEventTypeRef, {
_id: [listId, elementId || restClientMock.getNextId()], _id: [listId, elementId || restClientMock.getNextId()],
uid: `${listId}-${elementId}`, uid: `${listId}-${elementId}`,
}) })
} }
function makeUserAlarmInfo(event: CalendarEvent): UserAlarmInfo { function makeUserAlarmInfo(event: CalendarEvent): UserAlarmInfo {
return createUserAlarmInfo({ return createTestEntity(UserAlarmInfoTypeRef, {
_id: [userAlarmInfoListId, restClientMock.getNextId()], _id: [userAlarmInfoListId, restClientMock.getNextId()],
alarmInfo: makeAlarmInfo(event), alarmInfo: makeAlarmInfo(event),
}) })
} }
function makeAlarmInfo(event: CalendarEvent): AlarmInfo { function makeAlarmInfo(event: CalendarEvent): AlarmInfo {
return createAlarmInfo({ return createTestEntity(AlarmInfoTypeRef, {
calendarRef: createCalendarEventRef({ calendarRef: createTestEntity(CalendarEventRefTypeRef, {
elementId: getElementId(event), elementId: getElementId(event),
listId: getListId(event), listId: getListId(event),
}), }),
@ -97,11 +103,11 @@ o.spec("CalendarFacadeTest", async function () {
restClientMock = new EntityRestClientMock() restClientMock = new EntityRestClientMock()
userAlarmInfoListId = restClientMock.getNextId() userAlarmInfoListId = restClientMock.getNextId()
user = createUser({ user = createTestEntity(UserTypeRef, {
alarmInfoList: createUserAlarmInfoListType({ alarmInfoList: createTestEntity(UserAlarmInfoListTypeTypeRef, {
alarms: userAlarmInfoListId, alarms: userAlarmInfoListId,
}), }),
pushIdentifierList: createPushIdentifierList({ list: "pushIdentifierList" }), pushIdentifierList: createTestEntity(PushIdentifierListTypeRef, { list: "pushIdentifierList" }),
userGroup: downcast({ userGroup: downcast({
group: "Id", group: "Id",
}), }),
@ -435,7 +441,7 @@ o.spec("CalendarFacadeTest", async function () {
}) })
o("sorts array with len 1", function () { o("sorts array with len 1", function () {
const arr = [createCalendarEvent({ recurrenceId: new Date("2023-07-17T13:00") })] as Array<CalendarEventAlteredInstance> const arr = [createTestEntity(CalendarEventTypeRef, { recurrenceId: new Date("2023-07-17T13:00") })] as Array<CalendarEventAlteredInstance>
const expected = clone(arr) const expected = clone(arr)
sortByRecurrenceId(arr) sortByRecurrenceId(arr)
o(arr).deepEquals(expected) o(arr).deepEquals(expected)
@ -443,8 +449,8 @@ o.spec("CalendarFacadeTest", async function () {
o("sorts array that's not sorted", function () { o("sorts array that's not sorted", function () {
const arr = [ const arr = [
createCalendarEvent({ recurrenceId: new Date("2023-07-17T13:00") }), createTestEntity(CalendarEventTypeRef, { recurrenceId: new Date("2023-07-17T13:00") }),
createCalendarEvent({ recurrenceId: new Date("2023-07-16T13:00") }), createTestEntity(CalendarEventTypeRef, { recurrenceId: new Date("2023-07-16T13:00") }),
] as Array<CalendarEventAlteredInstance> ] as Array<CalendarEventAlteredInstance>
const expected = clone(arr) const expected = clone(arr)
const smaller = expected[1] const smaller = expected[1]

View file

@ -5,10 +5,14 @@ import {
createGroupInfo, createGroupInfo,
createGroupMembership, createGroupMembership,
createSaltReturn, createSaltReturn,
CreateSessionReturnTypeRef,
createUser, createUser,
createUserExternalAuthInfo, createUserExternalAuthInfo,
GroupInfoTypeRef, GroupInfoTypeRef,
GroupMembershipTypeRef,
SaltReturnTypeRef,
User, User,
UserExternalAuthInfoTypeRef,
UserTypeRef, UserTypeRef,
} from "../../../../../src/api/entities/sys/TypeRefs" } from "../../../../../src/api/entities/sys/TypeRefs"
import { createAuthVerifier, encryptKey, keyToBase64, sha256Hash } from "@tutao/tutanota-crypto" import { createAuthVerifier, encryptKey, keyToBase64, sha256Hash } from "@tutao/tutanota-crypto"
@ -65,15 +69,15 @@ async function makeUser({ id, passphrase, salt }, facade: LoginFacade): Promise<
const groupKey = encryptKey(userPassphraseKey, [3229306880, 2716953871, 4072167920, 3901332676]) const groupKey = encryptKey(userPassphraseKey, [3229306880, 2716953871, 4072167920, 3901332676])
return createUser({ return createTestEntity(UserTypeRef, {
_id: id, _id: id,
verifier: sha256Hash(createAuthVerifier(userPassphraseKey)), verifier: sha256Hash(createAuthVerifier(userPassphraseKey)),
userGroup: createGroupMembership({ userGroup: createTestEntity(GroupMembershipTypeRef, {
group: "groupId", group: "groupId",
symEncGKey: groupKey, symEncGKey: groupKey,
groupInfo: ["groupInfoListId", "groupInfoElId"], groupInfo: ["groupInfoListId", "groupInfoElId"],
}), }),
externalAuthInfo: createUserExternalAuthInfo({ externalAuthInfo: createTestEntity(UserExternalAuthInfoTypeRef, {
latestSaltHash: SALT, latestSaltHash: SALT,
}), }),
}) })
@ -102,7 +106,7 @@ o.spec("LoginFacadeTest", function () {
o.beforeEach(function () { o.beforeEach(function () {
workerMock = instance(WorkerImpl) workerMock = instance(WorkerImpl)
serviceExecutor = object() serviceExecutor = object()
when(serviceExecutor.get(SaltService, anything()), { ignoreExtraArgs: true }).thenResolve(createSaltReturn({ salt: SALT })) when(serviceExecutor.get(SaltService, anything()), { ignoreExtraArgs: true }).thenResolve(createTestEntity(SaltReturnTypeRef, { salt: SALT }))
restClientMock = instance(RestClient) restClientMock = instance(RestClient)
entityClientMock = instance(EntityClient) entityClientMock = instance(EntityClient)
@ -165,7 +169,7 @@ o.spec("LoginFacadeTest", function () {
o.beforeEach(async function () { o.beforeEach(async function () {
when(serviceExecutor.post(SessionService, anything()), { ignoreExtraArgs: true }).thenResolve( when(serviceExecutor.post(SessionService, anything()), { ignoreExtraArgs: true }).thenResolve(
createCreateSessionReturn({ user: userId, accessToken: "accessToken", challenges: [] }), createTestEntity(CreateSessionReturnTypeRef, { user: userId, accessToken: "accessToken", challenges: [] }),
) )
when(entityClientMock.load(UserTypeRef, userId)).thenResolve( when(entityClientMock.load(UserTypeRef, userId)).thenResolve(
await makeUser( await makeUser(
@ -618,7 +622,7 @@ o.spec("LoginFacadeTest", function () {
}, },
facade, facade,
) )
user.externalAuthInfo = createUserExternalAuthInfo({ user.externalAuthInfo = createTestEntity(UserExternalAuthInfoTypeRef, {
latestSaltHash: sha256Hash(SALT), latestSaltHash: sha256Hash(SALT),
}) })

View file

@ -11,6 +11,7 @@ import {
createMailAddressProperties, createMailAddressProperties,
createMailboxGroupRoot, createMailboxGroupRoot,
createMailboxProperties, createMailboxProperties,
MailAddressPropertiesTypeRef,
MailboxGroupRootTypeRef, MailboxGroupRootTypeRef,
MailboxPropertiesTypeRef, MailboxPropertiesTypeRef,
} from "../../../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
@ -21,9 +22,12 @@ import {
createMailAddressAlias, createMailAddressAlias,
createUser, createUser,
GroupInfoTypeRef, GroupInfoTypeRef,
GroupMembershipTypeRef,
MailAddressAliasTypeRef,
UserTypeRef, UserTypeRef,
} from "../../../../../src/api/entities/sys/TypeRefs.js" } from "../../../../../src/api/entities/sys/TypeRefs.js"
import { MailAddressFacade } from "../../../../../src/api/worker/facades/lazy/MailAddressFacade.js" import { MailAddressFacade } from "../../../../../src/api/worker/facades/lazy/MailAddressFacade.js"
import { createTestEntity } from "../../../TestUtils.js"
o.spec("MailAddressFacadeTest", function () { o.spec("MailAddressFacadeTest", function () {
let worker: WorkerImpl let worker: WorkerImpl
@ -51,18 +55,18 @@ o.spec("MailAddressFacadeTest", function () {
const mailGroupId = "mailGroupId" const mailGroupId = "mailGroupId"
const viaUser = "viaUser" const viaUser = "viaUser"
const mailboxPropertiesId = "mailboxPropertiesId" const mailboxPropertiesId = "mailboxPropertiesId"
const mailboxGroupRoot = createMailboxGroupRoot({ const mailboxGroupRoot = createTestEntity(MailboxGroupRootTypeRef, {
_ownerGroup: mailGroupId, _ownerGroup: mailGroupId,
mailboxProperties: mailboxPropertiesId, mailboxProperties: mailboxPropertiesId,
}) })
const mailGroupKey = [1, 2, 3] const mailGroupKey = [1, 2, 3]
const mailboxProperties = createMailboxProperties({ const mailboxProperties = createTestEntity(MailboxPropertiesTypeRef, {
mailAddressProperties: [ mailAddressProperties: [
createMailAddressProperties({ createTestEntity(MailAddressPropertiesTypeRef, {
mailAddress: "a@a.com", mailAddress: "a@a.com",
senderName: "a", senderName: "a",
}), }),
createMailAddressProperties({ createTestEntity(MailAddressPropertiesTypeRef, {
mailAddress: "b@b.com", mailAddress: "b@b.com",
senderName: "b", senderName: "b",
}), }),
@ -84,30 +88,30 @@ o.spec("MailAddressFacadeTest", function () {
const mailGroupId = "mailGroupId" const mailGroupId = "mailGroupId"
const viaUser = "viaUser" const viaUser = "viaUser"
const mailboxPropertiesId = "mailboxProeprtiesId" const mailboxPropertiesId = "mailboxProeprtiesId"
const mailboxGroupRoot = createMailboxGroupRoot({ const mailboxGroupRoot = createTestEntity(MailboxGroupRootTypeRef, {
_ownerGroup: mailGroupId, _ownerGroup: mailGroupId,
mailboxProperties: null, mailboxProperties: null,
}) })
const mailGroupKey = [1, 2, 3] const mailGroupKey = [1, 2, 3]
const mailboxProperties = createMailboxProperties({ const mailboxProperties = createTestEntity(MailboxPropertiesTypeRef, {
_id: mailboxPropertiesId, _id: mailboxPropertiesId,
_ownerGroup: mailGroupId, _ownerGroup: mailGroupId,
reportMovedMails: "", reportMovedMails: "",
mailAddressProperties: [], mailAddressProperties: [],
}) })
const userGroupInfoId: IdTuple = ["groupInfoListId", "groupInfoId"] const userGroupInfoId: IdTuple = ["groupInfoListId", "groupInfoId"]
const user = createUser({ const user = createTestEntity(UserTypeRef, {
_id: viaUser, _id: viaUser,
userGroup: createGroupMembership({ userGroup: createTestEntity(GroupMembershipTypeRef, {
groupInfo: userGroupInfoId, groupInfo: userGroupInfoId,
}), }),
}) })
const userGroupInfo = createGroupInfo({ const userGroupInfo = createTestEntity(GroupInfoTypeRef, {
_id: userGroupInfoId, _id: userGroupInfoId,
name: "User name", name: "User name",
mailAddress: "primary@example.com", mailAddress: "primary@example.com",
mailAddressAliases: [ mailAddressAliases: [
createMailAddressAlias({ createTestEntity(MailAddressAliasTypeRef, {
mailAddress: "a@a.com", mailAddress: "a@a.com",
enabled: true, enabled: true,
}), }),

View file

@ -1,6 +1,6 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { MailFacade, phishingMarkerValue, validateMimeTypesForAttachments } from "../../../../../src/api/worker/facades/lazy/MailFacade.js" import { MailFacade, phishingMarkerValue, validateMimeTypesForAttachments } from "../../../../../src/api/worker/facades/lazy/MailFacade.js"
import { createMail, createMailAddress, createReportedMailFieldMarker } from "../../../../../src/api/entities/tutanota/TypeRefs.js" import { MailAddressTypeRef, MailTypeRef, ReportedMailFieldMarkerTypeRef } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
import { MailAuthenticationStatus, ReportedMailFieldType } from "../../../../../src/api/common/TutanotaConstants.js" import { MailAuthenticationStatus, ReportedMailFieldType } from "../../../../../src/api/common/TutanotaConstants.js"
import { object } from "testdouble" import { object } from "testdouble"
import { CryptoFacade } from "../../../../../src/api/worker/crypto/CryptoFacade.js" import { CryptoFacade } from "../../../../../src/api/worker/crypto/CryptoFacade.js"
@ -13,6 +13,7 @@ import { LoginFacade } from "../../../../../src/api/worker/facades/LoginFacade.j
import { DataFile } from "../../../../../src/api/common/DataFile.js" import { DataFile } from "../../../../../src/api/common/DataFile.js"
import { downcast } from "@tutao/tutanota-utils" import { downcast } from "@tutao/tutanota-utils"
import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js" import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js"
import { createTestEntity } from "../../../TestUtils.js"
o.spec("MailFacade test", function () { o.spec("MailFacade test", function () {
let facade: MailFacade let facade: MailFacade
@ -37,10 +38,10 @@ o.spec("MailFacade test", function () {
o.spec("checkMailForPhishing", function () { o.spec("checkMailForPhishing", function () {
o("not phishing if no markers", async function () { o("not phishing if no markers", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
@ -49,19 +50,19 @@ o.spec("MailFacade test", function () {
}) })
o("not phishing if no matching markers", async function () { o("not phishing if no matching markers", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test 2"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test 2"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example2.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example2.com"),
}), }),
]) ])
@ -70,19 +71,19 @@ o.spec("MailFacade test", function () {
}) })
o("not phishing if only from domain matches", async function () { o("not phishing if only from domain matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test 2"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test 2"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
}), }),
]) ])
@ -91,19 +92,19 @@ o.spec("MailFacade test", function () {
}) })
o("not phishing if only subject matches", async function () { o("not phishing if only subject matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example2.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example2.com"),
}), }),
]) ])
@ -112,19 +113,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and sender domain matches", async function () { o("is phishing if subject and sender domain matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
}), }),
]) ])
@ -133,19 +134,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject with whitespaces and sender domain matches", async function () { o("is phishing if subject with whitespaces and sender domain matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "\tTest spaces \n", subject: "\tTest spaces \n",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Testspaces"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Testspaces"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
}), }),
]) ])
@ -154,19 +155,19 @@ o.spec("MailFacade test", function () {
}) })
o("is not phishing if subject and sender domain matches but not authenticated", async function () { o("is not phishing if subject and sender domain matches but not authenticated", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.SOFT_FAIL, authStatus: MailAuthenticationStatus.SOFT_FAIL,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN, "example.com"),
}), }),
]) ])
@ -175,19 +176,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and sender address matches", async function () { o("is phishing if subject and sender address matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS, "test@example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS, "test@example.com"),
}), }),
]) ])
@ -196,19 +197,19 @@ o.spec("MailFacade test", function () {
}) })
o("is not phishing if subject and sender address matches but not authenticated", async function () { o("is not phishing if subject and sender address matches but not authenticated", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.SOFT_FAIL, authStatus: MailAuthenticationStatus.SOFT_FAIL,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS, "test@example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS, "test@example.com"),
}), }),
]) ])
@ -217,19 +218,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and non auth sender domain matches", async function () { o("is phishing if subject and non auth sender domain matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.SOFT_FAIL, authStatus: MailAuthenticationStatus.SOFT_FAIL,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN_NON_AUTH, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_DOMAIN_NON_AUTH, "example.com"),
}), }),
]) ])
@ -238,19 +239,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and non auth sender address matches", async function () { o("is phishing if subject and non auth sender address matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.SOFT_FAIL, authStatus: MailAuthenticationStatus.SOFT_FAIL,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS_NON_AUTH, "test@example.com"), marker: phishingMarkerValue(ReportedMailFieldType.FROM_ADDRESS_NON_AUTH, "test@example.com"),
}), }),
]) ])
@ -259,19 +260,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and link matches", async function () { o("is phishing if subject and link matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example.com"), marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example.com"),
}), }),
]) ])
@ -280,19 +281,19 @@ o.spec("MailFacade test", function () {
}) })
o("is not phishing if just two links match", async function () { o("is not phishing if just two links match", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example.com"), marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example.com"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example2.com"), marker: phishingMarkerValue(ReportedMailFieldType.LINK, "https://example2.com"),
}), }),
]) ])
@ -306,19 +307,19 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and link domain matches", async function () { o("is phishing if subject and link domain matches", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.LINK_DOMAIN, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.LINK_DOMAIN, "example.com"),
}), }),
]) ])
@ -327,19 +328,19 @@ o.spec("MailFacade test", function () {
}) })
o("does not throw on invalid link", async function () { o("does not throw on invalid link", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.LINK_DOMAIN, "example.com"), marker: phishingMarkerValue(ReportedMailFieldType.LINK_DOMAIN, "example.com"),
}), }),
]) ])
@ -354,16 +355,16 @@ o.spec("MailFacade test", function () {
}) })
o("is phishing if subject and suspicious link", async function () { o("is phishing if subject and suspicious link", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
]) ])
@ -372,16 +373,16 @@ o.spec("MailFacade test", function () {
}) })
o("link is not suspicious if on the same domain", async function () { o("link is not suspicious if on the same domain", async function () {
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
subject: "Test", subject: "Test",
authStatus: MailAuthenticationStatus.AUTHENTICATED, authStatus: MailAuthenticationStatus.AUTHENTICATED,
sender: createMailAddress({ sender: createTestEntity(MailAddressTypeRef, {
name: "a", name: "a",
address: "test@example.com", address: "test@example.com",
}), }),
}) })
facade.phishingMarkersUpdateReceived([ facade.phishingMarkersUpdateReceived([
createReportedMailFieldMarker({ createTestEntity(ReportedMailFieldMarkerTypeRef, {
marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"), marker: phishingMarkerValue(ReportedMailFieldType.SUBJECT, "Test"),
}), }),
]) ])

View file

@ -150,7 +150,7 @@ o.spec("OfflineStorage", function () {
o.spec("ElementType", function () { o.spec("ElementType", function () {
o("deleteAllOfType", async function () { o("deleteAllOfType", async function () {
const userId = "id1" const userId = "id1"
const storableUser = createUser({ _id: userId }) const storableUser = createTestEntity(UserTypeRef, { _id: userId })
await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false }) await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false })
@ -173,7 +173,7 @@ o.spec("OfflineStorage", function () {
o("deleteAllOfType", async function () { o("deleteAllOfType", async function () {
const listId = "listId1" const listId = "listId1"
const elementId = "id1" const elementId = "id1"
const storableMail = createMail({ _id: [listId, elementId] }) const storableMail = createTestEntity(MailTypeRef, { _id: [listId, elementId] })
await storage.init({ userId: elementId, databaseKey, timeRangeDays, forceNewDatabase: false }) await storage.init({ userId: elementId, databaseKey, timeRangeDays, forceNewDatabase: false })
@ -200,7 +200,10 @@ o.spec("OfflineStorage", function () {
o("put, get and delete", async function () { o("put, get and delete", async function () {
const archiveId = "archiveId" const archiveId = "archiveId"
const blobElementId = "id1" const blobElementId = "id1"
const storableMailDetails = createMailDetailsBlob({ _id: [archiveId, blobElementId], details: createTestEntity(MailDetailsTypeRef) }) const storableMailDetails = createTestEntity(MailDetailsBlobTypeRef, {
_id: [archiveId, blobElementId],
details: createTestEntity(MailDetailsTypeRef),
})
await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false }) await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false })
@ -223,7 +226,7 @@ o.spec("OfflineStorage", function () {
const archiveId = "archiveId" const archiveId = "archiveId"
const blobElementId = "id1" const blobElementId = "id1"
const _ownerGroup = "ownerGroup" const _ownerGroup = "ownerGroup"
const storableMailDetails = createMailDetailsBlob({ const storableMailDetails = createTestEntity(MailDetailsBlobTypeRef, {
_id: [archiveId, blobElementId], _id: [archiveId, blobElementId],
_ownerGroup, _ownerGroup,
details: createTestEntity(MailDetailsTypeRef), details: createTestEntity(MailDetailsTypeRef),
@ -254,17 +257,21 @@ o.spec("OfflineStorage", function () {
o.beforeEach(async function () { o.beforeEach(async function () {
await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false }) await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false })
await insertEntity(createMailFolder({ _id: ["mailFolderList", spamFolderId], mails: spamListId, folderType: MailFolderType.SPAM })) await insertEntity(
await insertEntity(createMailFolder({ _id: ["mailFolderList", trashFolderId], mails: trashListId, folderType: MailFolderType.TRASH })) createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", spamFolderId], mails: spamListId, folderType: MailFolderType.SPAM }),
)
await insertEntity(
createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", trashFolderId], mails: trashListId, folderType: MailFolderType.TRASH }),
)
}) })
o("old ranges will be deleted", async function () { o("old ranges will be deleted", async function () {
const upper = offsetId(-1) const upper = offsetId(-1)
const lower = offsetId(-2) const lower = offsetId(-2)
const mailDetailsBlobId: IdTuple = ["mailDetailsList", "mailDetailsBlobId"] const mailDetailsBlobId: IdTuple = ["mailDetailsList", "mailDetailsBlobId"]
await insertEntity(createMailFolder({ _id: ["mailFolderList", "mailFolderId"], mails: listId })) await insertEntity(createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", "mailFolderId"], mails: listId }))
await insertEntity(createMailDetailsBlob({ _id: mailDetailsBlobId, details: createTestEntity(MailDetailsTypeRef) })) await insertEntity(createTestEntity(MailDetailsBlobTypeRef, { _id: mailDetailsBlobId, details: createTestEntity(MailDetailsTypeRef) }))
await insertEntity(createMail({ _id: [listId, "anything"], mailDetails: mailDetailsBlobId })) await insertEntity(createTestEntity(MailTypeRef, { _id: [listId, "anything"], mailDetails: mailDetailsBlobId }))
await insertRange(MailTypeRef, listId, lower, upper) await insertRange(MailTypeRef, listId, lower, upper)
// Here we clear the excluded data // Here we clear the excluded data
@ -281,7 +288,7 @@ o.spec("OfflineStorage", function () {
o("modified ranges will be shrunk", async function () { o("modified ranges will be shrunk", async function () {
const upper = offsetId(2) const upper = offsetId(2)
const lower = offsetId(-2) const lower = offsetId(-2)
await insertEntity(createMailFolder({ _id: ["mailFolderListId", "mailFolderId"], mails: listId })) await insertEntity(createTestEntity(MailFolderTypeRef, { _id: ["mailFolderListId", "mailFolderId"], mails: listId }))
await insertRange(MailTypeRef, listId, lower, upper) await insertRange(MailTypeRef, listId, lower, upper)
// Here we clear the excluded data // Here we clear the excluded data
@ -295,7 +302,7 @@ o.spec("OfflineStorage", function () {
const upper = offsetId(2) const upper = offsetId(2)
const lower = offsetId(1) const lower = offsetId(1)
await insertEntity(createMailFolder({ _id: ["mailFolderList", "mailFolderId"], mails: listId })) await insertEntity(createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", "mailFolderId"], mails: listId }))
await insertRange(MailTypeRef, listId, lower, upper) await insertRange(MailTypeRef, listId, lower, upper)
// Here we clear the excluded data // Here we clear the excluded data
@ -308,8 +315,8 @@ o.spec("OfflineStorage", function () {
o("complete ranges won't be lost if entities are all newer than cutoff", async function () { o("complete ranges won't be lost if entities are all newer than cutoff", async function () {
const upper = offsetId(2) const upper = offsetId(2)
const lower = GENERATED_MIN_ID const lower = GENERATED_MIN_ID
const mail = createMail({ _id: [listId, offsetId(1)] }) const mail = createTestEntity(MailTypeRef, { _id: [listId, offsetId(1)] })
const mailFolder = createMailFolder({ _id: ["mailFolderList", "folderId"], mails: listId }) const mailFolder = createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", "folderId"], mails: listId })
await insertEntity(mailFolder) await insertEntity(mailFolder)
await insertEntity(mail) await insertEntity(mail)
await insertRange(MailTypeRef, listId, lower, upper) await insertRange(MailTypeRef, listId, lower, upper)
@ -331,14 +338,14 @@ o.spec("OfflineStorage", function () {
const trashMailBodyId = "trashMailBodyId" const trashMailBodyId = "trashMailBodyId"
const spamMailId = offsetId(2) const spamMailId = offsetId(2)
const spamMail = createMail({ _id: [spamListId, spamMailId], body: spamMailBodyId }) const spamMail = createTestEntity(MailTypeRef, { _id: [spamListId, spamMailId], body: spamMailBodyId })
const trashMailId = offsetId(2) const trashMailId = offsetId(2)
const trashMail = createMail({ _id: [trashListId, trashMailId], body: trashMailBodyId }) const trashMail = createTestEntity(MailTypeRef, { _id: [trashListId, trashMailId], body: trashMailBodyId })
await insertEntity(spamMail) await insertEntity(spamMail)
await insertEntity(trashMail) await insertEntity(trashMail)
await insertEntity(createMailBody({ _id: spamMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: spamMailBodyId }))
await insertEntity(createMailBody({ _id: trashMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: trashMailBodyId }))
// Here we clear the excluded data // Here we clear the excluded data
await storage.clearExcludedData(timeRangeDays, userId) await storage.clearExcludedData(timeRangeDays, userId)
@ -359,14 +366,14 @@ o.spec("OfflineStorage", function () {
const trashSubfolderMailBodyId = "trashSubfolderMailBodyId" const trashSubfolderMailBodyId = "trashSubfolderMailBodyId"
const spamMailId = offsetId(2) const spamMailId = offsetId(2)
const spamMail = createMail({ _id: [spamListId, spamMailId], body: spamMailBodyId }) const spamMail = createTestEntity(MailTypeRef, { _id: [spamListId, spamMailId], body: spamMailBodyId })
const trashMailId = offsetId(2) const trashMailId = offsetId(2)
const trashMail = createMail({ _id: [trashListId, trashMailId], body: trashMailBodyId }) const trashMail = createTestEntity(MailTypeRef, { _id: [trashListId, trashMailId], body: trashMailBodyId })
const trashSubfolderMailId = offsetId(2) const trashSubfolderMailId = offsetId(2)
const trashSubfolderMail = createMail({ _id: [trashSubfolderListId, trashSubfolderMailId], body: trashSubfolderMailBodyId }) const trashSubfolderMail = createTestEntity(MailTypeRef, { _id: [trashSubfolderListId, trashSubfolderMailId], body: trashSubfolderMailBodyId })
await insertEntity( await insertEntity(
createMailFolder({ createTestEntity(MailFolderTypeRef, {
_id: ["mailFolderList", trashSubfolderId], _id: ["mailFolderList", trashSubfolderId],
parentFolder: ["mailFolderList", trashFolderId], parentFolder: ["mailFolderList", trashFolderId],
mails: trashSubfolderListId, mails: trashSubfolderListId,
@ -376,9 +383,9 @@ o.spec("OfflineStorage", function () {
await insertEntity(spamMail) await insertEntity(spamMail)
await insertEntity(trashMail) await insertEntity(trashMail)
await insertEntity(trashSubfolderMail) await insertEntity(trashSubfolderMail)
await insertEntity(createMailBody({ _id: spamMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: spamMailBodyId }))
await insertEntity(createMailBody({ _id: trashMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: trashMailBodyId }))
await insertEntity(createMailBody({ _id: trashSubfolderMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: trashSubfolderMailBodyId }))
// Here we clear the excluded data // Here we clear the excluded data
await storage.clearExcludedData(timeRangeDays, userId) await storage.clearExcludedData(timeRangeDays, userId)
@ -397,15 +404,15 @@ o.spec("OfflineStorage", function () {
const spamMailId = offsetId(2) const spamMailId = offsetId(2)
const trashMailId = offsetId(2) const trashMailId = offsetId(2)
const spamMail = createMail({ _id: [spamListId, spamMailId], mailDetails: spamDetailsId }) const spamMail = createTestEntity(MailTypeRef, { _id: [spamListId, spamMailId], mailDetails: spamDetailsId })
const trashMail = createMail({ _id: [trashListId, trashMailId], mailDetails: trashDetailsId }) const trashMail = createTestEntity(MailTypeRef, { _id: [trashListId, trashMailId], mailDetails: trashDetailsId })
await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false }) await storage.init({ userId, databaseKey, timeRangeDays, forceNewDatabase: false })
await insertEntity(spamMail) await insertEntity(spamMail)
await insertEntity(trashMail) await insertEntity(trashMail)
await insertEntity(createMailDetailsBlob({ _id: spamDetailsId, details: createTestEntity(MailDetailsTypeRef) })) await insertEntity(createTestEntity(MailDetailsBlobTypeRef, { _id: spamDetailsId, details: createTestEntity(MailDetailsTypeRef) }))
await insertEntity(createMailDetailsBlob({ _id: trashDetailsId, details: createTestEntity(MailDetailsTypeRef) })) await insertEntity(createTestEntity(MailDetailsBlobTypeRef, { _id: trashDetailsId, details: createTestEntity(MailDetailsTypeRef) }))
// Here we clear the excluded data // Here we clear the excluded data
await storage.clearExcludedData(timeRangeDays, userId) await storage.clearExcludedData(timeRangeDays, userId)
@ -423,14 +430,16 @@ o.spec("OfflineStorage", function () {
const beforeMailBodyId = "beforeMailBodyId" const beforeMailBodyId = "beforeMailBodyId"
const afterMailBodyId = "afterMailBodyId" const afterMailBodyId = "afterMailBodyId"
const mailBefore = createMail({ _id: [inboxMailList, offsetId(-2)], body: beforeMailBodyId }) const mailBefore = createTestEntity(MailTypeRef, { _id: [inboxMailList, offsetId(-2)], body: beforeMailBodyId })
const mailAfter = createMail({ _id: [inboxMailList, offsetId(2)], body: afterMailBodyId }) const mailAfter = createTestEntity(MailTypeRef, { _id: [inboxMailList, offsetId(2)], body: afterMailBodyId })
await insertEntity(createMailFolder({ _id: ["mailFolderList", "folderId"], mails: inboxMailList, folderType: MailFolderType.INBOX })) await insertEntity(
createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", "folderId"], mails: inboxMailList, folderType: MailFolderType.INBOX }),
)
await insertEntity(mailBefore) await insertEntity(mailBefore)
await insertEntity(mailAfter) await insertEntity(mailAfter)
await insertEntity(createMailBody({ _id: beforeMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: beforeMailBodyId }))
await insertEntity(createMailBody({ _id: afterMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: afterMailBodyId }))
// Here we clear the excluded data // Here we clear the excluded data
await storage.clearExcludedData(timeRangeDays, userId) await storage.clearExcludedData(timeRangeDays, userId)
@ -446,14 +455,16 @@ o.spec("OfflineStorage", function () {
const mailBodyId1 = "mailBodyId1" const mailBodyId1 = "mailBodyId1"
const mailBodyId2 = "afterMailBodyId" const mailBodyId2 = "afterMailBodyId"
const mail1 = createMail({ _id: [inboxMailList, offsetId(-2)], body: mailBodyId1 }) const mail1 = createTestEntity(MailTypeRef, { _id: [inboxMailList, offsetId(-2)], body: mailBodyId1 })
const mail2 = createMail({ _id: [inboxMailList, offsetId(-3)], body: mailBodyId2 }) const mail2 = createTestEntity(MailTypeRef, { _id: [inboxMailList, offsetId(-3)], body: mailBodyId2 })
await insertEntity(createMailFolder({ _id: ["mailFolderList", "folderId"], mails: inboxMailList, folderType: MailFolderType.INBOX })) await insertEntity(
createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", "folderId"], mails: inboxMailList, folderType: MailFolderType.INBOX }),
)
await insertEntity(mail1) await insertEntity(mail1)
await insertEntity(mail2) await insertEntity(mail2)
await insertEntity(createMailBody({ _id: mailBodyId1 })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: mailBodyId1 }))
await insertEntity(createMailBody({ _id: mailBodyId2 })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: mailBodyId2 }))
// Here we clear the excluded data // Here we clear the excluded data
await storage.clearExcludedData(timeRangeDays, userId) await storage.clearExcludedData(timeRangeDays, userId)
@ -468,18 +479,20 @@ o.spec("OfflineStorage", function () {
const afterMailBodyId = "afterMailBodyId" const afterMailBodyId = "afterMailBodyId"
const fileListId = "fileListId" const fileListId = "fileListId"
const fileBefore = createFile({ _id: [fileListId, "fileBefore"] }) const fileBefore = createTestEntity(FileTypeRef, { _id: [fileListId, "fileBefore"] })
const fileAfter = createFile({ _id: [fileListId, "fileAfter"] }) const fileAfter = createTestEntity(FileTypeRef, { _id: [fileListId, "fileAfter"] })
const mailBefore = createMail({ _id: [inboxMailList, offsetId(-2)], body: beforeMailBodyId, attachments: [fileBefore._id] }) const mailBefore = createTestEntity(MailTypeRef, { _id: [inboxMailList, offsetId(-2)], body: beforeMailBodyId, attachments: [fileBefore._id] })
const mailAfter = createMail({ _id: [inboxMailList, offsetId(2)], body: afterMailBodyId, attachments: [fileAfter._id] }) const mailAfter = createTestEntity(MailTypeRef, { _id: [inboxMailList, offsetId(2)], body: afterMailBodyId, attachments: [fileAfter._id] })
await insertEntity(createMailFolder({ _id: ["mailFolderList", "folderId"], mails: inboxMailList, folderType: MailFolderType.INBOX })) await insertEntity(
createTestEntity(MailFolderTypeRef, { _id: ["mailFolderList", "folderId"], mails: inboxMailList, folderType: MailFolderType.INBOX }),
)
await insertEntity(mailBefore) await insertEntity(mailBefore)
await insertEntity(mailAfter) await insertEntity(mailAfter)
await insertEntity(fileBefore) await insertEntity(fileBefore)
await insertEntity(fileAfter) await insertEntity(fileAfter)
await insertEntity(createMailBody({ _id: beforeMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: beforeMailBodyId }))
await insertEntity(createMailBody({ _id: afterMailBodyId })) await insertEntity(createTestEntity(MailBodyTypeRef, { _id: afterMailBodyId }))
// Here we clear the excluded data // Here we clear the excluded data
await storage.clearExcludedData(timeRangeDays, userId) await storage.clearExcludedData(timeRangeDays, userId)
@ -498,14 +511,14 @@ o.spec("OfflineStorage", function () {
const mailId = idGenerator.getNext() const mailId = idGenerator.getNext()
const bodyId = idGenerator.getNext() const bodyId = idGenerator.getNext()
mails.push( mails.push(
createMail({ createTestEntity(MailTypeRef, {
_id: [listId, mailId], _id: [listId, mailId],
subject: getSubject(i), subject: getSubject(i),
body: bodyId, body: bodyId,
}), }),
) )
mailBodies.push( mailBodies.push(
createMailBody({ createTestEntity(MailBodyTypeRef, {
_id: bodyId, _id: bodyId,
text: getBody(i), text: getBody(i),
}), }),
@ -520,7 +533,7 @@ o.spec("OfflineStorage", function () {
const newIds = new IdGenerator(offsetId(5)) const newIds = new IdGenerator(offsetId(5))
const inboxListId = oldIds.getNext() const inboxListId = oldIds.getNext()
const inboxFolder = createMailFolder({ const inboxFolder = createTestEntity(MailFolderTypeRef, {
_id: [userId, oldIds.getNext()], _id: [userId, oldIds.getNext()],
mails: inboxListId, mails: inboxListId,
folderType: MailFolderType.INBOX, folderType: MailFolderType.INBOX,
@ -542,7 +555,7 @@ o.spec("OfflineStorage", function () {
) )
const trashListId = oldIds.getNext() const trashListId = oldIds.getNext()
const trashFolder = createMailFolder({ const trashFolder = createTestEntity(MailFolderTypeRef, {
_id: [userId, oldIds.getNext()], _id: [userId, oldIds.getNext()],
mails: trashListId, mails: trashListId,
folderType: MailFolderType.TRASH, folderType: MailFolderType.TRASH,
@ -556,7 +569,7 @@ o.spec("OfflineStorage", function () {
) )
const spamListId = oldIds.getNext() const spamListId = oldIds.getNext()
const spamFolder = createMailFolder({ const spamFolder = createTestEntity(MailFolderTypeRef, {
_id: [userId, oldIds.getNext()], _id: [userId, oldIds.getNext()],
mails: spamListId, mails: spamListId,
folderType: MailFolderType.SPAM, folderType: MailFolderType.SPAM,

View file

@ -7,6 +7,7 @@ import { EntityRestClient } from "../../../../../src/api/worker/rest/EntityRestC
import { LateInitializedCacheStorageImpl } from "../../../../../src/api/worker/rest/CacheStorageProxy.js" import { LateInitializedCacheStorageImpl } from "../../../../../src/api/worker/rest/CacheStorageProxy.js"
import { CUSTOM_MAX_ID, CUSTOM_MIN_ID, LOAD_MULTIPLE_LIMIT } from "../../../../../src/api/common/utils/EntityUtils.js" import { CUSTOM_MAX_ID, CUSTOM_MIN_ID, LOAD_MULTIPLE_LIMIT } from "../../../../../src/api/common/utils/EntityUtils.js"
import { numberRange } from "@tutao/tutanota-utils" import { numberRange } from "@tutao/tutanota-utils"
import { createTestEntity } from "../../../TestUtils.js"
o.spec("Custom calendar events handler", function () { o.spec("Custom calendar events handler", function () {
const entityRestClientMock = instance(EntityRestClient) const entityRestClientMock = instance(EntityRestClient)
@ -15,11 +16,11 @@ o.spec("Custom calendar events handler", function () {
const listId = "listId" const listId = "listId"
let timestamp = Date.now() let timestamp = Date.now()
const ids = [0, 1, 2, 3, 4, 5, 6].map((n) => createEventElementId(timestamp, n)) const ids = [0, 1, 2, 3, 4, 5, 6].map((n) => createEventElementId(timestamp, n))
const allList = [0, 1, 2, 3, 4, 5, 6].map((n) => createCalendarEvent({ _id: [listId, ids[n]] })) const allList = [0, 1, 2, 3, 4, 5, 6].map((n) => createTestEntity(CalendarEventTypeRef, { _id: [listId, ids[n]] }))
const bigListId = "bigListId" const bigListId = "bigListId"
const bigListIds = numberRange(0, 299).map((n) => createEventElementId(timestamp, n)) const bigListIds = numberRange(0, 299).map((n) => createEventElementId(timestamp, n))
const bigList = numberRange(0, 299).map((n) => createCalendarEvent({ _id: [bigListId, bigListIds[n]] })) const bigList = numberRange(0, 299).map((n) => createTestEntity(CalendarEventTypeRef, { _id: [bigListId, bigListIds[n]] }))
const toElementId = (e) => e._id[1] const toElementId = (e) => e._id[1]
o.spec("Load elements from cache", function () { o.spec("Load elements from cache", function () {

View file

@ -15,6 +15,7 @@ import {
} from "../../../../../src/api/common/utils/EntityUtils.js" } from "../../../../../src/api/common/utils/EntityUtils.js"
import { arrayOf, clone, downcast, isSameTypeRef, neverNull, TypeRef } from "@tutao/tutanota-utils" import { arrayOf, clone, downcast, isSameTypeRef, neverNull, TypeRef } from "@tutao/tutanota-utils"
import { import {
BucketKeyTypeRef,
createBucketKey, createBucketKey,
createCustomer, createCustomer,
createEntityUpdate, createEntityUpdate,
@ -28,6 +29,9 @@ import {
EntityUpdate, EntityUpdate,
EntityUpdateTypeRef, EntityUpdateTypeRef,
ExternalUserReferenceTypeRef, ExternalUserReferenceTypeRef,
GroupMembershipTypeRef,
GroupRootTypeRef,
InstanceSessionKeyTypeRef,
PermissionTypeRef, PermissionTypeRef,
UserTypeRef, UserTypeRef,
} from "../../../../../src/api/entities/sys/TypeRefs.js" } from "../../../../../src/api/entities/sys/TypeRefs.js"
@ -187,8 +191,8 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
const calendarEventIds = [0, 1, 2, 3, 4, 5, 6].map((n) => createEventElementId(timestamp, n)) const calendarEventIds = [0, 1, 2, 3, 4, 5, 6].map((n) => createEventElementId(timestamp, n))
o("writes batch meta on entity update", async function () { o("writes batch meta on entity update", async function () {
const contact1 = createContact({ _id: [contactListId1, id1] }) const contact1 = createTestEntity(ContactTypeRef, { _id: [contactListId1, id1] })
const contact2 = createContact({ _id: [contactListId1, id2] }) const contact2 = createTestEntity(ContactTypeRef, { _id: [contactListId1, id2] })
const batch = [ const batch = [
createUpdate(ContactTypeRef, contactListId1, id1, OperationType.CREATE), createUpdate(ContactTypeRef, contactListId1, id1, OperationType.CREATE),
@ -215,8 +219,8 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
//when using offline calendar ids are always in cache range //when using offline calendar ids are always in cache range
}) })
o("entity events received should call loadMultiple when receiving updates from a postMultiple", async function () { o("entity events received should call loadMultiple when receiving updates from a postMultiple", async function () {
const contact1 = createContact({ _id: [contactListId1, id1] }) const contact1 = createTestEntity(ContactTypeRef, { _id: [contactListId1, id1] })
const contact2 = createContact({ _id: [contactListId1, id2] }) const contact2 = createTestEntity(ContactTypeRef, { _id: [contactListId1, id2] })
const batch = [ const batch = [
createUpdate(ContactTypeRef, contactListId1, id1, OperationType.CREATE), createUpdate(ContactTypeRef, contactListId1, id1, OperationType.CREATE),
@ -240,8 +244,8 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (name === "offline") { if (name === "offline") {
// in the other case storage is an EphemeralCache which doesn't use custom handlers or caches calendar events. // in the other case storage is an EphemeralCache which doesn't use custom handlers or caches calendar events.
o("entity events received should call loadMultiple when receiving updates from a postMultiple with CustomCacheHandler", async function () { o("entity events received should call loadMultiple when receiving updates from a postMultiple with CustomCacheHandler", async function () {
const event1 = createCalendarEvent({ _id: [calendarEventListId, calendarEventIds[0]] }) const event1 = createTestEntity(CalendarEventTypeRef, { _id: [calendarEventListId, calendarEventIds[0]] })
const event2 = createCalendarEvent({ _id: [calendarEventListId, calendarEventIds[1]] }) const event2 = createTestEntity(CalendarEventTypeRef, { _id: [calendarEventListId, calendarEventIds[1]] })
// We only consider events to be in the range if we do actually have correct range // We only consider events to be in the range if we do actually have correct range
await storage.setNewRangeForList(CalendarEventTypeRef, calendarEventListId, CUSTOM_MIN_ID, CUSTOM_MAX_ID) await storage.setNewRangeForList(CalendarEventTypeRef, calendarEventListId, CUSTOM_MIN_ID, CUSTOM_MAX_ID)
@ -282,14 +286,14 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (isSameTypeRef(typeRef, ContactTypeRef)) { if (isSameTypeRef(typeRef, ContactTypeRef)) {
o(elementId).equals(id2) o(elementId).equals(id2)
return Promise.resolve( return Promise.resolve(
createContact({ createTestEntity(ContactTypeRef, {
_id: [neverNull(listId), elementId], _id: [neverNull(listId), elementId],
}), }),
) )
} else if (isSameTypeRef(typeRef, CustomerTypeRef)) { } else if (isSameTypeRef(typeRef, CustomerTypeRef)) {
o(["id5", "id6", "id7"].includes(elementId)).equals(true) o(["id5", "id6", "id7"].includes(elementId)).equals(true)
return Promise.resolve( return Promise.resolve(
createCustomer({ createTestEntity(CustomerTypeRef, {
_id: elementId, _id: elementId,
}), }),
) )
@ -301,30 +305,30 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (listId === contactListId1) { if (listId === contactListId1) {
o(ids).deepEquals(["id1", "id2"]) o(ids).deepEquals(["id1", "id2"])
return Promise.resolve([ return Promise.resolve([
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, id1], _id: [listId, id1],
}), }),
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, id2], _id: [listId, id2],
}), }),
]) ])
} else if (listId === calendarEventListId) { } else if (listId === calendarEventListId) {
o(ids).deepEquals([calendarEventIds[0], calendarEventIds[1]]) o(ids).deepEquals([calendarEventIds[0], calendarEventIds[1]])
return Promise.resolve([ return Promise.resolve([
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: [calendarEventListId, calendarEventIds[0]], _id: [calendarEventListId, calendarEventIds[0]],
}), }),
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: [calendarEventListId, calendarEventIds[1]], _id: [calendarEventListId, calendarEventIds[1]],
}), }),
]) ])
} else if (listId === contactListId2) { } else if (listId === contactListId2) {
o(ids).deepEquals(["id3", "id4"]) o(ids).deepEquals(["id3", "id4"])
return Promise.resolve([ return Promise.resolve([
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, "id3"], _id: [listId, "id3"],
}), }),
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, "id4"], _id: [listId, "id4"],
}), }),
]) ])
@ -384,10 +388,10 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (listId === contactListId1) { if (listId === contactListId1) {
o(ids).deepEquals(["id1", "id2"]) o(ids).deepEquals(["id1", "id2"])
return Promise.resolve([ return Promise.resolve([
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, id1], _id: [listId, id1],
}), }),
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, id2], _id: [listId, id2],
}), }),
]) ])
@ -432,7 +436,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (isSameTypeRef(typeRef, ContactTypeRef)) { if (isSameTypeRef(typeRef, ContactTypeRef)) {
if (listId === contactListId1) { if (listId === contactListId1) {
o(ids).deepEquals(["id1", "id2"]) o(ids).deepEquals(["id1", "id2"])
return Promise.resolve([createContact({ _id: [listId, id1] })]) return Promise.resolve([createTestEntity(ContactTypeRef, { _id: [listId, id1] })])
} }
} }
throw new Error("should not be reached") throw new Error("should not be reached")
@ -465,14 +469,14 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (listId === contactListId1) { if (listId === contactListId1) {
o(ids).deepEquals(["id1"]) o(ids).deepEquals(["id1"])
return Promise.resolve([ return Promise.resolve([
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, id1], _id: [listId, id1],
}), }),
]) ])
} else if (listId === contactListId2) { } else if (listId === contactListId2) {
o(ids).deepEquals(["id4"]) o(ids).deepEquals(["id4"])
return Promise.resolve([ return Promise.resolve([
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, "id4"], _id: [listId, "id4"],
}), }),
]) ])
@ -508,7 +512,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
if (listId === contactListId1) { if (listId === contactListId1) {
o(ids).deepEquals(["id1"]) o(ids).deepEquals(["id1"])
return Promise.resolve([ return Promise.resolve([
createContact({ createTestEntity(ContactTypeRef, {
_id: [listId, id1], _id: [listId, id1],
}), }),
]) ])
@ -620,9 +624,9 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
}) })
o("Mail should not be loaded when a move event is received - update bucket key", async function () { o("Mail should not be loaded when a move event is received - update bucket key", async function () {
const instance = createMailInstance("listId1", "id1", "henlo") const instance = createMailInstance("listId1", "id1", "henlo")
instance.bucketKey = createBucketKey({ instance.bucketKey = createTestEntity(BucketKeyTypeRef, {
bucketEncSessionKeys: [ bucketEncSessionKeys: [
createInstanceSessionKey({ createTestEntity(InstanceSessionKeyTypeRef, {
instanceList: "listId1", instanceList: "listId1",
instanceId: getElementId(instance), instanceId: getElementId(instance),
}), }),
@ -723,7 +727,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
}) })
o("delete Mail deletes MailDetailsBlob", async function () { o("delete Mail deletes MailDetailsBlob", async function () {
const mailDetailsBlob = createMailDetailsBlob({ _id: ["archiveId", "blobId"] }) const mailDetailsBlob = createTestEntity(MailDetailsBlobTypeRef, { _id: ["archiveId", "blobId"] })
const mail = createMailInstance("listId1", "id1", "mail 1") const mail = createMailInstance("listId1", "id1", "mail 1")
mail.mailDetails = mailDetailsBlob._id mail.mailDetails = mailDetailsBlob._id
@ -780,14 +784,14 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("no membership change does not delete an entity and lastUpdateBatchIdPerGroup", async function () { o("no membership change does not delete an entity and lastUpdateBatchIdPerGroup", async function () {
const userId = "userId" const userId = "userId"
const calendarGroupId = "calendarGroupId" const calendarGroupId = "calendarGroupId"
const initialUser = createUser({ const initialUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "calendarShipId", _id: "calendarShipId",
group: calendarGroupId, group: calendarGroupId,
groupType: GroupType.Calendar, groupType: GroupType.Calendar,
@ -801,7 +805,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
await storage.put(initialUser) await storage.put(initialUser)
const eventId: IdTuple = ["eventListId", "eventId"] const eventId: IdTuple = ["eventListId", "eventId"]
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
_id: eventId, _id: eventId,
_ownerGroup: calendarGroupId, _ownerGroup: calendarGroupId,
}) })
@ -819,14 +823,14 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("membership change deletes an element entity and lastUpdateBatchIdPerGroup", async function () { o("membership change deletes an element entity and lastUpdateBatchIdPerGroup", async function () {
const userId = "userId" const userId = "userId"
const calendarGroupId = "calendarGroupId" const calendarGroupId = "calendarGroupId"
const initialUser = createUser({ const initialUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "calendarShipId", _id: "calendarShipId",
group: calendarGroupId, group: calendarGroupId,
groupType: GroupType.Calendar, groupType: GroupType.Calendar,
@ -836,10 +840,10 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
await storage.put(initialUser) await storage.put(initialUser)
const updatedUser = createUser({ const updatedUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
@ -850,7 +854,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
when(entityRestClient.load(UserTypeRef, userId)).thenResolve(updatedUser) when(entityRestClient.load(UserTypeRef, userId)).thenResolve(updatedUser)
const groupRootId = "groupRootId" const groupRootId = "groupRootId"
const groupRoot = createGroupRoot({ const groupRoot = createTestEntity(GroupRootTypeRef, {
_id: groupRootId, _id: groupRootId,
_ownerGroup: calendarGroupId, _ownerGroup: calendarGroupId,
}) })
@ -868,14 +872,14 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("membership change deletes a list entity and lastUpdateBatchIdPerGroup", async function () { o("membership change deletes a list entity and lastUpdateBatchIdPerGroup", async function () {
const userId = "userId" const userId = "userId"
const calendarGroupId = "calendarGroupId" const calendarGroupId = "calendarGroupId"
const initialUser = createUser({ const initialUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "calendarShipId", _id: "calendarShipId",
group: calendarGroupId, group: calendarGroupId,
groupType: GroupType.Calendar, groupType: GroupType.Calendar,
@ -885,10 +889,10 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
await storage.put(initialUser) await storage.put(initialUser)
const updatedUser = createUser({ const updatedUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
@ -899,7 +903,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
when(entityRestClient.load(UserTypeRef, userId)).thenResolve(updatedUser) when(entityRestClient.load(UserTypeRef, userId)).thenResolve(updatedUser)
const eventId: IdTuple = ["eventListId", "eventId"] const eventId: IdTuple = ["eventListId", "eventId"]
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
_id: eventId, _id: eventId,
_ownerGroup: calendarGroupId, _ownerGroup: calendarGroupId,
}) })
@ -919,14 +923,14 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("membership change but for another user does nothing", async function () { o("membership change but for another user does nothing", async function () {
const userId = "userId" const userId = "userId"
const calendarGroupId = "calendarGroupId" const calendarGroupId = "calendarGroupId"
const initialUser = createUser({ const initialUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "calendarShipId", _id: "calendarShipId",
group: calendarGroupId, group: calendarGroupId,
groupType: GroupType.Calendar, groupType: GroupType.Calendar,
@ -936,10 +940,10 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
await storage.put(initialUser) await storage.put(initialUser)
const updatedUser = createUser({ const updatedUser = createTestEntity(UserTypeRef, {
_id: userId, _id: userId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: "mailShipId", _id: "mailShipId",
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
@ -950,7 +954,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
when(entityRestClient.load(UserTypeRef, userId)).thenResolve(updatedUser) when(entityRestClient.load(UserTypeRef, userId)).thenResolve(updatedUser)
const eventId: IdTuple = ["eventListId", "eventId"] const eventId: IdTuple = ["eventListId", "eventId"]
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
_id: eventId, _id: eventId,
_ownerGroup: calendarGroupId, _ownerGroup: calendarGroupId,
}) })
@ -1514,7 +1518,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
}) })
o("load passes same parameters to entityRestClient", async function () { o("load passes same parameters to entityRestClient", async function () {
const contactId: IdTuple = [createId("0"), createId("1")] const contactId: IdTuple = [createId("0"), createId("1")]
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: contactId, _id: contactId,
firstName: "greg", firstName: "greg",
}) })
@ -1544,7 +1548,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
}) })
o("single entity is cached after being loaded", async function () { o("single entity is cached after being loaded", async function () {
const contactId: IdTuple = [createId("0"), createId("1")] const contactId: IdTuple = [createId("0"), createId("1")]
const contactOnTheServer = createContact({ const contactOnTheServer = createTestEntity(ContactTypeRef, {
_id: contactId, _id: contactId,
firstName: "greg", firstName: "greg",
}) })
@ -1567,12 +1571,12 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("A new range request for a nonexistent range should initialize that range", async function () { o("A new range request for a nonexistent range should initialize that range", async function () {
const loadRange = spy(function (typeRef, listId, ...an) { const loadRange = spy(function (typeRef, listId, ...an) {
return [ return [
createContact({ _id: [listId, createId("1")] }), createTestEntity(ContactTypeRef, { _id: [listId, createId("1")] }),
createContact({ _id: [listId, createId("2")] }), createTestEntity(ContactTypeRef, { _id: [listId, createId("2")] }),
createContact({ _id: [listId, createId("3")] }), createTestEntity(ContactTypeRef, { _id: [listId, createId("3")] }),
createContact({ _id: [listId, createId("4")] }), createTestEntity(ContactTypeRef, { _id: [listId, createId("4")] }),
createContact({ _id: [listId, createId("5")] }), createTestEntity(ContactTypeRef, { _id: [listId, createId("5")] }),
createContact({ _id: [listId, createId("6")] }), createTestEntity(ContactTypeRef, { _id: [listId, createId("6")] }),
] ]
}) })
@ -1587,7 +1591,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("single entity is not cached if it is an ignored entity", async function () { o("single entity is not cached if it is an ignored entity", async function () {
const permissionId: IdTuple = [createId("0"), createId("1")] const permissionId: IdTuple = [createId("0"), createId("1")]
const permissionOnTheServer = createPermission({ const permissionOnTheServer = createTestEntity(PermissionTypeRef, {
_id: permissionId, _id: permissionId,
}) })
const client = downcast<EntityRestClient>({ const client = downcast<EntityRestClient>({
@ -1605,7 +1609,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o.spec("no user id", function () { o.spec("no user id", function () {
o("get", async function () { o("get", async function () {
userId = null userId = null
entityRestClient.load = spy(async () => createContact({ _id: ["listId", "id"] })) as EntityRestClient["load"] entityRestClient.load = spy(async () => createTestEntity(ContactTypeRef, { _id: ["listId", "id"] })) as EntityRestClient["load"]
await cache.load(ContactTypeRef, ["listId", "id"]) await cache.load(ContactTypeRef, ["listId", "id"])
o(entityRestClient.load.callCount).equals(1) o(entityRestClient.load.callCount).equals(1)
}) })
@ -1613,7 +1617,7 @@ export function testEntityRestCache(name: string, getStorage: (userId: Id) => Pr
o("put", async function () { o("put", async function () {
userId = null userId = null
entityRestClient.setup = spy(async () => "id") entityRestClient.setup = spy(async () => "id")
await cache.setup("listId", createContact({ _id: ["listId", "id"] })) await cache.setup("listId", createTestEntity(ContactTypeRef, { _id: ["listId", "id"] }))
o(entityRestClient.setup.callCount).equals(1) o(entityRestClient.setup.callCount).equals(1)
}) })
}) })

View file

@ -19,7 +19,12 @@ import tutanotaModelInfo from "../../../../../src/api/entities/tutanota/ModelInf
import sysModelInfo from "../../../../../src/api/entities/sys/ModelInfo.js" import sysModelInfo from "../../../../../src/api/entities/sys/ModelInfo.js"
import { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade.js" import { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade.js"
import { LoginIncompleteError } from "../../../../../src/api/common/error/LoginIncompleteError.js" import { LoginIncompleteError } from "../../../../../src/api/common/error/LoginIncompleteError.js"
import { createBlobServerAccessInfo, createBlobServerUrl } from "../../../../../src/api/entities/storage/TypeRefs.js" import {
BlobServerAccessInfoTypeRef,
BlobServerUrlTypeRef,
createBlobServerAccessInfo,
createBlobServerUrl,
} from "../../../../../src/api/entities/storage/TypeRefs.js"
import { Mapper, ofClass } from "@tutao/tutanota-utils" import { Mapper, ofClass } from "@tutao/tutanota-utils"
import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js" import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError.js"
import { BlobAccessTokenFacade } from "../../../../../src/api/worker/facades/BlobAccessTokenFacade.js" import { BlobAccessTokenFacade } from "../../../../../src/api/worker/facades/BlobAccessTokenFacade.js"
@ -57,7 +62,7 @@ const countFrom = (start, count) => createArrayOf(count, (idx) => String(idx + s
function contacts(count) { function contacts(count) {
const contactFactory = (idx) => const contactFactory = (idx) =>
createContact({ createTestEntity(ContactTypeRef, {
firstName: `Contact${idx}`, firstName: `Contact${idx}`,
}) })
@ -343,9 +348,9 @@ o.spec("EntityRestClient", async function () {
const firstServer = "firstServer" const firstServer = "firstServer"
const blobAccessToken = "123" const blobAccessToken = "123"
let blobServerAccessInfo = createBlobServerAccessInfo({ let blobServerAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken, blobAccessToken,
servers: [createBlobServerUrl({ url: firstServer }), createBlobServerUrl({ url: "otherServer" })], servers: [createTestEntity(BlobServerUrlTypeRef, { url: firstServer }), createTestEntity(BlobServerUrlTypeRef, { url: "otherServer" })],
}) })
when(blobAccessTokenFacade.requestReadTokenArchive(archiveId)).thenResolve(blobServerAccessInfo) when(blobAccessTokenFacade.requestReadTokenArchive(archiveId)).thenResolve(blobServerAccessInfo)
@ -399,9 +404,9 @@ o.spec("EntityRestClient", async function () {
const blobAccessToken = "123" const blobAccessToken = "123"
const otherServer = "otherServer" const otherServer = "otherServer"
const blobServerAccessInfo = createBlobServerAccessInfo({ const blobServerAccessInfo = createTestEntity(BlobServerAccessInfoTypeRef, {
blobAccessToken, blobAccessToken,
servers: [createBlobServerUrl({ url: firstServer }), createBlobServerUrl({ url: otherServer })], servers: [createTestEntity(BlobServerUrlTypeRef, { url: firstServer }), createTestEntity(BlobServerUrlTypeRef, { url: otherServer })],
}) })
when(blobAccessTokenFacade.requestReadTokenArchive(archiveId)).thenResolve(blobServerAccessInfo) when(blobAccessTokenFacade.requestReadTokenArchive(archiveId)).thenResolve(blobServerAccessInfo)
@ -793,7 +798,7 @@ o.spec("EntityRestClient", async function () {
o.spec("Update", function () { o.spec("Update", function () {
o("Update entity", async function () { o("Update entity", async function () {
const { version } = await resolveTypeReference(CustomerTypeRef) const { version } = await resolveTypeReference(CustomerTypeRef)
const newCustomer = createCustomer({ const newCustomer = createTestEntity(CustomerTypeRef, {
_id: "id", _id: "id",
}) })
when( when(
@ -815,7 +820,7 @@ o.spec("EntityRestClient", async function () {
o("when ownerKey is passed it is used instead for session key resolution", async function () { o("when ownerKey is passed it is used instead for session key resolution", async function () {
const typeModel = await resolveTypeReference(CustomerTypeRef) const typeModel = await resolveTypeReference(CustomerTypeRef)
const version = typeModel.version const version = typeModel.version
const newCustomer = createCustomer({ const newCustomer = createTestEntity(CustomerTypeRef, {
_id: "id", _id: "id",
}) })
when( when(
@ -840,7 +845,7 @@ o.spec("EntityRestClient", async function () {
o("Delete entity", async function () { o("Delete entity", async function () {
const { version } = await resolveTypeReference(CustomerTypeRef) const { version } = await resolveTypeReference(CustomerTypeRef)
const id = "id" const id = "id"
const newCustomer = createCustomer({ const newCustomer = createTestEntity(CustomerTypeRef, {
_id: id, _id: id,
}) })
when( when(
@ -855,7 +860,7 @@ o.spec("EntityRestClient", async function () {
o.spec("tryServers", function () { o.spec("tryServers", function () {
o("tryServers successful", async function () { o("tryServers successful", async function () {
let servers = [createBlobServerUrl({ url: "w1" }), createBlobServerUrl({ url: "w2" })] let servers = [createTestEntity(BlobServerUrlTypeRef, { url: "w1" }), createTestEntity(BlobServerUrlTypeRef, { url: "w2" })]
const mapperMock = func<Mapper<string, object>>() const mapperMock = func<Mapper<string, object>>()
const expectedResult = { response: "response-from-server" } const expectedResult = { response: "response-from-server" }
when(mapperMock(anything(), anything())).thenResolve(expectedResult) when(mapperMock(anything(), anything())).thenResolve(expectedResult)
@ -866,7 +871,7 @@ o.spec("EntityRestClient", async function () {
}) })
o("tryServers error", async function () { o("tryServers error", async function () {
let servers = [createBlobServerUrl({ url: "w1" }), createBlobServerUrl({ url: "w2" })] let servers = [createTestEntity(BlobServerUrlTypeRef, { url: "w1" }), createTestEntity(BlobServerUrlTypeRef, { url: "w2" })]
const mapperMock = func<Mapper<string, object>>() const mapperMock = func<Mapper<string, object>>()
when(mapperMock("w1", 0)).thenReject(new ProgrammingError("test")) when(mapperMock("w1", 0)).thenReject(new ProgrammingError("test"))
const e = await assertThrows(ProgrammingError, () => tryServers(servers, mapperMock, "error")) const e = await assertThrows(ProgrammingError, () => tryServers(servers, mapperMock, "error"))
@ -875,7 +880,7 @@ o.spec("EntityRestClient", async function () {
}) })
o("tryServers ConnectionError and successful response", async function () { o("tryServers ConnectionError and successful response", async function () {
let servers = [createBlobServerUrl({ url: "w1" }), createBlobServerUrl({ url: "w2" })] let servers = [createTestEntity(BlobServerUrlTypeRef, { url: "w1" }), createTestEntity(BlobServerUrlTypeRef, { url: "w2" })]
const mapperMock = func<Mapper<string, object>>() const mapperMock = func<Mapper<string, object>>()
const expectedResult = { response: "response-from-server" } const expectedResult = { response: "response-from-server" }
when(mapperMock("w1", 0)).thenReject(new ConnectionError("test")) when(mapperMock("w1", 0)).thenReject(new ConnectionError("test"))
@ -886,7 +891,7 @@ o.spec("EntityRestClient", async function () {
}) })
o("tryServers multiple ConnectionError", async function () { o("tryServers multiple ConnectionError", async function () {
let servers = [createBlobServerUrl({ url: "w1" }), createBlobServerUrl({ url: "w2" })] let servers = [createTestEntity(BlobServerUrlTypeRef, { url: "w1" }), createTestEntity(BlobServerUrlTypeRef, { url: "w2" })]
const mapperMock = func<Mapper<string, object>>() const mapperMock = func<Mapper<string, object>>()
when(mapperMock("w1", 0)).thenReject(new ConnectionError("test")) when(mapperMock("w1", 0)).thenReject(new ConnectionError("test"))
when(mapperMock("w2", 1)).thenReject(new ConnectionError("test")) when(mapperMock("w2", 1)).thenReject(new ConnectionError("test"))

View file

@ -13,7 +13,10 @@ o.spec("EphemeralCacheStorageTest", function () {
o.spec("BlobElementType", function () { o.spec("BlobElementType", function () {
o("cache roundtrip: put, get, delete", async function () { o("cache roundtrip: put, get, delete", async function () {
storage.init({ userId }) storage.init({ userId })
const storableMailDetailsBlob = createMailDetailsBlob({ _id: [archiveId, blobElementId], details: createTestEntity(MailDetailsTypeRef) }) const storableMailDetailsBlob = createTestEntity(MailDetailsBlobTypeRef, {
_id: [archiveId, blobElementId],
details: createTestEntity(MailDetailsTypeRef),
})
let mailDetailsBlob = await storage.get(MailDetailsBlobTypeRef, archiveId, blobElementId) let mailDetailsBlob = await storage.get(MailDetailsBlobTypeRef, archiveId, blobElementId)
o(mailDetailsBlob).equals(null) o(mailDetailsBlob).equals(null)
@ -31,7 +34,7 @@ o.spec("EphemeralCacheStorageTest", function () {
o("cache roundtrip: put, get, deleteAllOwnedBy", async function () { o("cache roundtrip: put, get, deleteAllOwnedBy", async function () {
const _ownerGroup = "owenerGroup" const _ownerGroup = "owenerGroup"
storage.init({ userId }) storage.init({ userId })
const storableMailDetailsBlob = createMailDetailsBlob({ const storableMailDetailsBlob = createTestEntity(MailDetailsBlobTypeRef, {
_id: [archiveId, blobElementId], _id: [archiveId, blobElementId],
_ownerGroup, _ownerGroup,
details: createTestEntity(MailDetailsTypeRef), details: createTestEntity(MailDetailsTypeRef),

View file

@ -5,19 +5,14 @@ import { InstanceMapper } from "../../../../../src/api/worker/crypto/InstanceMap
import { CryptoFacade } from "../../../../../src/api/worker/crypto/CryptoFacade.js" import { CryptoFacade } from "../../../../../src/api/worker/crypto/CryptoFacade.js"
import { matchers, object, when } from "testdouble" import { matchers, object, when } from "testdouble"
import { DeleteService, GetService, PostService, PutService } from "../../../../../src/api/common/ServiceRequest.js" import { DeleteService, GetService, PostService, PutService } from "../../../../../src/api/common/ServiceRequest.js"
import { import { AlarmServicePostTypeRef, GiftCardCreateDataTypeRef, SaltDataTypeRef } from "../../../../../src/api/entities/sys/TypeRefs.js"
AlarmServicePostTypeRef,
createGiftCardCreateData,
createSaltData,
GiftCardCreateDataTypeRef,
SaltDataTypeRef,
} from "../../../../../src/api/entities/sys/TypeRefs.js"
import { HttpMethod, MediaType, resolveTypeReference } from "../../../../../src/api/common/EntityFunctions.js" import { HttpMethod, MediaType, resolveTypeReference } from "../../../../../src/api/common/EntityFunctions.js"
import { deepEqual } from "@tutao/tutanota-utils" import { deepEqual } from "@tutao/tutanota-utils"
import { assertThrows, verify } from "@tutao/tutanota-test-utils" import { assertThrows, verify } from "@tutao/tutanota-test-utils"
import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError" import { ProgrammingError } from "../../../../../src/api/common/error/ProgrammingError"
import { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade" import { AuthDataProvider } from "../../../../../src/api/worker/facades/UserFacade"
import { LoginIncompleteError } from "../../../../../src/api/common/error/LoginIncompleteError.js" import { LoginIncompleteError } from "../../../../../src/api/common/error/LoginIncompleteError.js"
import { createTestEntity } from "../../../TestUtils.js"
const { anything } = matchers const { anything } = matchers
@ -68,7 +63,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal) when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal)
@ -95,7 +90,7 @@ o.spec("ServiceExecutor", function () {
return: SaltDataTypeRef, return: SaltDataTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData)
@ -121,7 +116,7 @@ o.spec("ServiceExecutor", function () {
return: AlarmServicePostTypeRef, return: AlarmServicePostTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(AlarmServicePostTypeRef) const saltTypeModel = await resolveTypeReference(AlarmServicePostTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData)
@ -162,7 +157,7 @@ o.spec("ServiceExecutor", function () {
} }
const sessionKey = [1, 2, 3] const sessionKey = [1, 2, 3]
fullyLoggedIn = false fullyLoggedIn = false
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(AlarmServicePostTypeRef) const saltTypeModel = await resolveTypeReference(AlarmServicePostTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, sessionKey)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, sessionKey)).thenResolve(returnData)
@ -190,7 +185,7 @@ o.spec("ServiceExecutor", function () {
}, },
} }
fullyLoggedIn = false fullyLoggedIn = false
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData)
@ -219,7 +214,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal) when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal)
@ -246,7 +241,7 @@ o.spec("ServiceExecutor", function () {
return: SaltDataTypeRef, return: SaltDataTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData)
@ -287,7 +282,7 @@ o.spec("ServiceExecutor", function () {
} }
const sessionKey = [1, 2, 3] const sessionKey = [1, 2, 3]
fullyLoggedIn = false fullyLoggedIn = false
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(AlarmServicePostTypeRef) const saltTypeModel = await resolveTypeReference(AlarmServicePostTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, sessionKey)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, sessionKey)).thenResolve(returnData)
@ -316,7 +311,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal) when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal)
@ -343,7 +338,7 @@ o.spec("ServiceExecutor", function () {
return: SaltDataTypeRef, return: SaltDataTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData)
@ -384,7 +379,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal) when(instanceMapper.encryptAndMapToLiteral(saltTypeModel, data, null)).thenResolve(literal)
@ -411,7 +406,7 @@ o.spec("ServiceExecutor", function () {
return: SaltDataTypeRef, return: SaltDataTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData) when(instanceMapper.decryptAndMapToInstance(saltTypeModel, literal, null)).thenResolve(returnData)
@ -453,7 +448,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const query = Object.freeze({ myQueryParam: "2" }) const query = Object.freeze({ myQueryParam: "2" })
when(instanceMapper.encryptAndMapToLiteral(anything(), anything(), anything())).thenResolve({}) when(instanceMapper.encryptAndMapToLiteral(anything(), anything(), anything())).thenResolve({})
respondWith(undefined) respondWith(undefined)
@ -478,7 +473,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const headers = Object.freeze({ myHeader: "2" }) const headers = Object.freeze({ myHeader: "2" })
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
when(instanceMapper.encryptAndMapToLiteral(anything(), anything(), anything())).thenResolve({}) when(instanceMapper.encryptAndMapToLiteral(anything(), anything(), anything())).thenResolve({})
@ -505,7 +500,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const data = createSaltData({ mailAddress: "test" }) const data = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const accessToken = "myAccessToken" const accessToken = "myAccessToken"
authHeaders = { accessToken } authHeaders = { accessToken }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
@ -534,7 +529,7 @@ o.spec("ServiceExecutor", function () {
return: SaltDataTypeRef, return: SaltDataTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
const sessionKey = [1, 2, 3] const sessionKey = [1, 2, 3]
@ -563,7 +558,7 @@ o.spec("ServiceExecutor", function () {
return: SaltDataTypeRef, return: SaltDataTypeRef,
}, },
} }
const returnData = createSaltData({ mailAddress: "test" }) const returnData = createTestEntity(SaltDataTypeRef, { mailAddress: "test" })
const literal = { literal: true } const literal = { literal: true }
const saltTypeModel = await resolveTypeReference(SaltDataTypeRef) const saltTypeModel = await resolveTypeReference(SaltDataTypeRef)
const sessionKey = [1, 2, 3] const sessionKey = [1, 2, 3]
@ -592,7 +587,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const giftCardCreateData = createGiftCardCreateData({ message: "test" }) const giftCardCreateData = createTestEntity(GiftCardCreateDataTypeRef, { message: "test" })
const dataTypeModel = await resolveTypeReference(GiftCardCreateDataTypeRef) const dataTypeModel = await resolveTypeReference(GiftCardCreateDataTypeRef)
const sessionKey = [1, 2, 3] const sessionKey = [1, 2, 3]
const encrypted = { encrypted: true } const encrypted = { encrypted: true }
@ -620,7 +615,7 @@ o.spec("ServiceExecutor", function () {
return: null, return: null,
}, },
} }
const giftCardCreateData = createGiftCardCreateData({ message: "test" }) const giftCardCreateData = createTestEntity(GiftCardCreateDataTypeRef, { message: "test" })
await o(() => executor.get(getService, giftCardCreateData)).asyncThrows(ProgrammingError) await o(() => executor.get(getService, giftCardCreateData)).asyncThrows(ProgrammingError)
verify(restClient.request(anything(), anything()), { ignoreExtraArgs: true, times: 0 }) verify(restClient.request(anything(), anything()), { ignoreExtraArgs: true, times: 0 })

View file

@ -765,11 +765,11 @@ o.spec("Indexer test", () => {
}, },
] ]
let loadedBatches = [ let loadedBatches = [
createEntityEventBatch({ createTestEntity(EntityEventBatchTypeRef, {
_id: ["group-mail", loadedNewBatchId], _id: ["group-mail", loadedNewBatchId],
events: [createTestEntity(EntityUpdateTypeRef), createTestEntity(EntityUpdateTypeRef)], events: [createTestEntity(EntityUpdateTypeRef), createTestEntity(EntityUpdateTypeRef)],
}), }),
createEntityEventBatch({ createTestEntity(EntityEventBatchTypeRef, {
_id: ["group-mail", oldestBatchId], _id: ["group-mail", oldestBatchId],
}), }),
] ]
@ -798,7 +798,7 @@ o.spec("Indexer test", () => {
const loadPromise = indexer._loadNewEntities(groupIdToEventBatches) const loadPromise = indexer._loadNewEntities(groupIdToEventBatches)
const realtimeUpdates = [ const realtimeUpdates = [
createEntityUpdate({ createTestEntity(EntityUpdateTypeRef, {
instanceId: "realtime", instanceId: "realtime",
}), }),
] ]
@ -1148,7 +1148,7 @@ o.spec("Indexer test", () => {
}) })
}) })
const events1 = [ const events1 = [
createEntityUpdate({ createTestEntity(EntityUpdateTypeRef, {
application: MailTypeRef.app, application: MailTypeRef.app,
type: MailTypeRef.type, type: MailTypeRef.type,
operation: OperationType.CREATE, operation: OperationType.CREATE,
@ -1162,7 +1162,7 @@ o.spec("Indexer test", () => {
batchId: "batch-id-1", batchId: "batch-id-1",
} }
const events2 = [ const events2 = [
createEntityUpdate({ createTestEntity(EntityUpdateTypeRef, {
application: MailTypeRef.app, application: MailTypeRef.app,
type: MailTypeRef.type, type: MailTypeRef.type,
operation: OperationType.CREATE, operation: OperationType.CREATE,

View file

@ -38,6 +38,8 @@ import {
MailBoxTypeRef, MailBoxTypeRef,
MailFolderRefTypeRef, MailFolderRefTypeRef,
MailboxGroupRootTypeRef, MailboxGroupRootTypeRef,
MailDetailsBlobTypeRef,
MailDetailsTypeRef,
} from "../../../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../../../src/api/entities/tutanota/TypeRefs.js"
import { mock, spy } from "@tutao/tutanota-test-utils" import { mock, spy } from "@tutao/tutanota-test-utils"
import { browserDataStub, createTestEntity, makeCore } from "../../../TestUtils.js" import { browserDataStub, createTestEntity, makeCore } from "../../../TestUtils.js"
@ -92,7 +94,10 @@ o.spec("MailIndexer test", () => {
o("createMailIndexEntries without entries", function () { o("createMailIndexEntries without entries", function () {
let mail = createTestEntity(MailTypeRef) let mail = createTestEntity(MailTypeRef)
mail.mailDetails = ["details-list-id", "details-id"] mail.mailDetails = ["details-list-id", "details-id"]
let details = MailWrapper.details(mail, createMailDetails({ body: createTestEntity(BodyTypeRef), recipients: createTestEntity(RecipientsTypeRef) })) let details = MailWrapper.details(
mail,
createTestEntity(MailDetailsTypeRef, { body: createTestEntity(BodyTypeRef), recipients: createTestEntity(RecipientsTypeRef) }),
)
let files = [createTestEntity(FileTypeRef)] let files = [createTestEntity(FileTypeRef)]
let indexer = new MailIndexer( let indexer = new MailIndexer(
new IndexerCore(dbMock, null as any, browserDataStub), new IndexerCore(dbMock, null as any, browserDataStub),
@ -110,7 +115,10 @@ o.spec("MailIndexer test", () => {
let mail = createTestEntity(MailTypeRef) let mail = createTestEntity(MailTypeRef)
mail.subject = "Hello" mail.subject = "Hello"
mail.mailDetails = ["details-list-id", "details-id"] mail.mailDetails = ["details-list-id", "details-id"]
let details = MailWrapper.details(mail, createMailDetails({ body: createTestEntity(BodyTypeRef), recipients: createTestEntity(RecipientsTypeRef) })) let details = MailWrapper.details(
mail,
createTestEntity(MailDetailsTypeRef, { body: createTestEntity(BodyTypeRef), recipients: createTestEntity(RecipientsTypeRef) }),
)
let files = [createTestEntity(FileTypeRef)] let files = [createTestEntity(FileTypeRef)]
let indexer = new MailIndexer( let indexer = new MailIndexer(
new IndexerCore(dbMock, null as any, browserDataStub), new IndexerCore(dbMock, null as any, browserDataStub),
@ -163,7 +171,7 @@ o.spec("MailIndexer test", () => {
mail.sender = sender mail.sender = sender
mail.mailDetails = ["details-list-id", "details-id"] mail.mailDetails = ["details-list-id", "details-id"]
let details = MailWrapper.details(mail, createMailDetails({ body: createTestEntity(BodyTypeRef), recipients })) let details = MailWrapper.details(mail, createTestEntity(MailDetailsTypeRef, { body: createTestEntity(BodyTypeRef), recipients }))
details.getDetails().body.text = "BT" details.getDetails().body.text = "BT"
let files = [createTestEntity(FileTypeRef)] let files = [createTestEntity(FileTypeRef)]
files[0].mimeType = "binary" // not indexed files[0].mimeType = "binary" // not indexed
@ -925,15 +933,15 @@ function createMailInstances(
mailDetailsBlob: MailDetailsBlob mailDetailsBlob: MailDetailsBlob
files: Array<TutanotaFile> files: Array<TutanotaFile>
} { } {
let mail = createMail({ let mail = createTestEntity(MailTypeRef, {
_id: mailId, _id: mailId,
_ownerEncSessionKey: new Uint8Array(), _ownerEncSessionKey: new Uint8Array(),
mailDetails: mailDetailsBlobId, mailDetails: mailDetailsBlobId,
attachments: attachmentIds, attachments: attachmentIds,
}) })
let mailDetailsBlob = createMailDetailsBlob({ let mailDetailsBlob = createTestEntity(MailDetailsBlobTypeRef, {
_id: mailDetailsBlobId, _id: mailDetailsBlobId,
details: createMailDetails({ details: createTestEntity(MailDetailsTypeRef, {
body: createTestEntity(BodyTypeRef), body: createTestEntity(BodyTypeRef),
recipients: createTestEntity(RecipientsTypeRef), recipients: createTestEntity(RecipientsTypeRef),
}), }),

View file

@ -1,10 +1,10 @@
import { AlarmScheduler, AlarmSchedulerImpl } from "../../../src/calendar/date/AlarmScheduler.js" import { AlarmScheduler, AlarmSchedulerImpl } from "../../../src/calendar/date/AlarmScheduler.js"
import o from "@tutao/otest" import o from "@tutao/otest"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { createAlarmInfo, createDateWrapper, createRepeatRule } from "../../../src/api/entities/sys/TypeRefs.js" import { AlarmInfoTypeRef, DateWrapperTypeRef, RepeatRuleTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import { EndType, RepeatPeriod } from "../../../src/api/common/TutanotaConstants.js" import { EndType, RepeatPeriod } from "../../../src/api/common/TutanotaConstants.js"
import { DateProvider } from "../../../src/api/common/DateProvider.js" import { DateProvider } from "../../../src/api/common/DateProvider.js"
import { SchedulerMock } from "../TestUtils.js" import { createTestEntity, SchedulerMock } from "../TestUtils.js"
import { spy } from "@tutao/tutanota-test-utils" import { spy } from "@tutao/tutanota-test-utils"
o.spec("AlarmScheduler", function () { o.spec("AlarmScheduler", function () {
@ -27,7 +27,7 @@ o.spec("AlarmScheduler", function () {
endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(), endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(),
summary: "summary", summary: "summary",
} }
const alarmInfo = createAlarmInfo({ const alarmInfo = createTestEntity(AlarmInfoTypeRef, {
trigger: "10M", trigger: "10M",
}) })
const notificationSender = spy() const notificationSender = spy()
@ -48,10 +48,10 @@ o.spec("AlarmScheduler", function () {
endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(), endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(),
summary: "summary", summary: "summary",
} }
const alarmInfo = createAlarmInfo({ const alarmInfo = createTestEntity(AlarmInfoTypeRef, {
trigger: "30M", trigger: "30M",
}) })
const repeatRule = createRepeatRule({ const repeatRule = createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.Count, endType: EndType.Count,
@ -83,16 +83,16 @@ o.spec("AlarmScheduler", function () {
endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(), endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(),
summary: "summary", summary: "summary",
} }
const alarmInfo = createAlarmInfo({ const alarmInfo = createTestEntity(AlarmInfoTypeRef, {
trigger: "30M", trigger: "30M",
}) })
const repeatRule = createRepeatRule({ const repeatRule = createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.Count, endType: EndType.Count,
endValue: "3", endValue: "3",
timeZone: "Europe/Berlin", timeZone: "Europe/Berlin",
excludedDates: [createDateWrapper({ date: DateTime.fromISO("2021-04-22T20:00Z").toJSDate() })], excludedDates: [createTestEntity(DateWrapperTypeRef, { date: DateTime.fromISO("2021-04-22T20:00Z").toJSDate() })],
}) })
const notificationSender = spy() const notificationSender = spy()
alarmScheduler.scheduleAlarm(eventInfo, alarmInfo, repeatRule, notificationSender) alarmScheduler.scheduleAlarm(eventInfo, alarmInfo, repeatRule, notificationSender)
@ -121,7 +121,7 @@ o.spec("AlarmScheduler", function () {
endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(), endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(),
summary: "summary", summary: "summary",
} }
const alarmInfo = createAlarmInfo({ const alarmInfo = createTestEntity(AlarmInfoTypeRef, {
trigger: "10M", trigger: "10M",
alarmIdentifier: "identifier", alarmIdentifier: "identifier",
}) })
@ -143,10 +143,10 @@ o.spec("AlarmScheduler", function () {
endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(), endTime: DateTime.fromISO("2021-04-21T20:30Z").toJSDate(),
summary: "summary", summary: "summary",
} }
const alarmInfo = createAlarmInfo({ const alarmInfo = createTestEntity(AlarmInfoTypeRef, {
trigger: "30M", trigger: "30M",
}) })
const repeatRule = createRepeatRule({ const repeatRule = createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.Count, endType: EndType.Count,

View file

@ -9,13 +9,13 @@ import {
} from "../../../src/calendar/export/CalendarImporter.js" } from "../../../src/calendar/export/CalendarImporter.js"
import { import {
CalendarEvent, CalendarEvent,
CalendarEventAttendeeTypeRef,
CalendarEventTypeRef,
CalendarGroupRootTypeRef, CalendarGroupRootTypeRef,
createCalendarEvent, EncryptedMailAddressTypeRef,
createCalendarEventAttendee,
createEncryptedMailAddress,
} from "../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { createAlarmInfo, createDateWrapper, createRepeatRule, createUserAlarmInfo, RepeatRuleTypeRef } from "../../../src/api/entities/sys/TypeRefs.js" import { AlarmInfoTypeRef, DateWrapperTypeRef, RepeatRuleTypeRef, UserAlarmInfoTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import { CalendarAttendeeStatus, EndType, RepeatPeriod } from "../../../src/api/common/TutanotaConstants.js" import { CalendarAttendeeStatus, EndType, RepeatPeriod } from "../../../src/api/common/TutanotaConstants.js"
import { getAllDayDateUTC } from "../../../src/api/common/utils/CommonCalendarUtils.js" import { getAllDayDateUTC } from "../../../src/api/common/utils/CommonCalendarUtils.js"
import { getAllDayDateUTCFromZone } from "../../../src/calendar/date/CalendarUtils.js" import { getAllDayDateUTCFromZone } from "../../../src/calendar/date/CalendarUtils.js"
@ -23,7 +23,6 @@ import { EventImportRejectionReason, sortOutParsedEvents } from "../../../src/ca
import { getDateInZone } from "./CalendarTestUtils.js" import { getDateInZone } from "./CalendarTestUtils.js"
import { Require } from "@tutao/tutanota-utils" import { Require } from "@tutao/tutanota-utils"
import { createTestEntity } from "../TestUtils.js" import { createTestEntity } from "../TestUtils.js"
import { writeFile, writeFileSync } from "fs-extra"
const zone = "Europe/Berlin" const zone = "Europe/Berlin"
const now = new Date("2019-08-13T14:01:00.630Z") const now = new Date("2019-08-13T14:01:00.630Z")
@ -58,7 +57,7 @@ o.spec("CalendarImporterTest", function () {
o("simple one", function () { o("simple one", function () {
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -107,7 +106,7 @@ o.spec("CalendarImporterTest", function () {
const zone = "utc" const zone = "utc"
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -151,7 +150,7 @@ o.spec("CalendarImporterTest", function () {
const zone = "America/New_York" const zone = "America/New_York"
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "s", summary: "s",
@ -188,21 +187,21 @@ o.spec("CalendarImporterTest", function () {
]) ])
}) })
o("with alarms", function () { o("with alarms", function () {
const alarmOne = createUserAlarmInfo({ const alarmOne = createTestEntity(UserAlarmInfoTypeRef, {
alarmInfo: createAlarmInfo({ alarmInfo: createTestEntity(AlarmInfoTypeRef, {
alarmIdentifier: "123", alarmIdentifier: "123",
trigger: "1D", trigger: "1D",
}), }),
}) })
const alarmTwo = createUserAlarmInfo({ const alarmTwo = createTestEntity(UserAlarmInfoTypeRef, {
alarmInfo: createAlarmInfo({ alarmInfo: createTestEntity(AlarmInfoTypeRef, {
alarmIdentifier: "102", alarmIdentifier: "102",
trigger: "30M", trigger: "30M",
}), }),
}) })
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -258,7 +257,7 @@ o.spec("CalendarImporterTest", function () {
o("with repeat rule (never ends)", function () { o("with repeat rule (never ends)", function () {
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -282,7 +281,7 @@ o.spec("CalendarImporterTest", function () {
}, },
{ zone }, { zone },
).toJSDate(), ).toJSDate(),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.Never, endType: EndType.Never,
interval: "3", interval: "3",
frequency: RepeatPeriod.WEEKLY, frequency: RepeatPeriod.WEEKLY,
@ -309,7 +308,7 @@ o.spec("CalendarImporterTest", function () {
o("with repeat rule (ends after occurrences)", function () { o("with repeat rule (ends after occurrences)", function () {
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -333,7 +332,7 @@ o.spec("CalendarImporterTest", function () {
}, },
{ zone }, { zone },
).toJSDate(), ).toJSDate(),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
interval: "3", interval: "3",
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
@ -360,7 +359,7 @@ o.spec("CalendarImporterTest", function () {
o("with repeat rule (ends on a date)", function () { o("with repeat rule (ends on a date)", function () {
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -384,7 +383,7 @@ o.spec("CalendarImporterTest", function () {
}, },
{ zone }, { zone },
).toJSDate(), ).toJSDate(),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.UntilDate, endType: EndType.UntilDate,
interval: "3", interval: "3",
frequency: RepeatPeriod.MONTHLY, frequency: RepeatPeriod.MONTHLY,
@ -420,7 +419,7 @@ o.spec("CalendarImporterTest", function () {
o("with repeat rule (ends on a date, all-day)", function () { o("with repeat rule (ends on a date, all-day)", function () {
o( o(
serializeEvent( serializeEvent(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -438,7 +437,7 @@ o.spec("CalendarImporterTest", function () {
day: 15, day: 15,
}).toJSDate(), }).toJSDate(),
), ),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.UntilDate, endType: EndType.UntilDate,
interval: "3", interval: "3",
frequency: RepeatPeriod.MONTHLY, frequency: RepeatPeriod.MONTHLY,
@ -498,7 +497,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -522,7 +521,7 @@ o.spec("CalendarImporterTest", function () {
).toJSDate(), ).toJSDate(),
uid: "test@tuta.com", uid: "test@tuta.com",
hashedUid: null, hashedUid: null,
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.Never, endType: EndType.Never,
interval: "3", interval: "3",
frequency: RepeatPeriod.WEEKLY, frequency: RepeatPeriod.WEEKLY,
@ -561,7 +560,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "s", summary: "s",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -585,13 +584,13 @@ o.spec("CalendarImporterTest", function () {
).toJSDate(), ).toJSDate(),
uid: "test@tuta.com", uid: "test@tuta.com",
hashedUid: null, hashedUid: null,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
name: "", name: "",
address: "organizer@tuta.com", address: "organizer@tuta.com",
}), }),
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
name: "", name: "",
address: "test@example.com", address: "test@example.com",
}), }),
@ -632,7 +631,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "s", summary: "s",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -656,13 +655,13 @@ o.spec("CalendarImporterTest", function () {
).toJSDate(), ).toJSDate(),
uid: "test@tuta.com", uid: "test@tuta.com",
hashedUid: null, hashedUid: null,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
name: "", name: "",
address: "organizer@tuta.com", address: "organizer@tuta.com",
}), }),
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
name: "", name: "",
address: "test@example.com", address: "test@example.com",
}), }),
@ -705,7 +704,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "s", summary: "s",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -729,13 +728,13 @@ o.spec("CalendarImporterTest", function () {
).toJSDate(), ).toJSDate(),
uid: "test@tuta.com", uid: "test@tuta.com",
hashedUid: null, hashedUid: null,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
name: "", name: "",
address: "organizer@tuta.com", address: "organizer@tuta.com",
}), }),
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
name: "", name: "",
address: "test@example.com", address: "test@example.com",
}), }),
@ -775,7 +774,7 @@ o.spec("CalendarImporterTest", function () {
zone, zone,
).contents[0], ).contents[0],
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "Labor Day / May Day", summary: "Labor Day / May Day",
startTime: getAllDayDateUTCFromZone( startTime: getAllDayDateUTCFromZone(
DateTime.fromObject( DateTime.fromObject(
@ -810,7 +809,7 @@ o.spec("CalendarImporterTest", function () {
}) })
o("recurrence id on event without UID will be deleted", async function () { o("recurrence id on event without UID will be deleted", async function () {
const expected = { const expected = {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-07-04T15:00:00.000Z"), startTime: new Date("2023-07-04T15:00:00.000Z"),
endTime: new Date("2023-07-04T15:30:00.000Z"), endTime: new Date("2023-07-04T15:30:00.000Z"),
sequence: "1", sequence: "1",
@ -869,7 +868,7 @@ o.spec("CalendarImporterTest", function () {
zone, zone,
).contents[0], ).contents[0],
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "Labor Day / May Day", summary: "Labor Day / May Day",
startTime: getAllDayDateUTCFromZone( startTime: getAllDayDateUTCFromZone(
DateTime.fromObject( DateTime.fromObject(
@ -930,7 +929,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -957,7 +956,7 @@ o.spec("CalendarImporterTest", function () {
repeatRule: null, repeatRule: null,
}), }),
alarms: [ alarms: [
createAlarmInfo({ createTestEntity(AlarmInfoTypeRef, {
trigger: "15D", trigger: "15D",
}), }),
], ],
@ -996,7 +995,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -1023,7 +1022,7 @@ o.spec("CalendarImporterTest", function () {
repeatRule: null, repeatRule: null,
}), }),
alarms: [ alarms: [
createAlarmInfo({ createTestEntity(AlarmInfoTypeRef, {
trigger: "66M", trigger: "66M",
}), }),
], ],
@ -1060,7 +1059,7 @@ o.spec("CalendarImporterTest", function () {
method: "PUBLISH", method: "PUBLISH",
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
{ {
@ -1093,19 +1092,19 @@ o.spec("CalendarImporterTest", function () {
) )
}) })
o("roundtrip export -> import", async function () { o("roundtrip export -> import", async function () {
const alarmOne = createUserAlarmInfo({ const alarmOne = createTestEntity(UserAlarmInfoTypeRef, {
alarmInfo: createAlarmInfo({ alarmInfo: createTestEntity(AlarmInfoTypeRef, {
trigger: "1D", trigger: "1D",
}), }),
}) })
const alarmTwo = createUserAlarmInfo({ const alarmTwo = createTestEntity(UserAlarmInfoTypeRef, {
alarmInfo: createAlarmInfo({ alarmInfo: createTestEntity(AlarmInfoTypeRef, {
trigger: "30M", trigger: "30M",
}), }),
}) })
const events = [ const events = [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
summary: "Word \\ ; \n simple", summary: "Word \\ ; \n simple",
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
@ -1136,7 +1135,7 @@ o.spec("CalendarImporterTest", function () {
alarms: [], alarms: [],
}, },
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n alarms", summary: "Word \\ ; \n alarms",
@ -1167,7 +1166,7 @@ o.spec("CalendarImporterTest", function () {
alarms: [alarmOne, alarmTwo], alarms: [alarmOne, alarmTwo],
}, },
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -1193,7 +1192,7 @@ o.spec("CalendarImporterTest", function () {
).toJSDate(), ).toJSDate(),
uid: "test@tuta.com", uid: "test@tuta.com",
hashedUid: null, hashedUid: null,
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.UntilDate, endType: EndType.UntilDate,
interval: "3", interval: "3",
frequency: RepeatPeriod.MONTHLY, frequency: RepeatPeriod.MONTHLY,
@ -1213,7 +1212,7 @@ o.spec("CalendarImporterTest", function () {
alarms: [], alarms: [],
}, },
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
_id: ["123", "456"], _id: ["123", "456"],
_ownerGroup: "ownerId", _ownerGroup: "ownerId",
summary: "Word \\ ; \n", summary: "Word \\ ; \n",
@ -1233,7 +1232,7 @@ o.spec("CalendarImporterTest", function () {
), ),
uid: "b64lookingValue==", uid: "b64lookingValue==",
hashedUid: null, hashedUid: null,
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.UntilDate, endType: EndType.UntilDate,
interval: "3", interval: "3",
frequency: RepeatPeriod.MONTHLY, frequency: RepeatPeriod.MONTHLY,
@ -1339,7 +1338,7 @@ END:VCALENDAR`
_id: ["123", "456"], _id: ["123", "456"],
}), }),
alarms: alarms.map((alarmInfo) => alarms: alarms.map((alarmInfo) =>
createUserAlarmInfo({ createTestEntity(UserAlarmInfoTypeRef, {
alarmInfo, alarmInfo,
}), }),
), ),
@ -1353,8 +1352,14 @@ END:VCALENDAR`
}) })
o.spec("sortOutParsedEvents", function () { o.spec("sortOutParsedEvents", function () {
o("repeated progenitors are skipped", function () { o("repeated progenitors are skipped", function () {
const progenitor1 = createCalendarEvent({ uid: "hello", startTime: getDateInZone("2023-01-02T13:00") }) as Require<"uid", CalendarEvent> const progenitor1 = createTestEntity(CalendarEventTypeRef, { uid: "hello", startTime: getDateInZone("2023-01-02T13:00") }) as Require<
const progenitor2 = createCalendarEvent({ uid: "hello", startTime: getDateInZone("2023-01-01T13:00") }) as Require<"uid", CalendarEvent> "uid",
CalendarEvent
>
const progenitor2 = createTestEntity(CalendarEventTypeRef, { uid: "hello", startTime: getDateInZone("2023-01-01T13:00") }) as Require<
"uid",
CalendarEvent
>
const { rejectedEvents, eventsForCreation } = sortOutParsedEvents( const { rejectedEvents, eventsForCreation } = sortOutParsedEvents(
[ [
{ event: progenitor1, alarms: [] }, { event: progenitor1, alarms: [] },
@ -1371,12 +1376,12 @@ END:VCALENDAR`
o(rejectedEvents.get(EventImportRejectionReason.Duplicate)?.[0]).equals(progenitor2) o(rejectedEvents.get(EventImportRejectionReason.Duplicate)?.[0]).equals(progenitor2)
}) })
o("imported altered instances are added as exclusions", function () { o("imported altered instances are added as exclusions", function () {
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
uid: "hello", uid: "hello",
startTime: getDateInZone("2023-01-02T13:00"), startTime: getDateInZone("2023-01-02T13:00"),
repeatRule: createTestEntity(RepeatRuleTypeRef), repeatRule: createTestEntity(RepeatRuleTypeRef),
}) as Require<"uid", CalendarEvent> }) as Require<"uid", CalendarEvent>
const altered = createCalendarEvent({ const altered = createTestEntity(CalendarEventTypeRef, {
uid: "hello", uid: "hello",
startTime: getDateInZone("2023-01-02T14:00"), startTime: getDateInZone("2023-01-02T14:00"),
recurrenceId: getDateInZone("2023-01-02T13:00"), recurrenceId: getDateInZone("2023-01-02T13:00"),
@ -1397,7 +1402,7 @@ END:VCALENDAR`
o.spec("serializeRepeatRule", function () { o.spec("serializeRepeatRule", function () {
o("when RRULE is UNTIL and not all date the timestamp of the end of last day is written", function () { o("when RRULE is UNTIL and not all date the timestamp of the end of last day is written", function () {
const repeatRule = createRepeatRule({ const repeatRule = createTestEntity(RepeatRuleTypeRef, {
endType: EndType.UntilDate, endType: EndType.UntilDate,
endValue: String(DateTime.fromObject({ year: 2019, month: 9, day: 20 }, { zone: "UTC" }).toMillis()), endValue: String(DateTime.fromObject({ year: 2019, month: 9, day: 20 }, { zone: "UTC" }).toMillis()),
frequency: RepeatPeriod.MONTHLY, frequency: RepeatPeriod.MONTHLY,
@ -1413,7 +1418,7 @@ END:VCALENDAR`
}) })
o("one excluded date", function () { o("one excluded date", function () {
o(serializeExcludedDates([createDateWrapper({ date: new Date("2023-01-14T22:00:00Z") })], "Europe/Berlin")).deepEquals([ o(serializeExcludedDates([createTestEntity(DateWrapperTypeRef, { date: new Date("2023-01-14T22:00:00Z") })], "Europe/Berlin")).deepEquals([
"EXDATE;TZID=Europe/Berlin:20230114T230000", "EXDATE;TZID=Europe/Berlin:20230114T230000",
]) ])
}) })
@ -1421,7 +1426,10 @@ END:VCALENDAR`
o("more than one excluded date", function () { o("more than one excluded date", function () {
o( o(
serializeExcludedDates( serializeExcludedDates(
[createDateWrapper({ date: new Date("2023-01-14T22:00:00Z") }), createDateWrapper({ date: new Date("2023-01-21T22:00:00Z") })], [
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-01-14T22:00:00Z") }),
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-01-21T22:00:00Z") }),
],
"Europe/Berlin", "Europe/Berlin",
), ),
).deepEquals(["EXDATE;TZID=Europe/Berlin:20230114T230000,20230121T230000"]) ).deepEquals(["EXDATE;TZID=Europe/Berlin:20230114T230000,20230121T230000"])

View file

@ -1,14 +1,11 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import type { CalendarEvent, CalendarGroupRoot } from "../../../src/api/entities/tutanota/TypeRefs.js" import type { CalendarEvent, CalendarGroupRoot } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { import {
CalendarEventAttendeeTypeRef,
CalendarEventTypeRef, CalendarEventTypeRef,
CalendarEventUpdateTypeRef, CalendarEventUpdateTypeRef,
createCalendarEvent, CalendarGroupRootTypeRef,
createCalendarEventAttendee, EncryptedMailAddressTypeRef,
createCalendarEventUpdate,
createCalendarGroupRoot,
createEncryptedMailAddress,
createFile,
FileTypeRef, FileTypeRef,
} from "../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { incrementByRepeatPeriod } from "../../../src/calendar/date/CalendarUtils.js" import { incrementByRepeatPeriod } from "../../../src/calendar/date/CalendarUtils.js"
@ -19,7 +16,7 @@ import { DateTime } from "luxon"
import type { EntityUpdateData } from "../../../src/api/main/EventController.js" import type { EntityUpdateData } from "../../../src/api/main/EventController.js"
import { EntityEventsListener, EventController } from "../../../src/api/main/EventController.js" import { EntityEventsListener, EventController } from "../../../src/api/main/EventController.js"
import { Notifications } from "../../../src/gui/Notifications.js" import { Notifications } from "../../../src/gui/Notifications.js"
import { AlarmInfo, createAlarmInfo, createUser, createUserAlarmInfo, createUserAlarmInfoListType } from "../../../src/api/entities/sys/TypeRefs.js" import { AlarmInfo, AlarmInfoTypeRef, UserAlarmInfoListTypeTypeRef, UserAlarmInfoTypeRef, UserTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import { EntityRestClientMock } from "../api/worker/rest/EntityRestClientMock.js" import { EntityRestClientMock } from "../api/worker/rest/EntityRestClientMock.js"
import type { UserController } from "../../../src/api/main/UserController.js" import type { UserController } from "../../../src/api/main/UserController.js"
import { NotFoundError } from "../../../src/api/common/error/RestError.js" import { NotFoundError } from "../../../src/api/common/error/RestError.js"
@ -36,6 +33,7 @@ import { func, matchers, when } from "testdouble"
import { elementIdPart, getElementId, listIdPart } from "../../../src/api/common/utils/EntityUtils.js" import { elementIdPart, getElementId, listIdPart } from "../../../src/api/common/utils/EntityUtils.js"
import { createDataFile } from "../../../src/api/common/DataFile.js" import { createDataFile } from "../../../src/api/common/DataFile.js"
import { SessionKeyNotFoundError } from "../../../src/api/common/error/SessionKeyNotFoundError.js" import { SessionKeyNotFoundError } from "../../../src/api/common/error/SessionKeyNotFoundError.js"
import { createTestEntity } from "../TestUtils.js"
o.spec("CalendarModel", function () { o.spec("CalendarModel", function () {
o.spec("incrementByRepeatPeriod", function () { o.spec("incrementByRepeatPeriod", function () {
@ -189,7 +187,7 @@ o.spec("CalendarModel", function () {
const loginController = makeLoginController() const loginController = makeLoginController()
const alarmsListId = neverNull(loginController.getUserController().user.alarmInfoList).alarms const alarmsListId = neverNull(loginController.getUserController().user.alarmInfoList).alarms
o.beforeEach(function () { o.beforeEach(function () {
groupRoot = createCalendarGroupRoot({ groupRoot = createTestEntity(CalendarGroupRootTypeRef, {
_id: "groupRootId", _id: "groupRootId",
longEvents: "longEvents", longEvents: "longEvents",
shortEvents: "shortEvents", shortEvents: "shortEvents",
@ -199,7 +197,7 @@ o.spec("CalendarModel", function () {
}) })
o("reply but sender is not a guest", async function () { o("reply but sender is not a guest", async function () {
const uid = "uid" const uid = "uid"
const existingEvent = createCalendarEvent({ uid }) const existingEvent = createTestEntity(CalendarEventTypeRef, { uid })
const calendarFacade = makeCalendarFacade( const calendarFacade = makeCalendarFacade(
{ {
getEventsByUid: (loadUid) => getEventsByUid: (loadUid) =>
@ -217,7 +215,7 @@ o.spec("CalendarModel", function () {
method: CalendarMethod.REPLY, method: CalendarMethod.REPLY,
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
uid, uid,
}) as CalendarEventProgenitor, }) as CalendarEventProgenitor,
alarms: [], alarms: [],
@ -230,23 +228,23 @@ o.spec("CalendarModel", function () {
const uid = "uid" const uid = "uid"
const sender = "sender@example.com" const sender = "sender@example.com"
const anotherGuest = "another-attendee" const anotherGuest = "another-attendee"
const alarm = createAlarmInfo({ const alarm = createTestEntity(AlarmInfoTypeRef, {
_id: "alarm-id", _id: "alarm-id",
}) })
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_id: ["listId", "eventId"], _id: ["listId", "eventId"],
uid, uid,
_ownerGroup: groupRoot._id, _ownerGroup: groupRoot._id,
summary: "v1", summary: "v1",
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: anotherGuest, address: anotherGuest,
}), }),
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
@ -255,7 +253,7 @@ o.spec("CalendarModel", function () {
alarmInfos: [[alarmsListId, alarm._id]], alarmInfos: [[alarmsListId, alarm._id]],
}) })
restClientMock.addListInstances( restClientMock.addListInstances(
createUserAlarmInfo({ createTestEntity(UserAlarmInfoTypeRef, {
_id: [alarmsListId, alarm._id], _id: [alarmsListId, alarm._id],
alarmInfo: alarm, alarmInfo: alarm,
}), }),
@ -278,18 +276,18 @@ o.spec("CalendarModel", function () {
method: CalendarMethod.REPLY, method: CalendarMethod.REPLY,
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
uid, uid,
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
// should be ignored // should be ignored
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: anotherGuest, address: anotherGuest,
}), }),
status: CalendarAttendeeStatus.DECLINED, status: CalendarAttendeeStatus.DECLINED,
@ -308,14 +306,14 @@ o.spec("CalendarModel", function () {
o(createdEvent.uid).equals(existingEvent.uid) o(createdEvent.uid).equals(existingEvent.uid)
o(createdEvent.summary).equals(existingEvent.summary) o(createdEvent.summary).equals(existingEvent.summary)
o(createdEvent.attendees).deepEquals([ o(createdEvent.attendees).deepEquals([
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: "another-attendee", address: "another-attendee",
}), }),
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
@ -343,11 +341,11 @@ o.spec("CalendarModel", function () {
method: CalendarMethod.REQUEST, method: CalendarMethod.REQUEST,
contents: [ contents: [
{ {
event: createCalendarEvent({ event: createTestEntity(CalendarEventTypeRef, {
uid, uid,
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
@ -363,23 +361,23 @@ o.spec("CalendarModel", function () {
o("request as an update", async function () { o("request as an update", async function () {
const uid = "uid" const uid = "uid"
const sender = "sender@example.com" const sender = "sender@example.com"
const alarm = createAlarmInfo({ const alarm = createTestEntity(AlarmInfoTypeRef, {
_id: "alarm-id", _id: "alarm-id",
}) })
restClientMock.addListInstances( restClientMock.addListInstances(
createUserAlarmInfo({ createTestEntity(UserAlarmInfoTypeRef, {
_id: [alarmsListId, alarm._id], _id: [alarmsListId, alarm._id],
alarmInfo: alarm, alarmInfo: alarm,
}), }),
) )
const startTime = new Date() const startTime = new Date()
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_id: ["listId", "eventId"], _id: ["listId", "eventId"],
_ownerGroup: groupRoot._id, _ownerGroup: groupRoot._id,
summary: "v1", summary: "v1",
sequence: "1", sequence: "1",
uid, uid,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
alarmInfos: [[alarmsListId, alarm._id]], alarmInfos: [[alarmsListId, alarm._id]],
@ -398,11 +396,11 @@ o.spec("CalendarModel", function () {
restClientMock, restClientMock,
calendarFacade, calendarFacade,
}) })
const sentEvent = createCalendarEvent({ const sentEvent = createTestEntity(CalendarEventTypeRef, {
summary: "v2", summary: "v2",
uid, uid,
sequence: "2", sequence: "2",
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
startTime, startTime,
@ -431,22 +429,22 @@ o.spec("CalendarModel", function () {
o("event is re-created when the start time changes", async function () { o("event is re-created when the start time changes", async function () {
const uid = "uid" const uid = "uid"
const sender = "sender@example.com" const sender = "sender@example.com"
const alarm = createAlarmInfo({ const alarm = createTestEntity(AlarmInfoTypeRef, {
_id: "alarm-id", _id: "alarm-id",
}) })
restClientMock.addListInstances( restClientMock.addListInstances(
createUserAlarmInfo({ createTestEntity(UserAlarmInfoTypeRef, {
_id: [alarmsListId, alarm._id], _id: [alarmsListId, alarm._id],
alarmInfo: alarm, alarmInfo: alarm,
}), }),
) )
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_id: ["listId", "eventId"], _id: ["listId", "eventId"],
_ownerGroup: groupRoot._id, _ownerGroup: groupRoot._id,
summary: "v1", summary: "v1",
sequence: "1", sequence: "1",
uid, uid,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
startTime: DateTime.fromObject( startTime: DateTime.fromObject(
@ -472,7 +470,7 @@ o.spec("CalendarModel", function () {
restClientMock, restClientMock,
calendarFacade, calendarFacade,
}) })
const sentEvent = createCalendarEvent({ const sentEvent = createTestEntity(CalendarEventTypeRef, {
summary: "v2", summary: "v2",
uid, uid,
sequence: "2", sequence: "2",
@ -484,7 +482,7 @@ o.spec("CalendarModel", function () {
}, },
{ zone: "UTC" }, { zone: "UTC" },
).toJSDate(), ).toJSDate(),
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
}) })
@ -518,12 +516,12 @@ o.spec("CalendarModel", function () {
o("event is cancelled by organizer", async function () { o("event is cancelled by organizer", async function () {
const uid = "uid" const uid = "uid"
const sender = "sender@example.com" const sender = "sender@example.com"
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_id: ["listId", "eventId"], _id: ["listId", "eventId"],
_ownerGroup: groupRoot._id, _ownerGroup: groupRoot._id,
sequence: "1", sequence: "1",
uid, uid,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
}) })
@ -541,10 +539,10 @@ o.spec("CalendarModel", function () {
restClientMock, restClientMock,
calendarFacade: calendarFacade, calendarFacade: calendarFacade,
}) })
const sentEvent = createCalendarEvent({ const sentEvent = createTestEntity(CalendarEventTypeRef, {
uid, uid,
sequence: "2", sequence: "2",
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
}) })
@ -562,12 +560,12 @@ o.spec("CalendarModel", function () {
o("event is cancelled by someone else than organizer", async function () { o("event is cancelled by someone else than organizer", async function () {
const uid = "uid" const uid = "uid"
const sender = "sender@example.com" const sender = "sender@example.com"
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_id: ["listId", "eventId"], _id: ["listId", "eventId"],
_ownerGroup: groupRoot._id, _ownerGroup: groupRoot._id,
sequence: "1", sequence: "1",
uid, uid,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
}) })
@ -577,10 +575,10 @@ o.spec("CalendarModel", function () {
workerClient, workerClient,
restClientMock, restClientMock,
}) })
const sentEvent = createCalendarEvent({ const sentEvent = createTestEntity(CalendarEventTypeRef, {
uid, uid,
sequence: "2", sequence: "2",
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
}) })
@ -597,23 +595,23 @@ o.spec("CalendarModel", function () {
}) })
}) })
o("reprocess deferred calendar events with no owner enc session key", async function () { o("reprocess deferred calendar events with no owner enc session key", async function () {
const calendarFile = createFile({ const calendarFile = createTestEntity(FileTypeRef, {
_id: ["fileListId", "fileId"], _id: ["fileListId", "fileId"],
}) })
const eventUpdate = createCalendarEventUpdate({ const eventUpdate = createTestEntity(CalendarEventUpdateTypeRef, {
_id: ["calendarEventUpdateListId", "calendarEventUpdateId"], _id: ["calendarEventUpdateListId", "calendarEventUpdateId"],
file: calendarFile._id, file: calendarFile._id,
}) })
const uid = "uid" const uid = "uid"
const sender = "sender@example.com" const sender = "sender@example.com"
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_id: ["calendarListId", "eventId"], _id: ["calendarListId", "eventId"],
_ownerGroup: groupRoot._id, _ownerGroup: groupRoot._id,
sequence: "1", sequence: "1",
uid, uid,
organizer: createEncryptedMailAddress({ organizer: createTestEntity(EncryptedMailAddressTypeRef, {
address: sender, address: sender,
}), }),
}) })
@ -717,13 +715,14 @@ function makeWorkerClient(): WorkerClient {
} }
function makeLoginController(props: Partial<UserController> = {}): LoginController { function makeLoginController(props: Partial<UserController> = {}): LoginController {
const alarmInfoList = createTestEntity(UserAlarmInfoListTypeTypeRef, {
alarms: "alarms",
})
const userController = downcast( const userController = downcast(
Object.assign(props, { Object.assign(props, {
user: createUser({ user: createTestEntity(UserTypeRef, {
_id: "user-id", _id: "user-id",
alarmInfoList: createUserAlarmInfoListType({ alarmInfoList,
alarms: "alarms",
}),
}), }),
}), }),
) )

View file

@ -14,9 +14,10 @@ import {
} from "../../../src/calendar/export/CalendarParser.js" } from "../../../src/calendar/export/CalendarParser.js"
import { ParserError, StringIterator } from "../../../src/misc/parsing/ParserCombinator.js" import { ParserError, StringIterator } from "../../../src/misc/parsing/ParserCombinator.js"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { createDateWrapper } from "../../../src/api/entities/sys/TypeRefs.js" import { DateWrapperTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import { getDateInUTC, zone } from "./CalendarTestUtils.js" import { getDateInUTC, zone } from "./CalendarTestUtils.js"
import { AlarmIntervalUnit } from "../../../src/calendar/date/CalendarUtils.js" import { AlarmIntervalUnit } from "../../../src/calendar/date/CalendarUtils.js"
import { createTestEntity } from "../TestUtils.js"
o.spec("CalendarParser", function () { o.spec("CalendarParser", function () {
o.spec("propertySequenceParser", function () { o.spec("propertySequenceParser", function () {
@ -223,15 +224,15 @@ o.spec("CalendarParser", function () {
o("are excluded dates deduplicated", function () { o("are excluded dates deduplicated", function () {
const parsedDates = parseExDates([{ name: "EXDATES", params: {}, value: "20230308T230000Z,20230308T230000Z,20230309T230000Z" }]) const parsedDates = parseExDates([{ name: "EXDATES", params: {}, value: "20230308T230000Z,20230308T230000Z,20230309T230000Z" }])
o(parsedDates).deepEquals([ o(parsedDates).deepEquals([
createDateWrapper({ date: new Date("2023-03-08T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-08T23:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-09T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-09T23:00:00Z") }),
]) ])
}) })
o("are excluded dates sorted", function () { o("are excluded dates sorted", function () {
const parsedDates = parseExDates([{ name: "EXDATES", params: {}, value: "20230313T230000Z,20230309T230000Z" }]) const parsedDates = parseExDates([{ name: "EXDATES", params: {}, value: "20230313T230000Z,20230309T230000Z" }])
o(parsedDates).deepEquals([ o(parsedDates).deepEquals([
createDateWrapper({ date: new Date("2023-03-09T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-09T23:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-13T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-13T23:00:00Z") }),
]) ])
}) })
o("multiple exdates in separate lines are parsed", function () { o("multiple exdates in separate lines are parsed", function () {
@ -244,8 +245,8 @@ o.spec("CalendarParser", function () {
}, },
]) ])
o(parsedDates).deepEquals([ o(parsedDates).deepEquals([
createDateWrapper({ date: new Date("2023-02-03T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-02-03T23:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-09T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-09T23:00:00Z") }),
]) ])
}) })
o("deduplication over multiple lines works", function () { o("deduplication over multiple lines works", function () {
@ -258,16 +259,16 @@ o.spec("CalendarParser", function () {
}, },
]) ])
o(parsedDates).deepEquals([ o(parsedDates).deepEquals([
createDateWrapper({ date: new Date("2023-01-14T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-01-14T23:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-02T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-02T23:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-09T23:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-09T23:00:00Z") }),
]) ])
}) })
o("is timezone parsed", function () { o("is timezone parsed", function () {
const parsedDates = parseExDates([{ name: "EXDATES", params: { TZID: "Europe/Berlin" }, value: "20230309T230000,20230302T230000" }]) const parsedDates = parseExDates([{ name: "EXDATES", params: { TZID: "Europe/Berlin" }, value: "20230309T230000,20230302T230000" }])
o(parsedDates).deepEquals([ o(parsedDates).deepEquals([
createDateWrapper({ date: new Date("2023-03-02T22:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-02T22:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-09T22:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-09T22:00:00Z") }),
]) ])
}) })
o(" deduplication over different timezones", function () { o(" deduplication over different timezones", function () {
@ -275,7 +276,7 @@ o.spec("CalendarParser", function () {
{ name: "EXDATES", params: { TZID: "Europe/Berlin" }, value: "20230309T230000" }, { name: "EXDATES", params: { TZID: "Europe/Berlin" }, value: "20230309T230000" },
{ name: "EXDATES", params: { TZID: "Europe/Sofia" }, value: "20230310T000000" }, { name: "EXDATES", params: { TZID: "Europe/Sofia" }, value: "20230310T000000" },
]) ])
o(parsedDates).deepEquals([createDateWrapper({ date: new Date("2023-03-09T22:00:00Z") })]) o(parsedDates).deepEquals([createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-09T22:00:00Z") })])
}) })
}) })

View file

@ -1,6 +1,7 @@
import { AccountType, ContactAddressType, FeatureType, GroupType, ShareCapability, TimeFormat } from "../../../src/api/common/TutanotaConstants.js" import { AccountType, ContactAddressType, FeatureType, GroupType, ShareCapability, TimeFormat } from "../../../src/api/common/TutanotaConstants.js"
import type { UserController } from "../../../src/api/main/UserController.js" import type { UserController } from "../../../src/api/main/UserController.js"
import { import {
BookingsRefTypeRef,
createBookingsRef, createBookingsRef,
createCustomer, createCustomer,
createCustomerInfo, createCustomerInfo,
@ -11,14 +12,26 @@ import {
createMailAddressAlias, createMailAddressAlias,
createPlanConfiguration, createPlanConfiguration,
createUser, createUser,
CustomerInfoTypeRef,
CustomerTypeRef,
Feature, Feature,
FeatureTypeRef,
GroupInfoTypeRef, GroupInfoTypeRef,
GroupMembershipTypeRef,
GroupTypeRef,
MailAddressAliasTypeRef,
PlanConfigurationTypeRef,
User, User,
UserTypeRef,
} from "../../../src/api/entities/sys/TypeRefs.js" } from "../../../src/api/entities/sys/TypeRefs.js"
import { GENERATED_MAX_ID } from "../../../src/api/common/utils/EntityUtils.js" import { GENERATED_MAX_ID } from "../../../src/api/common/utils/EntityUtils.js"
import { downcast, LazyLoaded } from "@tutao/tutanota-utils" import { downcast, LazyLoaded } from "@tutao/tutanota-utils"
import type { CalendarEvent } from "../../../src/api/entities/tutanota/TypeRefs.js" import type { CalendarEvent } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { import {
CalendarEventTypeRef,
CalendarGroupRootTypeRef,
ContactAddressTypeRef,
ContactTypeRef,
createCalendarEvent, createCalendarEvent,
createCalendarGroupRoot, createCalendarGroupRoot,
createContact, createContact,
@ -28,8 +41,10 @@ import {
createMailboxGroupRoot, createMailboxGroupRoot,
createTutanotaProperties, createTutanotaProperties,
EncryptedMailAddress, EncryptedMailAddress,
EncryptedMailAddressTypeRef,
MailboxGroupRootTypeRef, MailboxGroupRootTypeRef,
MailBoxTypeRef, MailBoxTypeRef,
TutanotaPropertiesTypeRef,
} from "../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../src/api/entities/tutanota/TypeRefs.js"
import type { MailboxDetail } from "../../../src/mail/model/MailModel.js" import type { MailboxDetail } from "../../../src/mail/model/MailModel.js"
import o from "@tutao/otest" import o from "@tutao/otest"
@ -45,7 +60,7 @@ export const ownerMailAddress = "calendarowner@tutanota.de" as const
export const ownerId = "ownerId" as const export const ownerId = "ownerId" as const
export const calendarGroupId = "0" as const export const calendarGroupId = "0" as const
export const ownerAddress = createEncryptedMailAddress({ export const ownerAddress = createTestEntity(EncryptedMailAddressTypeRef, {
address: ownerMailAddress, address: ownerMailAddress,
name: "Calendar Owner", name: "Calendar Owner",
}) })
@ -55,7 +70,7 @@ export const ownerRecipient: Recipient = {
type: RecipientType.INTERNAL, type: RecipientType.INTERNAL,
contact: null, contact: null,
} }
export const ownerAlias = createEncryptedMailAddress({ export const ownerAlias = createTestEntity(EncryptedMailAddressTypeRef, {
address: "calendarowneralias@tutanota.de", address: "calendarowneralias@tutanota.de",
name: "Calendar Owner Alias", name: "Calendar Owner Alias",
}) })
@ -65,7 +80,7 @@ export const ownerAliasRecipient: Recipient = {
type: RecipientType.INTERNAL, type: RecipientType.INTERNAL,
contact: null, contact: null,
} }
export const otherAddress = createEncryptedMailAddress({ export const otherAddress = createTestEntity(EncryptedMailAddressTypeRef, {
address: "someone@tutanota.de", address: "someone@tutanota.de",
name: "Some One", name: "Some One",
}) })
@ -73,18 +88,18 @@ export const otherRecipient: Recipient = {
address: otherAddress.address, address: otherAddress.address,
name: otherAddress.name, name: otherAddress.name,
type: RecipientType.EXTERNAL, type: RecipientType.EXTERNAL,
contact: createContact({ contact: createTestEntity(ContactTypeRef, {
nickname: otherAddress.name, nickname: otherAddress.name,
presharedPassword: "otherPassword", presharedPassword: "otherPassword",
addresses: [ addresses: [
createContactAddress({ createTestEntity(ContactAddressTypeRef, {
address: otherAddress.address, address: otherAddress.address,
type: ContactAddressType.WORK, type: ContactAddressType.WORK,
}), }),
], ],
}), }),
} }
export const otherAddress2 = createEncryptedMailAddress({ export const otherAddress2 = createTestEntity(EncryptedMailAddressTypeRef, {
address: "someoneelse@tutanota.de", address: "someoneelse@tutanota.de",
name: "Some One Else", name: "Some One Else",
}) })
@ -92,11 +107,11 @@ export const otherRecipient2: Recipient = {
address: otherAddress2.address, address: otherAddress2.address,
name: otherAddress2.name, name: otherAddress2.name,
type: RecipientType.INTERNAL, type: RecipientType.INTERNAL,
contact: createContact({ contact: createTestEntity(ContactTypeRef, {
nickname: otherAddress2.name, nickname: otherAddress2.name,
presharedPassword: "otherPassword2", presharedPassword: "otherPassword2",
addresses: [ addresses: [
createContactAddress({ createTestEntity(ContactAddressTypeRef, {
address: otherAddress2.address, address: otherAddress2.address,
type: ContactAddressType.WORK, type: ContactAddressType.WORK,
}), }),
@ -104,16 +119,16 @@ export const otherRecipient2: Recipient = {
}), }),
} }
export const thirdAddress = createEncryptedMailAddress({ address: "somethirdaddress@tuta.com", name: "thirdperson" }) export const thirdAddress = createTestEntity(EncryptedMailAddressTypeRef, { address: "somethirdaddress@tuta.com", name: "thirdperson" })
export const thirdRecipient: Recipient = { export const thirdRecipient: Recipient = {
address: thirdAddress.address, address: thirdAddress.address,
name: thirdAddress.name, name: thirdAddress.name,
type: RecipientType.INTERNAL, type: RecipientType.INTERNAL,
contact: createContact({ contact: createTestEntity(ContactTypeRef, {
nickname: "drei", nickname: "drei",
presharedPassword: "noPassword", presharedPassword: "noPassword",
addresses: [ addresses: [
createContactAddress({ createTestEntity(ContactAddressTypeRef, {
address: thirdAddress.address, address: thirdAddress.address,
type: ContactAddressType.OTHER, type: ContactAddressType.OTHER,
}), }),
@ -125,11 +140,11 @@ export const calendars: ReadonlyMap<Id, CalendarInfo> = new Map([
[ [
"ownCalendar", "ownCalendar",
{ {
groupRoot: createCalendarGroupRoot({}), groupRoot: createTestEntity(CalendarGroupRootTypeRef, {}),
shared: false, shared: false,
longEvents: new LazyLoaded(() => Promise.resolve([])), longEvents: new LazyLoaded(() => Promise.resolve([])),
groupInfo: createGroupInfo({}), groupInfo: createTestEntity(GroupInfoTypeRef, {}),
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "ownCalendar", _id: "ownCalendar",
user: "ownerId", user: "ownerId",
type: GroupType.Calendar, type: GroupType.Calendar,
@ -139,11 +154,11 @@ export const calendars: ReadonlyMap<Id, CalendarInfo> = new Map([
[ [
"sharedCalendar", "sharedCalendar",
{ {
groupRoot: createCalendarGroupRoot({}), groupRoot: createTestEntity(CalendarGroupRootTypeRef, {}),
shared: true, shared: true,
longEvents: new LazyLoaded(() => Promise.resolve([])), longEvents: new LazyLoaded(() => Promise.resolve([])),
groupInfo: createGroupInfo({}), groupInfo: createTestEntity(GroupInfoTypeRef, {}),
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "sharedCalendar", _id: "sharedCalendar",
user: "otherId", user: "otherId",
type: GroupType.Calendar, type: GroupType.Calendar,
@ -161,38 +176,38 @@ export function makeUserController(
businessFeatureOrdered: boolean = false, businessFeatureOrdered: boolean = false,
isNewPaidPlan: boolean = false, isNewPaidPlan: boolean = false,
): UserController { ): UserController {
const bookingsRef = createBookingsRef({ const bookingsRef = createTestEntity(BookingsRefTypeRef, {
items: GENERATED_MAX_ID, items: GENERATED_MAX_ID,
}) })
const customizations: Feature[] = [] const customizations: Feature[] = []
if (businessFeatureOrdered) { if (businessFeatureOrdered) {
customizations.push( customizations.push(
createFeature({ createTestEntity(FeatureTypeRef, {
feature: FeatureType.BusinessFeatureEnabled, feature: FeatureType.BusinessFeatureEnabled,
}), }),
) )
} }
return downcast({ return downcast({
user: createUser({ user: createTestEntity(UserTypeRef, {
_id: ownerId, _id: ownerId,
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
groupType: GroupType.Mail, groupType: GroupType.Mail,
}), }),
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
groupType: GroupType.Contact, groupType: GroupType.Contact,
}), }),
], ],
accountType, accountType,
}), }),
props: createTutanotaProperties({ props: createTestEntity(TutanotaPropertiesTypeRef, {
defaultSender: defaultSender || ownerMailAddress, defaultSender: defaultSender || ownerMailAddress,
}), }),
userGroupInfo: createGroupInfo({ userGroupInfo: createTestEntity(GroupInfoTypeRef, {
mailAddressAliases: aliases.map((address) => mailAddressAliases: aliases.map((address) =>
createMailAddressAlias({ createTestEntity(MailAddressAliasTypeRef, {
mailAddress: address, mailAddress: address,
enabled: true, enabled: true,
}), }),
@ -207,13 +222,13 @@ export function makeUserController(
isNewPaidPlan: () => isNewPaidPlan, isNewPaidPlan: () => isNewPaidPlan,
loadCustomer: () => loadCustomer: () =>
Promise.resolve( Promise.resolve(
createCustomer({ createTestEntity(CustomerTypeRef, {
customizations: customizations, customizations: customizations,
}), }),
), ),
loadCustomerInfo: () => loadCustomerInfo: () =>
Promise.resolve( Promise.resolve(
createCustomerInfo({ createTestEntity(CustomerInfoTypeRef, {
bookings: bookingsRef, bookings: bookingsRef,
}), }),
), ),
@ -223,7 +238,7 @@ export function makeUserController(
}, },
getPlanConfig: () => getPlanConfig: () =>
Promise.resolve( Promise.resolve(
createPlanConfiguration({ createTestEntity(PlanConfigurationTypeRef, {
eventInvites: businessFeatureOrdered || isNewPaidPlan, eventInvites: businessFeatureOrdered || isNewPaidPlan,
}), }),
), ),
@ -235,7 +250,7 @@ export function makeMailboxDetail(): MailboxDetail {
mailbox: createTestEntity(MailBoxTypeRef), mailbox: createTestEntity(MailBoxTypeRef),
folders: new FolderSystem([]), folders: new FolderSystem([]),
mailGroupInfo: createTestEntity(GroupInfoTypeRef), mailGroupInfo: createTestEntity(GroupInfoTypeRef),
mailGroup: createGroup({ mailGroup: createTestEntity(GroupTypeRef, {
user: ownerId, user: ownerId,
}), }),
mailboxGroupRoot: createTestEntity(MailboxGroupRootTypeRef), mailboxGroupRoot: createTestEntity(MailboxGroupRootTypeRef),
@ -250,7 +265,7 @@ export function makeCalendarInfo(type: "own" | "shared", id: string): CalendarIn
}), }),
longEvents: new LazyLoaded(() => Promise.resolve([])), longEvents: new LazyLoaded(() => Promise.resolve([])),
groupInfo: downcast({}), groupInfo: downcast({}),
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: id, _id: id,
type: GroupType.Calendar, type: GroupType.Calendar,
user: type === "own" ? ownerId : "anotherUserId", user: type === "own" ? ownerId : "anotherUserId",
@ -285,7 +300,7 @@ function id(element: string): IdTuple {
} }
export function makeEvent(_id: string, startTime: Date, endTime: Date, uid: string = ""): CalendarEvent { export function makeEvent(_id: string, startTime: Date, endTime: Date, uid: string = ""): CalendarEvent {
return createCalendarEvent({ return createTestEntity(CalendarEventTypeRef, {
_ownerGroup: "ownerGroup", _ownerGroup: "ownerGroup",
_id: id(_id), _id: id(_id),
startTime, startTime,
@ -296,7 +311,7 @@ export function makeEvent(_id: string, startTime: Date, endTime: Date, uid: stri
export function addCapability(user: User, groupId: Id, capability: ShareCapability) { export function addCapability(user: User, groupId: Id, capability: ShareCapability) {
user.memberships.push( user.memberships.push(
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
group: groupId, group: groupId,
capability, capability,
}), }),

View file

@ -29,7 +29,7 @@ import {
StandardAlarmInterval, StandardAlarmInterval,
} from "../../../src/calendar/date/CalendarUtils.js" } from "../../../src/calendar/date/CalendarUtils.js"
import { lang } from "../../../src/misc/LanguageViewModel.js" import { lang } from "../../../src/misc/LanguageViewModel.js"
import { createDateWrapper, createGroup, createGroupMembership, createUser, User } from "../../../src/api/entities/sys/TypeRefs.js" import { DateWrapperTypeRef, GroupMembershipTypeRef, GroupTypeRef, User, UserTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import { AccountType, EndType, GroupType, RepeatPeriod, ShareCapability } from "../../../src/api/common/TutanotaConstants.js" import { AccountType, EndType, GroupType, RepeatPeriod, ShareCapability } from "../../../src/api/common/TutanotaConstants.js"
import { timeStringFromParts } from "../../../src/misc/Formatter.js" import { timeStringFromParts } from "../../../src/misc/Formatter.js"
import { DateTime } from "luxon" import { DateTime } from "luxon"
@ -37,11 +37,11 @@ import { generateEventElementId, getAllDayDateUTC } from "../../../src/api/commo
import { hasCapabilityOnGroup } from "../../../src/sharing/GroupUtils.js" import { hasCapabilityOnGroup } from "../../../src/sharing/GroupUtils.js"
import type { CalendarEvent } from "../../../src/api/entities/tutanota/TypeRefs.js" import type { CalendarEvent } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { import {
CalendarEventAttendeeTypeRef,
CalendarEventTypeRef, CalendarEventTypeRef,
createCalendarEvent, CalendarRepeatRuleTypeRef,
createCalendarEventAttendee,
createCalendarRepeatRule, createCalendarRepeatRule,
createEncryptedMailAddress, EncryptedMailAddressTypeRef,
} from "../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { clone, getStartOfDay, identity, lastThrow, neverNull } from "@tutao/tutanota-utils" import { clone, getStartOfDay, identity, lastThrow, neverNull } from "@tutao/tutanota-utils"
import { Time } from "../../../src/calendar/date/Time.js" import { Time } from "../../../src/calendar/date/Time.js"
@ -427,22 +427,23 @@ o.spec("calendar utils tests", function () {
let groupMembership let groupMembership
let groupOwnerMembership let groupOwnerMembership
o.before(function () { o.before(function () {
group = createGroup({ // @ts-ignore
group = createTestEntity(GroupTypeRef, {
_id: "g1", _id: "g1",
type: GroupType.Calendar, type: GroupType.Calendar,
user: "groupOwner", user: "groupOwner",
}) })
groupMembership = createGroupMembership({ groupMembership = createTestEntity(GroupMembershipTypeRef, {
group: group._id, group: group._id,
}) })
groupOwnerMembership = createGroupMembership({ groupOwnerMembership = createTestEntity(GroupMembershipTypeRef, {
group: group._id, group: group._id,
}) })
ownerUser = createUser({ ownerUser = createTestEntity(UserTypeRef, {
_id: "groupOwner", _id: "groupOwner",
memberships: [groupOwnerMembership], memberships: [groupOwnerMembership],
}) })
user = createUser({ user = createTestEntity(UserTypeRef, {
_id: "groupMember", _id: "groupMember",
memberships: [groupMembership], memberships: [groupMembership],
}) })
@ -679,7 +680,7 @@ o.spec("calendar utils tests", function () {
const zone = getTimeZone() const zone = getTimeZone()
function eventOn(start: Date, end: Date): CalendarEvent { function eventOn(start: Date, end: Date): CalendarEvent {
return createCalendarEvent({ return createTestEntity(CalendarEventTypeRef, {
startTime: start, startTime: start,
endTime: end, endTime: end,
}) })
@ -734,7 +735,7 @@ o.spec("calendar utils tests", function () {
o("events with invalid dates are detected", function () { o("events with invalid dates are detected", function () {
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("nan"), startTime: new Date("nan"),
endTime: new Date("1990"), endTime: new Date("1990"),
}), }),
@ -742,7 +743,7 @@ o.spec("calendar utils tests", function () {
).equals(CalendarEventValidity.InvalidContainsInvalidDate) ).equals(CalendarEventValidity.InvalidContainsInvalidDate)
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("1991"), startTime: new Date("1991"),
endTime: new Date("nan"), endTime: new Date("nan"),
}), }),
@ -750,7 +751,7 @@ o.spec("calendar utils tests", function () {
).equals(CalendarEventValidity.InvalidContainsInvalidDate) ).equals(CalendarEventValidity.InvalidContainsInvalidDate)
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("nan"), startTime: new Date("nan"),
endTime: new Date("nan"), endTime: new Date("nan"),
}), }),
@ -760,7 +761,7 @@ o.spec("calendar utils tests", function () {
o("events with start date not before end date are detected", function () { o("events with start date not before end date are detected", function () {
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("1990"), startTime: new Date("1990"),
endTime: new Date("1990"), endTime: new Date("1990"),
}), }),
@ -768,7 +769,7 @@ o.spec("calendar utils tests", function () {
).equals(CalendarEventValidity.InvalidEndBeforeStart) ).equals(CalendarEventValidity.InvalidEndBeforeStart)
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("1990"), startTime: new Date("1990"),
endTime: new Date("1980"), endTime: new Date("1980"),
}), }),
@ -778,7 +779,7 @@ o.spec("calendar utils tests", function () {
o("events with date before 1970 are detected", function () { o("events with date before 1970 are detected", function () {
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("1969"), startTime: new Date("1969"),
endTime: new Date("1990"), endTime: new Date("1990"),
}), }),
@ -786,7 +787,7 @@ o.spec("calendar utils tests", function () {
).equals(CalendarEventValidity.InvalidPre1970) ).equals(CalendarEventValidity.InvalidPre1970)
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("1960"), startTime: new Date("1960"),
endTime: new Date("1966"), endTime: new Date("1966"),
}), }),
@ -794,7 +795,7 @@ o.spec("calendar utils tests", function () {
).equals(CalendarEventValidity.InvalidPre1970) ).equals(CalendarEventValidity.InvalidPre1970)
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("1970"), startTime: new Date("1970"),
endTime: new Date("1966"), endTime: new Date("1966"),
}), }),
@ -804,7 +805,7 @@ o.spec("calendar utils tests", function () {
o("valid events are detected", function () { o("valid events are detected", function () {
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: getDateInUTC("1970"), startTime: getDateInUTC("1970"),
endTime: getDateInUTC("1990"), endTime: getDateInUTC("1990"),
}), }),
@ -812,7 +813,7 @@ o.spec("calendar utils tests", function () {
).equals(CalendarEventValidity.Valid)("events on the cusp of 1970 UTC are valid") ).equals(CalendarEventValidity.Valid)("events on the cusp of 1970 UTC are valid")
o( o(
checkEventValidity( checkEventValidity(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: getDateInZone("1971"), startTime: getDateInZone("1971"),
endTime: getDateInZone("2022"), endTime: getDateInZone("2022"),
}), }),
@ -934,7 +935,7 @@ o.spec("calendar utils tests", function () {
event.repeatRule.endValue = "2" event.repeatRule.endValue = "2"
addDaysForRecurringEvent(eventsForDays, event, getMonthRange(getDateInZone("2023-07-01"), zone), zone) addDaysForRecurringEvent(eventsForDays, event, getMonthRange(getDateInZone("2023-07-01"), zone), zone)
o(countDaysWithEvents(eventsForDays)).equals(2) o(countDaysWithEvents(eventsForDays)).equals(2)
event.repeatRule.excludedDates = [createDateWrapper({ date: getDateInZone("2023-07-21T12:00") })] event.repeatRule.excludedDates = [createTestEntity(DateWrapperTypeRef, { date: getDateInZone("2023-07-21T12:00") })]
addDaysForRecurringEvent(eventsForDays, event, getMonthRange(getDateInZone("2023-07-01"), zone), zone) addDaysForRecurringEvent(eventsForDays, event, getMonthRange(getDateInZone("2023-07-01"), zone), zone)
o(countDaysWithEvents(eventsForDays)).equals(1) o(countDaysWithEvents(eventsForDays)).equals(1)
}) })
@ -1317,7 +1318,7 @@ o.spec("calendar utils tests", function () {
const repeatRule = createRepeatRuleWithValues(RepeatPeriod.DAILY, 1, zone) const repeatRule = createRepeatRuleWithValues(RepeatPeriod.DAILY, 1, zone)
repeatRule.endValue = "2" repeatRule.endValue = "2"
repeatRule.endType = EndType.Count repeatRule.endType = EndType.Count
repeatRule.excludedDates = [createDateWrapper({ date: event.startTime })] repeatRule.excludedDates = [createTestEntity(DateWrapperTypeRef, { date: event.startTime })]
event.repeatRule = repeatRule event.repeatRule = repeatRule
const alteredEvent = clone(event) const alteredEvent = clone(event)
alteredEvent._id = ["shortEvents", generateEventElementId(alteredEvent.startTime.getTime())] alteredEvent._id = ["shortEvents", generateEventElementId(alteredEvent.startTime.getTime())]
@ -1441,30 +1442,34 @@ o.spec("calendar utils tests", function () {
}) })
o.spec("calendarEventHasMoreThanOneOccurrencesLeft", function () { o.spec("calendarEventHasMoreThanOneOccurrencesLeft", function () {
o("event without end condition has more than one occurrence", function () { o("event without end condition has more than one occurrence", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.Never, endType: EndType.Never,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
}) })
const progenitor = createCalendarEvent({ startTime: new Date(), endTime: new Date(), repeatRule }) as CalendarEventProgenitor const progenitor = createTestEntity(CalendarEventTypeRef, { startTime: new Date(), endTime: new Date(), repeatRule }) as CalendarEventProgenitor
o(calendarEventHasMoreThanOneOccurrencesLeft({ progenitor, ownerGroup: "", alteredInstances: [] })).equals(true) o(calendarEventHasMoreThanOneOccurrencesLeft({ progenitor, ownerGroup: "", alteredInstances: [] })).equals(true)
}) })
o("event without repeat rule has less than two occurrences", function () { o("event without repeat rule has less than two occurrences", function () {
const progenitor = createCalendarEvent({ startTime: new Date(), endTime: new Date(), repeatRule: null }) as CalendarEventProgenitor const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date(),
endTime: new Date(),
repeatRule: null,
}) as CalendarEventProgenitor
o(calendarEventHasMoreThanOneOccurrencesLeft({ progenitor, ownerGroup: "", alteredInstances: [] })).equals(false) o(calendarEventHasMoreThanOneOccurrencesLeft({ progenitor, ownerGroup: "", alteredInstances: [] })).equals(false)
}) })
o("event with higher count than exclusions+1 has more left", function () { o("event with higher count than exclusions+1 has more left", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endValue: "3", endValue: "3",
excludedDates: [createDateWrapper({ date: new Date("2023-03-03T22:00:00Z") })], excludedDates: [createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-03T22:00:00Z") })],
timeZone: zone, timeZone: zone,
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1473,15 +1478,18 @@ o.spec("calendar utils tests", function () {
}) })
o("event with count and enough exclusions has less than two left", function () { o("event with count and enough exclusions has less than two left", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endValue: "3", endValue: "3",
excludedDates: [createDateWrapper({ date: new Date("2023-03-03T22:00:00Z") }), createDateWrapper({ date: new Date("2023-03-04T22:00:00Z") })], excludedDates: [
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-03T22:00:00Z") }),
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-04T22:00:00Z") }),
],
timeZone: zone, timeZone: zone,
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1490,15 +1498,18 @@ o.spec("calendar utils tests", function () {
}) })
o("event with count and enough exclusions has less than two left, first is excluded", function () { o("event with count and enough exclusions has less than two left, first is excluded", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endValue: "3", endValue: "3",
excludedDates: [createDateWrapper({ date: new Date("2023-03-02T22:00:00Z") }), createDateWrapper({ date: new Date("2023-03-04T22:00:00Z") })], excludedDates: [
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-02T22:00:00Z") }),
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-04T22:00:00Z") }),
],
timeZone: zone, timeZone: zone,
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1522,9 +1533,12 @@ o.spec("calendar utils tests", function () {
).toMillis(), ).toMillis(),
), ),
timeZone: zone, timeZone: zone,
excludedDates: [createDateWrapper({ date: new Date("2023-03-02T22:00:00Z") }), createDateWrapper({ date: new Date("2023-03-04T22:00:00Z") })], excludedDates: [
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-02T22:00:00Z") }),
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-04T22:00:00Z") }),
],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1548,9 +1562,12 @@ o.spec("calendar utils tests", function () {
).toMillis(), ).toMillis(),
), ),
timeZone: zone, timeZone: zone,
excludedDates: [createDateWrapper({ date: new Date("2023-03-02T22:00:00Z") }), createDateWrapper({ date: new Date("2023-03-04T22:00:00Z") })], excludedDates: [
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-02T22:00:00Z") }),
createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-04T22:00:00Z") }),
],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1575,15 +1592,15 @@ o.spec("calendar utils tests", function () {
), ),
timeZone: zone, timeZone: zone,
excludedDates: [ excludedDates: [
createDateWrapper({ date: new Date("2023-03-02T22:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-02T22:00:00Z") }),
// 2023-03-03T22:00:00Z not excluded // 2023-03-03T22:00:00Z not excluded
createDateWrapper({ date: new Date("2023-03-04T22:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-04T22:00:00Z") }),
createDateWrapper({ date: new Date("2023-03-05T22:00:00Z") }), createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-05T22:00:00Z") }),
// 2023-03-06T22:00:00Z not excluded // 2023-03-06T22:00:00Z not excluded
// 2023-03-07T22:00:00Z not excluded // 2023-03-07T22:00:00Z not excluded
], ],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1598,18 +1615,18 @@ o.spec("calendar utils tests", function () {
}) })
o("event with end date after 2 occurrences and an altered instance is considered to have more than one occurrence", function () { o("event with end date after 2 occurrences and an altered instance is considered to have more than one occurrence", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.UntilDate, endType: EndType.UntilDate,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endValue: getDateInUTC("2023-03-04").getTime().toString(), endValue: getDateInUTC("2023-03-04").getTime().toString(),
timeZone: zone, timeZone: zone,
excludedDates: [ excludedDates: [
createDateWrapper({ date: getDateInZone("2023-03-02T22:00") }), createTestEntity(DateWrapperTypeRef, { date: getDateInZone("2023-03-02T22:00") }),
// 2023-03-03T22:00:00Z not excluded // 2023-03-03T22:00:00Z not excluded
], ],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: getDateInZone("2023-03-02T22:00"), startTime: getDateInZone("2023-03-02T22:00"),
endTime: getDateInZone("2023-03-02T23:00"), endTime: getDateInZone("2023-03-02T23:00"),
repeatRule, repeatRule,
@ -1624,15 +1641,15 @@ o.spec("calendar utils tests", function () {
}) })
o("event with exclusions that are not occurrences", function () { o("event with exclusions that are not occurrences", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "2", interval: "2",
endValue: "2", endValue: "2",
timeZone: zone, timeZone: zone,
excludedDates: [createDateWrapper({ date: new Date("2023-03-03T22:00:00Z") })], excludedDates: [createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-03T22:00:00Z") })],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1641,7 +1658,7 @@ o.spec("calendar utils tests", function () {
}) })
o("event with one occurrence (count), no exclusions", function () { o("event with one occurrence (count), no exclusions", function () {
const repeatRule = createCalendarRepeatRule({ const repeatRule = createTestEntity(CalendarRepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
@ -1649,7 +1666,7 @@ o.spec("calendar utils tests", function () {
timeZone: zone, timeZone: zone,
excludedDates: [], excludedDates: [],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1675,7 +1692,7 @@ o.spec("calendar utils tests", function () {
timeZone: zone, timeZone: zone,
excludedDates: [], excludedDates: [],
}) })
const progenitor = createCalendarEvent({ const progenitor = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-02T22:00:00Z"), startTime: new Date("2023-03-02T22:00:00Z"),
endTime: new Date("2023-03-02T23:00:00Z"), endTime: new Date("2023-03-02T23:00:00Z"),
repeatRule, repeatRule,
@ -1694,7 +1711,7 @@ o.spec("calendar utils tests", function () {
}) })
o("if no ownergroup but organizer, gets OWN", function () { o("if no ownergroup but organizer, gets OWN", function () {
const event: Partial<CalendarEvent> = { organizer: createEncryptedMailAddress({ address: "my@address.to", name: "my" }) } const event: Partial<CalendarEvent> = { organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "my@address.to", name: "my" }) }
const calendars = new Map() const calendars = new Map()
const ownMailAddresses = ["my@address.to"] const ownMailAddresses = ["my@address.to"]
const user: User = object() const user: User = object()
@ -1703,7 +1720,7 @@ o.spec("calendar utils tests", function () {
}) })
o("if no ownergroup and not organizer, gets INVITE", function () { o("if no ownergroup and not organizer, gets INVITE", function () {
const event: Partial<CalendarEvent> = { organizer: createEncryptedMailAddress({ address: "no@address.to", name: "my" }) } const event: Partial<CalendarEvent> = { organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "no@address.to", name: "my" }) }
const calendars = new Map() const calendars = new Map()
const ownMailAddresses = ["my@address.to"] const ownMailAddresses = ["my@address.to"]
const user: User = object() const user: User = object()
@ -1712,7 +1729,10 @@ o.spec("calendar utils tests", function () {
}) })
o("event in not any of our calendars gets SHARED_RO", function () { o("event in not any of our calendars gets SHARED_RO", function () {
const event: Partial<CalendarEvent> = { organizer: createEncryptedMailAddress({ address: "no@address.to", name: "my" }), _ownerGroup: "ownergroup" } const event: Partial<CalendarEvent> = {
organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "no@address.to", name: "my" }),
_ownerGroup: "ownergroup",
}
const calendars = new Map() const calendars = new Map()
const ownMailAddresses = ["my@address.to"] const ownMailAddresses = ["my@address.to"]
const user: User = object() const user: User = object()
@ -1721,11 +1741,14 @@ o.spec("calendar utils tests", function () {
}) })
o("event in rw-shared calendar w/o attendees gets SHARED_RW", function () { o("event in rw-shared calendar w/o attendees gets SHARED_RW", function () {
const event: Partial<CalendarEvent> = { organizer: createEncryptedMailAddress({ address: "no@address.to", name: "my" }), _ownerGroup: "ownergroup" } const event: Partial<CalendarEvent> = {
organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "no@address.to", name: "my" }),
_ownerGroup: "ownergroup",
}
const calendars = new Map() const calendars = new Map()
calendars.set("ownergroup", { calendars.set("ownergroup", {
shared: true, shared: true,
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "calendarGroup", _id: "calendarGroup",
type: GroupType.Calendar, type: GroupType.Calendar,
user: "otherUser", user: "otherUser",
@ -1735,7 +1758,7 @@ o.spec("calendar utils tests", function () {
const user: User = object() const user: User = object()
user.accountType = AccountType.PAID user.accountType = AccountType.PAID
user.memberships = [ user.memberships = [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
group: "calendarGroup", group: "calendarGroup",
capability: ShareCapability.Write, capability: ShareCapability.Write,
}), }),
@ -1746,14 +1769,18 @@ o.spec("calendar utils tests", function () {
o("event in rw-shared calendar w attendees gets LOCKED", function () { o("event in rw-shared calendar w attendees gets LOCKED", function () {
const event: Partial<CalendarEvent> = { const event: Partial<CalendarEvent> = {
organizer: createEncryptedMailAddress({ address: "no@address.to", name: "my" }), organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "no@address.to", name: "my" }),
_ownerGroup: "ownergroup", _ownerGroup: "ownergroup",
attendees: [createCalendarEventAttendee({ address: createEncryptedMailAddress({ address: "bla", name: "blabla" }) })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, {
address: createTestEntity(EncryptedMailAddressTypeRef, { address: "bla", name: "blabla" }),
}),
],
} }
const calendars = new Map() const calendars = new Map()
calendars.set("ownergroup", { calendars.set("ownergroup", {
shared: true, shared: true,
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "calendarGroup", _id: "calendarGroup",
type: GroupType.Calendar, type: GroupType.Calendar,
user: "otherUser", user: "otherUser",
@ -1763,7 +1790,7 @@ o.spec("calendar utils tests", function () {
const user: User = object() const user: User = object()
user.accountType = AccountType.PAID user.accountType = AccountType.PAID
user.memberships = [ user.memberships = [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
group: "calendarGroup", group: "calendarGroup",
capability: ShareCapability.Write, capability: ShareCapability.Write,
}), }),
@ -1774,14 +1801,18 @@ o.spec("calendar utils tests", function () {
o("event with ownergroup in own calendar where we're organizer gets OWN", function () { o("event with ownergroup in own calendar where we're organizer gets OWN", function () {
const event: Partial<CalendarEvent> = { const event: Partial<CalendarEvent> = {
organizer: createEncryptedMailAddress({ address: "my@address.to", name: "my" }), organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "my@address.to", name: "my" }),
_ownerGroup: "ownergroup", _ownerGroup: "ownergroup",
attendees: [createCalendarEventAttendee({ address: createEncryptedMailAddress({ address: "bla", name: "blabla" }) })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, {
address: createTestEntity(EncryptedMailAddressTypeRef, { address: "bla", name: "blabla" }),
}),
],
} }
const calendars = new Map() const calendars = new Map()
calendars.set("ownergroup", { calendars.set("ownergroup", {
shared: false, shared: false,
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "calendarGroup", _id: "calendarGroup",
type: GroupType.Calendar, type: GroupType.Calendar,
user: "userId", user: "userId",
@ -1798,14 +1829,16 @@ o.spec("calendar utils tests", function () {
o("event with ownergroup in ro-shared calendar gets shared_ro", function () { o("event with ownergroup in ro-shared calendar gets shared_ro", function () {
const event: Partial<CalendarEvent> = { const event: Partial<CalendarEvent> = {
organizer: createEncryptedMailAddress({ address: "no@address.to", name: "my" }), organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "no@address.to", name: "my" }),
_ownerGroup: "ownergroup", _ownerGroup: "ownergroup",
attendees: [createCalendarEventAttendee({ address: createEncryptedMailAddress({ address: "bla", name: "blabla" }) })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, { address: createTestEntity(EncryptedMailAddressTypeRef, { address: "bla", name: "blabla" }) }),
],
} }
const calendars = new Map() const calendars = new Map()
calendars.set("ownergroup", { calendars.set("ownergroup", {
shared: true, shared: true,
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "calendarGroup", _id: "calendarGroup",
type: GroupType.Calendar, type: GroupType.Calendar,
user: "otherUser", user: "otherUser",
@ -1815,7 +1848,7 @@ o.spec("calendar utils tests", function () {
const user: User = object() const user: User = object()
user.accountType = AccountType.PAID user.accountType = AccountType.PAID
user.memberships = [ user.memberships = [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
group: "calendarGroup", group: "calendarGroup",
capability: ShareCapability.Read, capability: ShareCapability.Read,
}), }),
@ -1826,14 +1859,16 @@ o.spec("calendar utils tests", function () {
o("event with ownergroup in own calendar and a different organizer gets INVITE", function () { o("event with ownergroup in own calendar and a different organizer gets INVITE", function () {
const event: Partial<CalendarEvent> = { const event: Partial<CalendarEvent> = {
organizer: createEncryptedMailAddress({ address: "other@address.to", name: "other" }), organizer: createTestEntity(EncryptedMailAddressTypeRef, { address: "other@address.to", name: "other" }),
_ownerGroup: "ownergroup", _ownerGroup: "ownergroup",
attendees: [createCalendarEventAttendee({ address: createEncryptedMailAddress({ address: "bla", name: "blabla" }) })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, { address: createTestEntity(EncryptedMailAddressTypeRef, { address: "bla", name: "blabla" }) }),
],
} }
const calendars = new Map() const calendars = new Map()
calendars.set("ownergroup", { calendars.set("ownergroup", {
shared: false, shared: false,
group: createGroup({ group: createTestEntity(GroupTypeRef, {
_id: "calendarGroup", _id: "calendarGroup",
type: GroupType.Calendar, type: GroupType.Calendar,
user: "userId", user: "userId",

View file

@ -14,17 +14,23 @@ import {
import { CalendarNotificationSender } from "../../../../src/calendar/date/CalendarNotificationSender.js" import { CalendarNotificationSender } from "../../../../src/calendar/date/CalendarNotificationSender.js"
import { CalendarModel } from "../../../../src/calendar/model/CalendarModel.js" import { CalendarModel } from "../../../../src/calendar/model/CalendarModel.js"
import { import {
CalendarEventAttendeeTypeRef,
CalendarEventTypeRef,
createCalendarEvent, createCalendarEvent,
createCalendarEventAttendee, createCalendarEventAttendee,
createEncryptedMailAddress, createEncryptedMailAddress,
createMailboxProperties, createMailboxProperties,
EncryptedMailAddressTypeRef,
MailboxGroupRootTypeRef, MailboxGroupRootTypeRef,
MailboxProperties, MailboxProperties,
MailboxPropertiesTypeRef,
MailBoxTypeRef, MailBoxTypeRef,
} from "../../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../../src/api/entities/tutanota/TypeRefs.js"
import { EntityClient } from "../../../../src/api/common/EntityClient.js" import { EntityClient } from "../../../../src/api/common/EntityClient.js"
import { calendars, getDateInZone, makeUserController, otherAddress, ownerAddress, ownerAlias, ownerId, ownerMailAddress } from "../CalendarTestUtils.js" import { calendars, getDateInZone, makeUserController, otherAddress, ownerAddress, ownerAlias, ownerId, ownerMailAddress } from "../CalendarTestUtils.js"
import { import {
AlarmInfoTypeRef,
CalendarEventRefTypeRef,
createAlarmInfo, createAlarmInfo,
createCalendarEventRef, createCalendarEventRef,
createDateWrapper, createDateWrapper,
@ -32,7 +38,11 @@ import {
createRepeatRule, createRepeatRule,
createUserAlarmInfo, createUserAlarmInfo,
DateWrapper, DateWrapper,
DateWrapperTypeRef,
GroupInfoTypeRef, GroupInfoTypeRef,
GroupTypeRef,
RepeatRuleTypeRef,
UserAlarmInfoTypeRef,
} from "../../../../src/api/entities/sys/TypeRefs.js" } from "../../../../src/api/entities/sys/TypeRefs.js"
import { clone, identity, noOp } from "@tutao/tutanota-utils" import { clone, identity, noOp } from "@tutao/tutanota-utils"
import { RecipientsModel, ResolvableRecipient, ResolveMode } from "../../../../src/api/main/RecipientsModel.js" import { RecipientsModel, ResolvableRecipient, ResolveMode } from "../../../../src/api/main/RecipientsModel.js"
@ -68,7 +78,7 @@ o.spec("CalendarEventModelTest", function () {
o.spec("integration tests", function () { o.spec("integration tests", function () {
o("doing no edit operation on an existing event updates it as expected, no updates.", async function () { o("doing no edit operation on an existing event updates it as expected, no updates.", async function () {
// this test case is insane and only serves as a warning example to not do such things. // this test case is insane and only serves as a warning example to not do such things.
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
sequence: "0", sequence: "0",
_id: ["eventListId", "eventElementId"], _id: ["eventListId", "eventElementId"],
_ownerGroup: "ownCalendar", _ownerGroup: "ownCalendar",
@ -81,7 +91,7 @@ o.spec("CalendarEventModelTest", function () {
startTime: new Date("2023-04-27T15:00:00.000Z"), startTime: new Date("2023-04-27T15:00:00.000Z"),
invitedConfidentially: false, invitedConfidentially: false,
endTime: new Date("2023-04-27T15:30:00.000Z"), endTime: new Date("2023-04-27T15:30:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "10", interval: "10",
_id: "repeatRuleId", _id: "repeatRuleId",
endType: EndType.Count, endType: EndType.Count,
@ -92,11 +102,11 @@ o.spec("CalendarEventModelTest", function () {
organizer: ownerAddress, organizer: ownerAddress,
alarmInfos: [["alarmListId", "alarmElementId"]], alarmInfos: [["alarmListId", "alarmElementId"]],
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: ownerAddress, address: ownerAddress,
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress, address: otherAddress,
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
}), }),
@ -107,12 +117,12 @@ o.spec("CalendarEventModelTest", function () {
const userController = makeUserController([ownerAlias.address], AccountType.PAID, ownerMailAddress, true) const userController = makeUserController([ownerAlias.address], AccountType.PAID, ownerMailAddress, true)
when(logins.getUserController()).thenReturn(userController) when(logins.getUserController()).thenReturn(userController)
when(calendarModel.loadAlarms(event.alarmInfos, userController.user)).thenResolve([ when(calendarModel.loadAlarms(event.alarmInfos, userController.user)).thenResolve([
createUserAlarmInfo({ createTestEntity(UserAlarmInfoTypeRef, {
_id: event.alarmInfos[0], _id: event.alarmInfos[0],
alarmInfo: createAlarmInfo({ alarmInfo: createTestEntity(AlarmInfoTypeRef, {
alarmIdentifier: "alarmIdentifier", alarmIdentifier: "alarmIdentifier",
trigger: "5M", trigger: "5M",
calendarRef: createCalendarEventRef({ calendarRef: createTestEntity(CalendarEventRefTypeRef, {
elementId: event._id[1], elementId: event._id[1],
listId: event._id[0], listId: event._id[0],
}), }),
@ -132,12 +142,12 @@ o.spec("CalendarEventModelTest", function () {
mailbox: createTestEntity(MailBoxTypeRef), mailbox: createTestEntity(MailBoxTypeRef),
folders: new FolderSystem([]), folders: new FolderSystem([]),
mailGroupInfo: createTestEntity(GroupInfoTypeRef), mailGroupInfo: createTestEntity(GroupInfoTypeRef),
mailGroup: createGroup({ mailGroup: createTestEntity(GroupTypeRef, {
user: ownerId, user: ownerId,
}), }),
mailboxGroupRoot: createTestEntity(MailboxGroupRootTypeRef), mailboxGroupRoot: createTestEntity(MailboxGroupRootTypeRef),
} }
const mailboxProperties: MailboxProperties = createMailboxProperties({}) const mailboxProperties: MailboxProperties = createTestEntity(MailboxPropertiesTypeRef, {})
const sendModelFac: () => SendMailModel = func<() => SendMailModel>() const sendModelFac: () => SendMailModel = func<() => SendMailModel>()
const model = await makeCalendarEventModel( const model = await makeCalendarEventModel(
CalendarOperation.EditAll, CalendarOperation.EditAll,
@ -180,13 +190,13 @@ o.spec("CalendarEventModelTest", function () {
}) })
o.spec("eventHasChanged", function () { o.spec("eventHasChanged", function () {
const fixedOrganizer = createEncryptedMailAddress({ const fixedOrganizer = createTestEntity(EncryptedMailAddressTypeRef, {
address: "moo@d.de", address: "moo@d.de",
name: "bla", name: "bla",
}) })
const att = (a, n, s) => const att = (a, n, s) =>
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: createEncryptedMailAddress({ address: a, name: n }), address: createTestEntity(EncryptedMailAddressTypeRef, { address: a, name: n }),
status: s, status: s,
}) })
// attr, now, previous, expected, msg // attr, now, previous, expected, msg
@ -200,9 +210,27 @@ o.spec("CalendarEventModelTest", function () {
["endTime", getDateInZone("2023-05-26"), getDateInZone("2023-05-27"), true], ["endTime", getDateInZone("2023-05-26"), getDateInZone("2023-05-27"), true],
["uid", "newUid", "oldUid", true], ["uid", "newUid", "oldUid", true],
["organizer", fixedOrganizer, fixedOrganizer, false, "same object in organizer"], ["organizer", fixedOrganizer, fixedOrganizer, false, "same object in organizer"],
["organizer", fixedOrganizer, createEncryptedMailAddress({ address: "moo@d.de", name: "bla" }), false, "same organizer, different object"], [
["organizer", fixedOrganizer, createEncryptedMailAddress({ address: "moo@d.de", name: "blabla" }), false, "different address, same name"], "organizer",
["organizer", fixedOrganizer, createEncryptedMailAddress({ address: "moo@d.io", name: "bla" }), true, "same name, different address"], fixedOrganizer,
createTestEntity(EncryptedMailAddressTypeRef, { address: "moo@d.de", name: "bla" }),
false,
"same organizer, different object",
],
[
"organizer",
fixedOrganizer,
createTestEntity(EncryptedMailAddressTypeRef, { address: "moo@d.de", name: "blabla" }),
false,
"different address, same name",
],
[
"organizer",
fixedOrganizer,
createTestEntity(EncryptedMailAddressTypeRef, { address: "moo@d.io", name: "bla" }),
true,
"same name, different address",
],
["attendees", [], [], false, "no attendees in either event"], ["attendees", [], [], false, "no attendees in either event"],
[ [
"attendees", "attendees",
@ -233,7 +261,7 @@ o.spec("CalendarEventModelTest", function () {
o(`${attr} changed -> ${expected}`, function () { o(`${attr} changed -> ${expected}`, function () {
// createCalendarEvent will create events with a startTime and endTime created by "new Date()", // createCalendarEvent will create events with a startTime and endTime created by "new Date()",
// which is not repeatable, so we only do it once. // which is not repeatable, so we only do it once.
const template = createCalendarEvent({ [attr]: previous }) const template = createTestEntity(CalendarEventTypeRef, { [attr]: previous })
const copy = Object.assign({}, template, { [attr]: now }) const copy = Object.assign({}, template, { [attr]: now })
o(eventHasChanged(copy, template)).equals(expected)(msg ?? attr) o(eventHasChanged(copy, template)).equals(expected)(msg ?? attr)
o(eventHasChanged(copy, clone(copy))).equals(false)(`do not change ${msg}`) o(eventHasChanged(copy, clone(copy))).equals(false)(`do not change ${msg}`)
@ -241,12 +269,12 @@ o.spec("CalendarEventModelTest", function () {
} }
o("same object -> false", function () { o("same object -> false", function () {
const event = createCalendarEvent({}) const event = createTestEntity(CalendarEventTypeRef, {})
o(eventHasChanged(event, event)).equals(false) o(eventHasChanged(event, event)).equals(false)
}) })
}) })
const dw = (d) => createDateWrapper({ date: getDateInZone(d) }) const dw = (d) => createTestEntity(DateWrapperTypeRef, { date: getDateInZone(d) })
o.spec("areRepeatRulesEqual", function () { o.spec("areRepeatRulesEqual", function () {
// property, now, previous, expected, msg // property, now, previous, expected, msg
const cases = [ const cases = [
@ -261,12 +289,16 @@ o.spec("CalendarEventModelTest", function () {
for (const [attr, now, previous, expected, msg] of cases) { for (const [attr, now, previous, expected, msg] of cases) {
o(`${attr} changed -> ${expected}`, function () { o(`${attr} changed -> ${expected}`, function () {
o(areRepeatRulesEqual(createRepeatRule({ [attr]: now }), createRepeatRule({ [attr]: previous }))).equals(expected)(msg ?? attr) o(areRepeatRulesEqual(createTestEntity(RepeatRuleTypeRef, { [attr]: now }), createTestEntity(RepeatRuleTypeRef, { [attr]: previous }))).equals(
o(areRepeatRulesEqual(createRepeatRule({ [attr]: now }), createRepeatRule({ [attr]: now }))).equals(true)(`do not change ${msg}`) expected,
)(msg ?? attr)
o(areRepeatRulesEqual(createTestEntity(RepeatRuleTypeRef, { [attr]: now }), createTestEntity(RepeatRuleTypeRef, { [attr]: now }))).equals(true)(
`do not change ${msg}`,
)
}) })
} }
o("same object -> true", function () { o("same object -> true", function () {
const r1 = createRepeatRule({}) const r1 = createTestEntity(RepeatRuleTypeRef, {})
o(areRepeatRulesEqual(r1, r1)).equals(true) o(areRepeatRulesEqual(r1, r1)).equals(true)
}) })
}) })

View file

@ -4,9 +4,10 @@ import { getEventWithDefaultTimes, isAllDayEvent } from "../../../../src/api/com
import { Time } from "../../../../src/calendar/date/Time.js" import { Time } from "../../../../src/calendar/date/Time.js"
import { CalendarEventWhenModel, getDefaultEndCountValue } from "../../../../src/calendar/date/eventeditor/CalendarEventWhenModel.js" import { CalendarEventWhenModel, getDefaultEndCountValue } from "../../../../src/calendar/date/eventeditor/CalendarEventWhenModel.js"
import { EndType, RepeatPeriod } from "../../../../src/api/common/TutanotaConstants.js" import { EndType, RepeatPeriod } from "../../../../src/api/common/TutanotaConstants.js"
import { createDateWrapper, createRepeatRule } from "../../../../src/api/entities/sys/TypeRefs.js" import { DateWrapperTypeRef, RepeatRuleTypeRef } from "../../../../src/api/entities/sys/TypeRefs.js"
import { CalendarEvent, createCalendarEvent } from "../../../../src/api/entities/tutanota/TypeRefs.js" import { CalendarEvent, CalendarEventTypeRef } from "../../../../src/api/entities/tutanota/TypeRefs.js"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { createTestEntity } from "../../TestUtils.js"
o.spec("CalendarEventWhenModel", function () { o.spec("CalendarEventWhenModel", function () {
const getModelBerlin = (initialValues: Partial<CalendarEvent>) => new CalendarEventWhenModel(initialValues, "Europe/Berlin", noOp) const getModelBerlin = (initialValues: Partial<CalendarEvent>) => new CalendarEventWhenModel(initialValues, "Europe/Berlin", noOp)
@ -335,7 +336,7 @@ o.spec("CalendarEventWhenModel", function () {
model.repeatPeriod = RepeatPeriod.DAILY model.repeatPeriod = RepeatPeriod.DAILY
o(model.repeatPeriod).equals(RepeatPeriod.DAILY) o(model.repeatPeriod).equals(RepeatPeriod.DAILY)
o(model.result.repeatRule).deepEquals( o(model.result.repeatRule).deepEquals(
createRepeatRule({ createTestEntity(RepeatRuleTypeRef, {
interval: "1", interval: "1",
endType: EndType.Never, endType: EndType.Never,
endValue: "1", endValue: "1",
@ -350,7 +351,7 @@ o.spec("CalendarEventWhenModel", function () {
const model = getModelBerlin({ const model = getModelBerlin({
startTime: new Date("2023-04-27T00:00:00.000Z"), startTime: new Date("2023-04-27T00:00:00.000Z"),
endTime: new Date("2023-04-28T00:00:00.000Z"), endTime: new Date("2023-04-28T00:00:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "1", interval: "1",
endType: EndType.Never, endType: EndType.Never,
endValue: "1", endValue: "1",
@ -377,7 +378,7 @@ o.spec("CalendarEventWhenModel", function () {
const model = getModelBerlin({ const model = getModelBerlin({
startTime: new Date("2023-04-27T00:00:00.000Z"), startTime: new Date("2023-04-27T00:00:00.000Z"),
endTime: new Date("2023-04-28T00:00:00.000Z"), endTime: new Date("2023-04-28T00:00:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "1", interval: "1",
endType: EndType.Never, endType: EndType.Never,
endValue: "1", endValue: "1",
@ -423,7 +424,7 @@ o.spec("CalendarEventWhenModel", function () {
const model = getModelBerlin({ const model = getModelBerlin({
startTime: new Date("2023-04-27T00:00:00.000Z"), startTime: new Date("2023-04-27T00:00:00.000Z"),
endTime: new Date("2023-04-28T00:00:00.000Z"), endTime: new Date("2023-04-28T00:00:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "1", interval: "1",
endType: EndType.Count, endType: EndType.Count,
endValue: "42", endValue: "42",
@ -442,7 +443,7 @@ o.spec("CalendarEventWhenModel", function () {
const model = getModelBerlin({ const model = getModelBerlin({
startTime: new Date("2023-04-27T00:00:00.000Z"), startTime: new Date("2023-04-27T00:00:00.000Z"),
endTime: new Date("2023-04-28T00:00:00.000Z"), endTime: new Date("2023-04-28T00:00:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "1", interval: "1",
endType: EndType.UntilDate, endType: EndType.UntilDate,
endValue: new Date("2023-04-30T00:00:00.000Z").getTime().toString(), endValue: new Date("2023-04-30T00:00:00.000Z").getTime().toString(),
@ -464,7 +465,7 @@ o.spec("CalendarEventWhenModel", function () {
const model = getModelBerlin({ const model = getModelBerlin({
startTime: new Date("2023-04-27T00:00:00.000Z"), startTime: new Date("2023-04-27T00:00:00.000Z"),
endTime: new Date("2023-04-28T00:00:00.000Z"), endTime: new Date("2023-04-28T00:00:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "10", interval: "10",
endType: EndType.Count, endType: EndType.Count,
endValue: "10", endValue: "10",
@ -482,7 +483,7 @@ o.spec("CalendarEventWhenModel", function () {
const model = getModelBerlin({ const model = getModelBerlin({
startTime: new Date("2023-04-27T00:00:00.000Z"), startTime: new Date("2023-04-27T00:00:00.000Z"),
endTime: new Date("2023-04-28T00:00:00.000Z"), endTime: new Date("2023-04-28T00:00:00.000Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
interval: "10", interval: "10",
endType: EndType.Count, endType: EndType.Count,
endValue: "10", endValue: "10",
@ -501,10 +502,10 @@ o.spec("CalendarEventWhenModel", function () {
o.spec("deleteExcludedDates", function () { o.spec("deleteExcludedDates", function () {
o("clears the array of excluded dates", async function () { o("clears the array of excluded dates", async function () {
const model = await getModelBerlin( const model = await getModelBerlin(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-13T00:00:00Z"), startTime: new Date("2023-03-13T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
excludedDates: [createDateWrapper({ date: new Date("2023-03-13T00:00:00Z") })], excludedDates: [createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-13T00:00:00Z") })],
}), }),
}), }),
) )
@ -515,12 +516,12 @@ o.spec("CalendarEventWhenModel", function () {
}) })
o("end occurrence changed to smaller -> delete exclusions", async function () { o("end occurrence changed to smaller -> delete exclusions", async function () {
const model = await getModelBerlin( const model = await getModelBerlin(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-13T00:00:00Z"), startTime: new Date("2023-03-13T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
endValue: "42", endValue: "42",
excludedDates: [createDateWrapper({ date: new Date("2023-03-13T00:00:00Z") })], excludedDates: [createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-13T00:00:00Z") })],
}), }),
}), }),
) )
@ -530,12 +531,12 @@ o.spec("CalendarEventWhenModel", function () {
}) })
o("end occurrence changed to bigger -> delete exclusions", async function () { o("end occurrence changed to bigger -> delete exclusions", async function () {
const model = await getModelBerlin( const model = await getModelBerlin(
createCalendarEvent({ createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-13T00:00:00Z"), startTime: new Date("2023-03-13T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
endType: EndType.Count, endType: EndType.Count,
endValue: "42", endValue: "42",
excludedDates: [createDateWrapper({ date: new Date("2023-03-13T00:00:00Z") })], excludedDates: [createTestEntity(DateWrapperTypeRef, { date: new Date("2023-03-13T00:00:00Z") })],
}), }),
}), }),
) )
@ -545,14 +546,14 @@ o.spec("CalendarEventWhenModel", function () {
}) })
o("interval changes delete exclusions", async function () { o("interval changes delete exclusions", async function () {
const excludedDates = [new Date("2023-03-13T00:00:00Z")] const excludedDates = [new Date("2023-03-13T00:00:00Z")]
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-13T00:00:00Z"), startTime: new Date("2023-03-13T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: "1", frequency: "1",
interval: "1", interval: "1",
endType: EndType.Count, endType: EndType.Count,
endValue: "10", endValue: "10",
excludedDates: excludedDates.map((date) => createDateWrapper({ date })), excludedDates: excludedDates.map((date) => createTestEntity(DateWrapperTypeRef, { date })),
timeZone: "Europe/Berlin", timeZone: "Europe/Berlin",
}), }),
}) })
@ -567,14 +568,14 @@ o.spec("CalendarEventWhenModel", function () {
}) })
o("frequency changes delete exclusions", async function () { o("frequency changes delete exclusions", async function () {
const excludedDates = [new Date("2023-03-13T00:00:00Z")] const excludedDates = [new Date("2023-03-13T00:00:00Z")]
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-03-13T00:00:00Z"), startTime: new Date("2023-03-13T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: "1", frequency: "1",
interval: "1", interval: "1",
endType: EndType.Count, endType: EndType.Count,
endValue: "10", endValue: "10",
excludedDates: excludedDates.map((date) => createDateWrapper({ date })), excludedDates: excludedDates.map((date) => createTestEntity(DateWrapperTypeRef, { date })),
timeZone: "Europe/Berlin", timeZone: "Europe/Berlin",
}), }),
}) })
@ -589,15 +590,15 @@ o.spec("CalendarEventWhenModel", function () {
o("repeat end date changes delete exclusions", async function () { o("repeat end date changes delete exclusions", async function () {
const excludedDates = [new Date("2023-04-13T15:00:00Z")] const excludedDates = [new Date("2023-04-13T15:00:00Z")]
const originalUntilDate = new Date("2023-05-13T00:00:00Z") const originalUntilDate = new Date("2023-05-13T00:00:00Z")
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T15:00:00Z"), startTime: new Date("2023-01-13T15:00:00Z"),
endTime: new Date("2023-01-13T20:00:00Z"), endTime: new Date("2023-01-13T20:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.UntilDate, endType: EndType.UntilDate,
endValue: originalUntilDate.getTime().toString(), endValue: originalUntilDate.getTime().toString(),
excludedDates: excludedDates.map((date) => createDateWrapper({ date })), excludedDates: excludedDates.map((date) => createTestEntity(DateWrapperTypeRef, { date })),
timeZone: "Europe/Berlin", timeZone: "Europe/Berlin",
}), }),
}) })
@ -614,15 +615,15 @@ o.spec("CalendarEventWhenModel", function () {
o("repeat end date changes delete exclusions, all-day events", function () { o("repeat end date changes delete exclusions, all-day events", function () {
const excludedDates = [new Date("2023-04-13T15:00:00Z")] const excludedDates = [new Date("2023-04-13T15:00:00Z")]
const originalUntilDate = new Date("2023-05-13T00:00:00Z") const originalUntilDate = new Date("2023-05-13T00:00:00Z")
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T00:00:00Z"), startTime: new Date("2023-01-13T00:00:00Z"),
endTime: new Date("2023-01-14T00:00:00Z"), endTime: new Date("2023-01-14T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.UntilDate, endType: EndType.UntilDate,
endValue: originalUntilDate.getTime().toString(), endValue: originalUntilDate.getTime().toString(),
excludedDates: excludedDates.map((date) => createDateWrapper({ date })), excludedDates: excludedDates.map((date) => createTestEntity(DateWrapperTypeRef, { date })),
timeZone: "Europe/Berlin", timeZone: "Europe/Berlin",
}), }),
}) })
@ -640,15 +641,15 @@ o.spec("CalendarEventWhenModel", function () {
o("time zone changes do not delete exclusions", async function () { o("time zone changes do not delete exclusions", async function () {
const excludedDates = [new Date("2023-04-13T15:00:00Z")] const excludedDates = [new Date("2023-04-13T15:00:00Z")]
const originalUntilDate = new Date("2023-05-13T00:00:00Z") const originalUntilDate = new Date("2023-05-13T00:00:00Z")
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T00:00:00Z"), startTime: new Date("2023-01-13T00:00:00Z"),
endTime: new Date("2023-01-14T00:00:00Z"), endTime: new Date("2023-01-14T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.UntilDate, endType: EndType.UntilDate,
endValue: originalUntilDate.getTime().toString(), endValue: originalUntilDate.getTime().toString(),
excludedDates: excludedDates.map((date) => createDateWrapper({ date })), excludedDates: excludedDates.map((date) => createTestEntity(DateWrapperTypeRef, { date })),
timeZone: "Asia/Krasnoyarsk", timeZone: "Asia/Krasnoyarsk",
}), }),
}) })
@ -661,7 +662,7 @@ o.spec("CalendarEventWhenModel", function () {
}) })
o.spec("excludeDate", function () { o.spec("excludeDate", function () {
o("no exclusion is added if event has no repeat rule", async function () { o("no exclusion is added if event has no repeat rule", async function () {
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T00:00:00Z"), startTime: new Date("2023-01-13T00:00:00Z"),
endTime: new Date("2023-01-14T00:00:00Z"), endTime: new Date("2023-01-14T00:00:00Z"),
repeatRule: null, repeatRule: null,
@ -672,10 +673,10 @@ o.spec("CalendarEventWhenModel", function () {
o(model.result.repeatRule).equals(null) o(model.result.repeatRule).equals(null)
}) })
o("adding two exclusions in reverse order sorts them", async function () { o("adding two exclusions in reverse order sorts them", async function () {
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T00:00:00Z"), startTime: new Date("2023-01-13T00:00:00Z"),
endTime: new Date("2023-01-14T00:00:00Z"), endTime: new Date("2023-01-14T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.Never, endType: EndType.Never,
@ -688,14 +689,14 @@ o.spec("CalendarEventWhenModel", function () {
model.excludeDate(exclusions[1]) model.excludeDate(exclusions[1])
model.excludeDate(exclusions[0]) model.excludeDate(exclusions[0])
o(model.result.repeatRule?.excludedDates).deepEquals(exclusions.map((date) => createDateWrapper({ date }))) o(model.result.repeatRule?.excludedDates).deepEquals(exclusions.map((date) => createTestEntity(DateWrapperTypeRef, { date })))
o(model.excludedDates).deepEquals(exclusions) o(model.excludedDates).deepEquals(exclusions)
}) })
o("adding two exclusions in order sorts them", async function () { o("adding two exclusions in order sorts them", async function () {
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T00:00:00Z"), startTime: new Date("2023-01-13T00:00:00Z"),
endTime: new Date("2023-01-14T00:00:00Z"), endTime: new Date("2023-01-14T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.Never, endType: EndType.Never,
@ -708,14 +709,14 @@ o.spec("CalendarEventWhenModel", function () {
model.excludeDate(exclusions[0]) model.excludeDate(exclusions[0])
model.excludeDate(exclusions[1]) model.excludeDate(exclusions[1])
o(model.result.repeatRule?.excludedDates).deepEquals(exclusions.map((date) => createDateWrapper({ date }))) o(model.result.repeatRule?.excludedDates).deepEquals(exclusions.map((date) => createTestEntity(DateWrapperTypeRef, { date })))
o(model.excludedDates).deepEquals(exclusions) o(model.excludedDates).deepEquals(exclusions)
}) })
o("adding the same exclusion multiple times deduplicates them", async function () { o("adding the same exclusion multiple times deduplicates them", async function () {
const event = createCalendarEvent({ const event = createTestEntity(CalendarEventTypeRef, {
startTime: new Date("2023-01-13T00:00:00Z"), startTime: new Date("2023-01-13T00:00:00Z"),
endTime: new Date("2023-01-14T00:00:00Z"), endTime: new Date("2023-01-14T00:00:00Z"),
repeatRule: createRepeatRule({ repeatRule: createTestEntity(RepeatRuleTypeRef, {
frequency: RepeatPeriod.DAILY, frequency: RepeatPeriod.DAILY,
interval: "1", interval: "1",
endType: EndType.Never, endType: EndType.Never,
@ -728,7 +729,7 @@ o.spec("CalendarEventWhenModel", function () {
model.excludeDate(exclusion) model.excludeDate(exclusion)
model.excludeDate(exclusion) model.excludeDate(exclusion)
o(model.result.repeatRule?.excludedDates).deepEquals([createDateWrapper({ date: exclusion })]) o(model.result.repeatRule?.excludedDates).deepEquals([createTestEntity(DateWrapperTypeRef, { date: exclusion })])
o(model.excludedDates).deepEquals([exclusion]) o(model.excludedDates).deepEquals([exclusion])
}) })
}) })

View file

@ -1,11 +1,19 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { CalendarEvent, createCalendarEvent, createCalendarEventAttendee, createContact } from "../../../../src/api/entities/tutanota/TypeRefs.js" import {
CalendarEvent,
CalendarEventAttendeeTypeRef,
CalendarEventTypeRef,
ContactTypeRef,
createCalendarEvent,
createCalendarEventAttendee,
createContact,
} from "../../../../src/api/entities/tutanota/TypeRefs.js"
import { CalendarEventWhoModel } from "../../../../src/calendar/date/eventeditor/CalendarEventWhoModel.js" import { CalendarEventWhoModel } from "../../../../src/calendar/date/eventeditor/CalendarEventWhoModel.js"
import { matchers, object, verify, when } from "testdouble" import { matchers, object, verify, when } from "testdouble"
import { RecipientsModel } from "../../../../src/api/main/RecipientsModel.js" import { RecipientsModel } from "../../../../src/api/main/RecipientsModel.js"
import { Recipient, RecipientType } from "../../../../src/api/common/recipients/Recipient.js" import { Recipient, RecipientType } from "../../../../src/api/common/recipients/Recipient.js"
import { AccountType, CalendarAttendeeStatus, ShareCapability } from "../../../../src/api/common/TutanotaConstants.js" import { AccountType, CalendarAttendeeStatus, ShareCapability } from "../../../../src/api/common/TutanotaConstants.js"
import { createUser } from "../../../../src/api/entities/sys/TypeRefs.js" import { createUser, UserTypeRef } from "../../../../src/api/entities/sys/TypeRefs.js"
import { SendMailModel } from "../../../../src/mail/editor/SendMailModel.js" import { SendMailModel } from "../../../../src/mail/editor/SendMailModel.js"
import { UserController } from "../../../../src/api/main/UserController.js" import { UserController } from "../../../../src/api/main/UserController.js"
import { CalendarOperation, EventType } from "../../../../src/calendar/date/eventeditor/CalendarEventModel.js" import { CalendarOperation, EventType } from "../../../../src/calendar/date/eventeditor/CalendarEventModel.js"
@ -29,6 +37,7 @@ import {
import { assertNotNull, neverNull } from "@tutao/tutanota-utils" import { assertNotNull, neverNull } from "@tutao/tutanota-utils"
import { RecipientField } from "../../../../src/mail/model/MailUtils.js" import { RecipientField } from "../../../../src/mail/model/MailUtils.js"
import { ProgrammingError } from "../../../../src/api/common/error/ProgrammingError.js" import { ProgrammingError } from "../../../../src/api/common/error/ProgrammingError.js"
import { createTestEntity } from "../../TestUtils.js"
o.spec("CalendarEventWhoModel", function () { o.spec("CalendarEventWhoModel", function () {
const passwordStrengthModel = () => 1 const passwordStrengthModel = () => 1
@ -152,18 +161,18 @@ o.spec("CalendarEventWhoModel", function () {
o.spec("invite capabilities for different events", function () { o.spec("invite capabilities for different events", function () {
o("invite in our own calendar can only modify own attendance", async function () { o("invite in our own calendar can only modify own attendance", async function () {
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
summary: "existing event", summary: "existing event",
startTime: new Date(2020, 4, 26, 12), startTime: new Date(2020, 4, 26, 12),
endTime: new Date(2020, 4, 26, 13), endTime: new Date(2020, 4, 26, 13),
organizer: otherAddress, organizer: otherAddress,
_ownerGroup: "ownCalendar", _ownerGroup: "ownCalendar",
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: ownerAddress, address: ownerAddress,
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress, address: otherAddress,
}), }),
], ],
@ -178,18 +187,18 @@ o.spec("CalendarEventWhoModel", function () {
o("existing normal event in writable calendar can not modify guests", async function () { o("existing normal event in writable calendar can not modify guests", async function () {
const userController = makeUserController() const userController = makeUserController()
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
summary: "existing event", summary: "existing event",
startTime: new Date(2020, 4, 26, 12), startTime: new Date(2020, 4, 26, 12),
endTime: new Date(2020, 4, 26, 13), endTime: new Date(2020, 4, 26, 13),
organizer: otherAddress, organizer: otherAddress,
_ownerGroup: "sharedCalendar", _ownerGroup: "sharedCalendar",
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: ownerAddress, address: ownerAddress,
status: CalendarAttendeeStatus.ACCEPTED, status: CalendarAttendeeStatus.ACCEPTED,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress, address: otherAddress,
}), }),
], ],
@ -203,17 +212,17 @@ o.spec("CalendarEventWhoModel", function () {
o("for an invite in writable calendar, we cannot modify guests", async function () { o("for an invite in writable calendar, we cannot modify guests", async function () {
const userController = makeUserController() const userController = makeUserController()
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
summary: "existing event", summary: "existing event",
startTime: new Date(2020, 4, 26, 12), startTime: new Date(2020, 4, 26, 12),
endTime: new Date(2020, 4, 26, 13), endTime: new Date(2020, 4, 26, 13),
organizer: otherAddress, organizer: otherAddress,
_ownerGroup: "sharedCalendar", _ownerGroup: "sharedCalendar",
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress, address: otherAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress2, address: otherAddress2,
}), }),
], ],
@ -225,7 +234,7 @@ o.spec("CalendarEventWhoModel", function () {
o("in readonly calendar, cannot modify guests", async function () { o("in readonly calendar, cannot modify guests", async function () {
const userController = makeUserController() const userController = makeUserController()
addCapability(userController.user, "sharedCalendar", ShareCapability.Read) addCapability(userController.user, "sharedCalendar", ShareCapability.Read)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_ownerGroup: "sharedCalendar", _ownerGroup: "sharedCalendar",
}) })
const model = getOldSharedModel(existingEvent, EventType.SHARED_RO) const model = getOldSharedModel(existingEvent, EventType.SHARED_RO)
@ -235,17 +244,17 @@ o.spec("CalendarEventWhoModel", function () {
o("in writable calendar w/ guests, we cannot modify guests", async function () { o("in writable calendar w/ guests, we cannot modify guests", async function () {
const userController = makeUserController() const userController = makeUserController()
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
summary: "existing event", summary: "existing event",
startTime: new Date(2020, 4, 26, 12), startTime: new Date(2020, 4, 26, 12),
endTime: new Date(2020, 4, 26, 13), endTime: new Date(2020, 4, 26, 13),
organizer: otherAddress, organizer: otherAddress,
_ownerGroup: "sharedCalendar", _ownerGroup: "sharedCalendar",
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress, address: otherAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: ownerAddress, address: ownerAddress,
}), }),
], ],
@ -258,7 +267,10 @@ o.spec("CalendarEventWhoModel", function () {
o.spec("adding and removing attendees", function () { o.spec("adding and removing attendees", function () {
o("adding another alias on your own event replaces the old attendee and updates the organizer", async function () { o("adding another alias on your own event replaces the old attendee and updates the organizer", async function () {
const model = getNewModel({ const model = getNewModel({
attendees: [createCalendarEventAttendee({ address: ownAddresses[0] }), createCalendarEventAttendee({ address: otherAddress })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0] }),
createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress }),
],
organizer: ownAddresses[0], organizer: ownAddresses[0],
}) })
@ -280,14 +292,17 @@ o.spec("CalendarEventWhoModel", function () {
o(result.cancelModel).equals(null) o(result.cancelModel).equals(null)
o(result.responseModel).equals(null) o(result.responseModel).equals(null)
o(result.attendees).deepEquals([ o(result.attendees).deepEquals([
createCalendarEventAttendee({ address: ownerAlias, status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownerAlias, status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.ADDED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.ADDED }),
])("the result contains all attendees including the organizer") ])("the result contains all attendees including the organizer")
o(result.organizer).deepEquals(ownerAlias) o(result.organizer).deepEquals(ownerAlias)
}) })
o("setting multiple ownAddresses correctly gives the possible organizers", function () { o("setting multiple ownAddresses correctly gives the possible organizers", function () {
const model = getNewModel({ const model = getNewModel({
attendees: [createCalendarEventAttendee({ address: ownAddresses[0] }), createCalendarEventAttendee({ address: otherAddress })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0] }),
createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress }),
],
organizer: ownAddresses[0], organizer: ownAddresses[0],
}) })
o(model.possibleOrganizers).deepEquals([ownerAddress, ownerAlias]) o(model.possibleOrganizers).deepEquals([ownerAddress, ownerAlias])
@ -324,7 +339,10 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("trying to remove the organizer while there are other attendees does nothing", function () { o("trying to remove the organizer while there are other attendees does nothing", function () {
const model = getNewModel({ const model = getNewModel({
attendees: [createCalendarEventAttendee({ address: ownAddresses[0] }), createCalendarEventAttendee({ address: otherAddress })], attendees: [
createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0] }),
createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress }),
],
organizer: ownerAddress, organizer: ownerAddress,
}) })
model.removeAttendee(ownerAddress.address) model.removeAttendee(ownerAddress.address)
@ -335,8 +353,8 @@ o.spec("CalendarEventWhoModel", function () {
o("getting the result on an old model is idempotent", function () { o("getting the result on an old model is idempotent", function () {
const model = getOldModel({ const model = getOldModel({
attendees: [ attendees: [
createCalendarEventAttendee({ address: ownAddresses[0], status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0], status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.ACCEPTED }),
], ],
organizer: ownerAddress, organizer: ownerAddress,
}) })
@ -347,8 +365,8 @@ o.spec("CalendarEventWhoModel", function () {
o("removing an attendee while there are other attendees removes only that attendee", async function () { o("removing an attendee while there are other attendees removes only that attendee", async function () {
const model = getOldModel({ const model = getOldModel({
attendees: [ attendees: [
createCalendarEventAttendee({ address: ownAddresses[0], status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0], status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress }),
], ],
organizer: ownerAddress, organizer: ownerAddress,
}) })
@ -357,24 +375,24 @@ o.spec("CalendarEventWhoModel", function () {
await model.recipientsSettled await model.recipientsSettled
const resultBeforeRemove = model.result const resultBeforeRemove = model.result
o(resultBeforeRemove.attendees).deepEquals([ o(resultBeforeRemove.attendees).deepEquals([
createCalendarEventAttendee({ address: ownerAddress, status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownerAddress, status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.ADDED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.ADDED }),
createCalendarEventAttendee({ address: otherAddress2, status: CalendarAttendeeStatus.ADDED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress2, status: CalendarAttendeeStatus.ADDED }),
])("there are three attendees in the event") ])("there are three attendees in the event")
o(resultBeforeRemove.organizer).deepEquals(ownerAddress) o(resultBeforeRemove.organizer).deepEquals(ownerAddress)
model.removeAttendee(otherAddress.address) model.removeAttendee(otherAddress.address)
const result = model.result const result = model.result
o(result.attendees).deepEquals([ o(result.attendees).deepEquals([
createCalendarEventAttendee({ address: ownerAddress, status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownerAddress, status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress2, status: CalendarAttendeeStatus.ADDED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress2, status: CalendarAttendeeStatus.ADDED }),
]) ])
o(result.organizer).deepEquals(ownerAddress) o(result.organizer).deepEquals(ownerAddress)
}) })
o("setting external passwords is reflected in the getters and result", async function () { o("setting external passwords is reflected in the getters and result", async function () {
const model = getNewModel({ const model = getNewModel({
attendees: [ attendees: [
createCalendarEventAttendee({ address: ownAddresses[0] }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0] }),
createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.NEEDS_ACTION }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.NEEDS_ACTION }),
], ],
organizer: ownerAddress, organizer: ownerAddress,
invitedConfidentially: true, invitedConfidentially: true,
@ -403,11 +421,11 @@ o.spec("CalendarEventWhoModel", function () {
o(model.getPresharedPassword(otherAddress.address)).deepEquals({ password: "otherPassword", strength: 1 }) o(model.getPresharedPassword(otherAddress.address)).deepEquals({ password: "otherPassword", strength: 1 })
const { attendees } = model.result const { attendees } = model.result
o(attendees).deepEquals([ o(attendees).deepEquals([
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: ownerAddress, address: ownerAddress,
status: CalendarAttendeeStatus.ADDED, status: CalendarAttendeeStatus.ADDED,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
address: otherAddress, address: otherAddress,
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
}), }),
@ -424,9 +442,9 @@ o.spec("CalendarEventWhoModel", function () {
o("organizer is replaced with ourselves when an own event with someone else as organizer is opened", function () { o("organizer is replaced with ourselves when an own event with someone else as organizer is opened", function () {
const model = getNewModel({ const model = getNewModel({
attendees: [ attendees: [
createCalendarEventAttendee({ address: ownAddresses[0], status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: ownAddresses[0], status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.ACCEPTED }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.ACCEPTED }),
createCalendarEventAttendee({ address: otherAddress2, status: CalendarAttendeeStatus.NEEDS_ACTION }), createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress2, status: CalendarAttendeeStatus.NEEDS_ACTION }),
], ],
organizer: otherAddress, organizer: otherAddress,
}) })
@ -439,21 +457,21 @@ o.spec("CalendarEventWhoModel", function () {
const sendModels: Array<SendMailModel> = [object<SendMailModel>("first"), object<SendMailModel>("second"), object<SendMailModel>("third")] const sendModels: Array<SendMailModel> = [object<SendMailModel>("first"), object<SendMailModel>("second"), object<SendMailModel>("third")]
const userController = makeUserController([], AccountType.PAID) const userController = makeUserController([], AccountType.PAID)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_ownerGroup: "ownCalendar", _ownerGroup: "ownCalendar",
startTime: getDateInZone("2020-06-01"), startTime: getDateInZone("2020-06-01"),
endTime: getDateInZone("2020-06-02"), endTime: getDateInZone("2020-06-02"),
organizer: ownerAddress, organizer: ownerAddress,
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: ownerAddress, address: ownerAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: otherAddress2, address: otherAddress2,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: thirdAddress, address: thirdAddress,
}), }),
@ -475,7 +493,7 @@ o.spec("CalendarEventWhoModel", function () {
) )
model.shouldSendUpdates = true model.shouldSendUpdates = true
model.removeAttendee(otherAddress2.address) model.removeAttendee(otherAddress2.address)
model.addAttendee(otherAddress.address, createContact({ nickname: otherAddress.name })) model.addAttendee(otherAddress.address, createTestEntity(ContactTypeRef, { nickname: otherAddress.name }))
const result = model.result const result = model.result
// this is not an invite to us, so we do not respond // this is not an invite to us, so we do not respond
o(result.responseModel).equals(null) o(result.responseModel).equals(null)
@ -491,17 +509,17 @@ o.spec("CalendarEventWhoModel", function () {
o("adding attendees on new event correctly creates invite model", function () { o("adding attendees on new event correctly creates invite model", function () {
const sendModels: Array<SendMailModel> = [object()] const sendModels: Array<SendMailModel> = [object()]
const userController = makeUserController([], AccountType.PAID) const userController = makeUserController([], AccountType.PAID)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_ownerGroup: "ownCalendar", _ownerGroup: "ownCalendar",
startTime: new Date(2020, 5, 1), startTime: new Date(2020, 5, 1),
endTime: new Date(2020, 5, 2), endTime: new Date(2020, 5, 2),
organizer: ownerAddress, organizer: ownerAddress,
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: ownerAddress, address: ownerAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: otherAddress2, address: otherAddress2,
}), }),
@ -521,7 +539,7 @@ o.spec("CalendarEventWhoModel", function () {
passwordStrengthModel, passwordStrengthModel,
() => sendModels.pop()!, () => sendModels.pop()!,
) )
model.addAttendee(otherAddress.address, createContact({ nickname: otherAddress.name })) model.addAttendee(otherAddress.address, createTestEntity(ContactTypeRef, { nickname: otherAddress.name }))
const result = model.result const result = model.result
o(result.responseModel).equals(null) o(result.responseModel).equals(null)
o(sendModels.length).equals(0) o(sendModels.length).equals(0)
@ -535,7 +553,7 @@ o.spec("CalendarEventWhoModel", function () {
o.spec("calendar selection", function () { o.spec("calendar selection", function () {
o.spec("getAvailableCalendars", function () { o.spec("getAvailableCalendars", function () {
o("it returns the shared calendars we have write access to when there are no attendees", function () { o("it returns the shared calendars we have write access to when there are no attendees", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
// add it as a writable calendar so that we see that it's filtered out // add it as a writable calendar so that we see that it's filtered out
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const model = getNewModel({}) const model = getNewModel({})
@ -543,7 +561,7 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("it returns only the calendars we have write access to", function () { o("it returns only the calendars we have write access to", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
// add it as a writable calendar so that we see that it's filtered out // add it as a writable calendar so that we see that it's filtered out
addCapability(userController.user, "sharedCalendar", ShareCapability.Read) addCapability(userController.user, "sharedCalendar", ShareCapability.Read)
const model = getNewModel({}) const model = getNewModel({})
@ -551,7 +569,7 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("it returns only own calendars after adding attendees to an existing event", function () { o("it returns only own calendars after adding attendees to an existing event", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
// add it as a writable calendar so that we see that it's filtered out // add it as a writable calendar so that we see that it's filtered out
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const model = getOldModel({}) const model = getOldModel({})
@ -560,17 +578,17 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("it returns only own calendars for existing own event with attendees ", function () { o("it returns only own calendars for existing own event with attendees ", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
// add it as a writable calendar so that we see that it's filtered out // add it as a writable calendar so that we see that it's filtered out
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const model = getOldModel({ const model = getOldModel({
attendees: [createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.NEEDS_ACTION })], attendees: [createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.NEEDS_ACTION })],
}) })
o(model.getAvailableCalendars()).deepEquals([calendars.get("ownCalendar")!]) o(model.getAvailableCalendars()).deepEquals([calendars.get("ownCalendar")!])
}) })
o("it returns only own calendars for invite", function () { o("it returns only own calendars for invite", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
// add it as a writable calendar so that we see that it's filtered out // add it as a writable calendar so that we see that it's filtered out
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const model = getOldInviteModel({}) const model = getOldInviteModel({})
@ -578,12 +596,12 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("it returns only existing calendar if it's existing shared event with attendees", function () { o("it returns only existing calendar if it's existing shared event with attendees", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
// add it as a writable calendar so that we see that it's filtered out // add it as a writable calendar so that we see that it's filtered out
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const model = getOldSharedModel( const model = getOldSharedModel(
{ {
attendees: [createCalendarEventAttendee({ address: otherAddress, status: CalendarAttendeeStatus.NEEDS_ACTION })], attendees: [createTestEntity(CalendarEventAttendeeTypeRef, { address: otherAddress, status: CalendarAttendeeStatus.NEEDS_ACTION })],
}, },
EventType.LOCKED, EventType.LOCKED,
) )
@ -591,7 +609,7 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("it returns only the current calendar for single-instance editing", function () { o("it returns only the current calendar for single-instance editing", function () {
userController.user = createUser({ _id: "ownerId" }) userController.user = createTestEntity(UserTypeRef, { _id: "ownerId" })
addCapability(userController.user, "sharedCalendar", ShareCapability.Write) addCapability(userController.user, "sharedCalendar", ShareCapability.Write)
const model = getOldModelWithSingleEdit({ attendees: [] }) const model = getOldModelWithSingleEdit({ attendees: [] })
o(model.getAvailableCalendars()).deepEquals([calendars.get("ownCalendar")!]) o(model.getAvailableCalendars()).deepEquals([calendars.get("ownCalendar")!])
@ -609,21 +627,21 @@ o.spec("CalendarEventWhoModel", function () {
o.spec("invites in own calendar, changing own attendance", function () { o.spec("invites in own calendar, changing own attendance", function () {
o("changing own attendance on new event results in responseModel and correct status", async function () { o("changing own attendance on new event results in responseModel and correct status", async function () {
const userController = makeUserController([], AccountType.PAID) const userController = makeUserController([], AccountType.PAID)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_ownerGroup: "ownCalendar", _ownerGroup: "ownCalendar",
startTime: getDateInZone("2020-06-01"), startTime: getDateInZone("2020-06-01"),
endTime: getDateInZone("2020-06-02"), endTime: getDateInZone("2020-06-02"),
organizer: otherAddress, organizer: otherAddress,
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.DECLINED, status: CalendarAttendeeStatus.DECLINED,
address: otherAddress, address: otherAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: ownerAddress, address: ownerAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: otherAddress2, address: otherAddress2,
}), }),
@ -654,21 +672,21 @@ o.spec("CalendarEventWhoModel", function () {
}) })
o("changing own attendance on existing event results in responseModel and correct status", async function () { o("changing own attendance on existing event results in responseModel and correct status", async function () {
const userController = makeUserController([], AccountType.PAID) const userController = makeUserController([], AccountType.PAID)
const existingEvent = createCalendarEvent({ const existingEvent = createTestEntity(CalendarEventTypeRef, {
_ownerGroup: "ownCalendar", _ownerGroup: "ownCalendar",
startTime: new Date(2020, 5, 1), startTime: new Date(2020, 5, 1),
endTime: new Date(2020, 5, 2), endTime: new Date(2020, 5, 2),
organizer: otherAddress, organizer: otherAddress,
attendees: [ attendees: [
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.DECLINED, status: CalendarAttendeeStatus.DECLINED,
address: otherAddress, address: otherAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: ownerAddress, address: ownerAddress,
}), }),
createCalendarEventAttendee({ createTestEntity(CalendarEventAttendeeTypeRef, {
status: CalendarAttendeeStatus.NEEDS_ACTION, status: CalendarAttendeeStatus.NEEDS_ACTION,
address: otherAddress2, address: otherAddress2,
}), }),

View file

@ -3,8 +3,9 @@ import { AccountType, FeatureType } from "../../../../src/api/common/TutanotaCon
import { hasPlanWithInvites } from "../../../../src/calendar/date/eventeditor/CalendarNotificationModel.js" import { hasPlanWithInvites } from "../../../../src/calendar/date/eventeditor/CalendarNotificationModel.js"
import { LoginController } from "../../../../src/api/main/LoginController.js" import { LoginController } from "../../../../src/api/main/LoginController.js"
import { object, replace, when } from "testdouble" import { object, replace, when } from "testdouble"
import { createPlanConfiguration, Customer } from "../../../../src/api/entities/sys/TypeRefs.js" import { Customer, PlanConfigurationTypeRef } from "../../../../src/api/entities/sys/TypeRefs.js"
import { UserController } from "../../../../src/api/main/UserController.js" import { UserController } from "../../../../src/api/main/UserController.js"
import { createTestEntity } from "../../TestUtils.js"
o.spec("CalendarNotificationModel", function () { o.spec("CalendarNotificationModel", function () {
let userController: UserController let userController: UserController
@ -22,7 +23,7 @@ o.spec("CalendarNotificationModel", function () {
o.spec("hasPlanWithInvites", async function () { o.spec("hasPlanWithInvites", async function () {
o("available for users with new paid plan that contains invites", async function () { o("available for users with new paid plan that contains invites", async function () {
when(userController.isNewPaidPlan()).thenResolve(true) when(userController.isNewPaidPlan()).thenResolve(true)
when(userController.getPlanConfig()).thenResolve(createPlanConfiguration({ eventInvites: true })) when(userController.getPlanConfig()).thenResolve(createTestEntity(PlanConfigurationTypeRef, { eventInvites: true }))
replace(userController, "user", { accountType: AccountType.PAID }) replace(userController, "user", { accountType: AccountType.PAID })
replace(customer, "customizations", []) replace(customer, "customizations", [])
o(await hasPlanWithInvites(logins)).equals(true) o(await hasPlanWithInvites(logins)).equals(true)
@ -30,7 +31,7 @@ o.spec("CalendarNotificationModel", function () {
o("not available for users with new paid plan that does not contain invites", async function () { o("not available for users with new paid plan that does not contain invites", async function () {
when(userController.isNewPaidPlan()).thenResolve(true) when(userController.isNewPaidPlan()).thenResolve(true)
when(userController.getPlanConfig()).thenResolve(createPlanConfiguration({ eventInvites: false })) when(userController.getPlanConfig()).thenResolve(createTestEntity(PlanConfigurationTypeRef, { eventInvites: false }))
replace(userController, "user", { accountType: AccountType.PAID }) replace(userController, "user", { accountType: AccountType.PAID })
o(await hasPlanWithInvites(logins)).equals(false) o(await hasPlanWithInvites(logins)).equals(false)
}) })

View file

@ -909,17 +909,17 @@ o.spec("ContactMergeUtilsTest", function () {
o(keptContact.phoneNumbers.length).equals(3) o(keptContact.phoneNumbers.length).equals(3)
}) })
o("getMergedPhoneNumber should ignore whitespace", function () { o("getMergedPhoneNumber should ignore whitespace", function () {
const numberWithoutWhitespace = createContactPhoneNumber({ const numberWithoutWhitespace = createTestEntity(ContactPhoneNumberTypeRef, {
number: "789654123", number: "789654123",
}) })
const numberWithWhitespace = createContactPhoneNumber({ const numberWithWhitespace = createTestEntity(ContactPhoneNumberTypeRef, {
number: " 789 654123 ", number: " 789 654123 ",
}) })
const mergedPhoneNumbers = _getMergedPhoneNumbers([numberWithoutWhitespace], [numberWithWhitespace]) const mergedPhoneNumbers = _getMergedPhoneNumbers([numberWithoutWhitespace], [numberWithWhitespace])
o(mergedPhoneNumbers).deepEquals([ o(mergedPhoneNumbers).deepEquals([
createContactPhoneNumber({ createTestEntity(ContactPhoneNumberTypeRef, {
number: "789654123", number: "789654123",
}), }),
]) ])

View file

@ -6,8 +6,8 @@ import { matchers, object, verify, when } from "testdouble"
import { FileReference } from "../../../src/api/common/utils/FileUtils.js" import { FileReference } from "../../../src/api/common/utils/FileUtils.js"
import { neverNull } from "@tutao/tutanota-utils" import { neverNull } from "@tutao/tutanota-utils"
import { DataFile } from "../../../src/api/common/DataFile.js" import { DataFile } from "../../../src/api/common/DataFile.js"
import { BlobTypeRef, createBlob } from "../../../src/api/entities/sys/TypeRefs.js" import { BlobTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import { createFile } from "../../../src/api/entities/tutanota/TypeRefs.js" import { FileTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { FileControllerNative } from "../../../src/file/FileControllerNative.js" import { FileControllerNative } from "../../../src/file/FileControllerNative.js"
import { FileControllerBrowser } from "../../../src/file/FileControllerBrowser.js" import { FileControllerBrowser } from "../../../src/file/FileControllerBrowser.js"
import { ConnectionError } from "../../../src/api/common/error/RestError.js" import { ConnectionError } from "../../../src/api/common/error/RestError.js"
@ -46,7 +46,7 @@ o.spec("FileControllerTest", function () {
o("should download non-legacy file natively using the blob service", async function () { o("should download non-legacy file natively using the blob service", async function () {
const blobs = [createTestEntity(BlobTypeRef)] const blobs = [createTestEntity(BlobTypeRef)]
const file = createFile({ blobs: blobs, name: "test.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] }) const file = createTestEntity(FileTypeRef, { blobs: blobs, name: "test.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] })
const fileReference = object<FileReference>() const fileReference = object<FileReference>()
when(blobFacadeMock.downloadAndDecryptNative(anything(), anything(), anything(), anything())).thenResolve(fileReference) when(blobFacadeMock.downloadAndDecryptNative(anything(), anything(), anything(), anything())).thenResolve(fileReference)
const result = await fileController.downloadAndDecrypt(file) const result = await fileController.downloadAndDecrypt(file)
@ -67,7 +67,7 @@ o.spec("FileControllerTest", function () {
o("immediately no connection", async function () { o("immediately no connection", async function () {
const testableFileController = new FileControllerNative(blobFacadeMock, guiDownload, fileAppMock) const testableFileController = new FileControllerNative(blobFacadeMock, guiDownload, fileAppMock)
const blobs = [createTestEntity(BlobTypeRef)] const blobs = [createTestEntity(BlobTypeRef)]
const file = createFile({ blobs: blobs, name: "test.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] }) const file = createTestEntity(FileTypeRef, { blobs: blobs, name: "test.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] })
when(blobFacadeMock.downloadAndDecryptNative(anything(), anything(), anything(), anything())).thenReject(new ConnectionError("no connection")) when(blobFacadeMock.downloadAndDecryptNative(anything(), anything(), anything(), anything())).thenReject(new ConnectionError("no connection"))
await assertThrows(ConnectionError, async () => await testableFileController.download(file)) await assertThrows(ConnectionError, async () => await testableFileController.download(file))
verify(fileAppMock.deleteFile(anything()), { times: 0 }) // mock for cleanup verify(fileAppMock.deleteFile(anything()), { times: 0 }) // mock for cleanup
@ -75,8 +75,18 @@ o.spec("FileControllerTest", function () {
o("connection lost after 1 already downloaded attachment- already downloaded attachments are processed", async function () { o("connection lost after 1 already downloaded attachment- already downloaded attachments are processed", async function () {
const testableFileController = new FileControllerNative(blobFacadeMock, guiDownload, fileAppMock) const testableFileController = new FileControllerNative(blobFacadeMock, guiDownload, fileAppMock)
const blobs = [createTestEntity(BlobTypeRef)] const blobs = [createTestEntity(BlobTypeRef)]
const fileWorks = createFile({ blobs: blobs, name: "works.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] }) const fileWorks = createTestEntity(FileTypeRef, {
const fileNotWorks = createFile({ blobs: blobs, name: "broken.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] }) blobs: blobs,
name: "works.txt",
mimeType: "plain/text",
_id: ["fileListId", "fileElementId"],
})
const fileNotWorks = createTestEntity(FileTypeRef, {
blobs: blobs,
name: "broken.txt",
mimeType: "plain/text",
_id: ["fileListId", "fileElementId"],
})
const fileReferenceWorks: FileReference = { const fileReferenceWorks: FileReference = {
name: "works.txt", name: "works.txt",
mimeType: "plain/text", mimeType: "plain/text",
@ -101,7 +111,7 @@ o.spec("FileControllerTest", function () {
o("should download non-legacy file non-natively using the blob service", async function () { o("should download non-legacy file non-natively using the blob service", async function () {
const blobs = [createTestEntity(BlobTypeRef)] const blobs = [createTestEntity(BlobTypeRef)]
const file = createFile({ blobs: blobs, name: "test.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] }) const file = createTestEntity(FileTypeRef, { blobs: blobs, name: "test.txt", mimeType: "plain/text", _id: ["fileListId", "fileElementId"] })
const data = new Uint8Array([1, 2, 3]) const data = new Uint8Array([1, 2, 3])
when(blobFacadeMock.downloadAndDecrypt(anything(), anything())).thenResolve(data) when(blobFacadeMock.downloadAndDecrypt(anything(), anything())).thenResolve(data)
const result = await fileController.downloadAndDecrypt(file) const result = await fileController.downloadAndDecrypt(file)

View file

@ -1,7 +1,7 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { DisplayMode, isLegacyDomain, LoginState, LoginViewModel } from "../../../src/login/LoginViewModel.js" import { DisplayMode, isLegacyDomain, LoginState, LoginViewModel } from "../../../src/login/LoginViewModel.js"
import type { LoginController } from "../../../src/api/main/LoginController.js" import type { LoginController } from "../../../src/api/main/LoginController.js"
import { createGroupInfo, createUser, UserTypeRef } from "../../../src/api/entities/sys/TypeRefs.js" import { GroupInfoTypeRef, UserTypeRef } from "../../../src/api/entities/sys/TypeRefs.js"
import type { UserController } from "../../../src/api/main/UserController.js" import type { UserController } from "../../../src/api/main/UserController.js"
import { KeyPermanentlyInvalidatedError } from "../../../src/api/common/error/KeyPermanentlyInvalidatedError.js" import { KeyPermanentlyInvalidatedError } from "../../../src/api/common/error/KeyPermanentlyInvalidatedError.js"
import { CredentialAuthenticationError } from "../../../src/api/common/error/CredentialAuthenticationError.js" import { CredentialAuthenticationError } from "../../../src/api/common/error/CredentialAuthenticationError.js"
@ -118,7 +118,7 @@ o.spec("LoginViewModelTest", () => {
replace( replace(
userControllerMock, userControllerMock,
"userGroupInfo", "userGroupInfo",
createGroupInfo({ createTestEntity(GroupInfoTypeRef, {
mailAddress: "test@example.com", mailAddress: "test@example.com",
}), }),
) )

View file

@ -3,12 +3,11 @@ import { UserController } from "../../../src/api/main/UserController.js"
import { reminderCutoffDate, shouldShowUpgradeReminder } from "../../../src/login/PostLoginUtils.js" import { reminderCutoffDate, shouldShowUpgradeReminder } from "../../../src/login/PostLoginUtils.js"
import { object, when } from "testdouble" import { object, when } from "testdouble"
import { import {
createCustomer,
createCustomerInfo,
createCustomerProperties,
Customer, Customer,
CustomerInfo, CustomerInfo,
CustomerInfoTypeRef,
CustomerProperties, CustomerProperties,
CustomerPropertiesTypeRef,
CustomerTypeRef, CustomerTypeRef,
} from "../../../src/api/entities/sys/TypeRefs.js" } from "../../../src/api/entities/sys/TypeRefs.js"
import { Const } from "../../../src/api/common/TutanotaConstants.js" import { Const } from "../../../src/api/common/TutanotaConstants.js"
@ -25,8 +24,8 @@ o.spec("PostLoginUtils", () => {
o.beforeEach(() => { o.beforeEach(() => {
userController = object() userController = object()
customerInfo = createCustomerInfo({}) customerInfo = createTestEntity(CustomerInfoTypeRef, {})
customerProperties = createCustomerProperties({}) customerProperties = createTestEntity(CustomerPropertiesTypeRef, {})
customer = createTestEntity(CustomerTypeRef) customer = createTestEntity(CustomerTypeRef)
when(userController.loadCustomerInfo()).thenResolve(customerInfo) when(userController.loadCustomerInfo()).thenResolve(customerInfo)

View file

@ -1,45 +1,46 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { knowledgeBaseSearch } from "../../../src/knowledgebase/model/KnowledgeBaseSearchFilter.js" import { knowledgeBaseSearch } from "../../../src/knowledgebase/model/KnowledgeBaseSearchFilter.js"
import type { KnowledgeBaseEntry } from "../../../src/api/entities/tutanota/TypeRefs.js" import type { KnowledgeBaseEntry } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { createKnowledgeBaseEntry } from "../../../src/api/entities/tutanota/TypeRefs.js" import { KnowledgeBaseEntryKeywordTypeRef, KnowledgeBaseEntryTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { createKnowledgeBaseEntryKeyword } from "../../../src/api/entities/tutanota/TypeRefs.js" import { createTestEntity } from "../TestUtils.js"
o.spec("KnowledgeBaseSearchFilter", function () { o.spec("KnowledgeBaseSearchFilter", function () {
o("finds in title with two filtered keywords", function () { o("finds in title with two filtered keywords", function () {
const knowledgebaseEntry1: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry1: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "User forgot their password", title: "User forgot their password",
description: description:
"When a user is certain that they do not remember their password anymore, " + "When a user is certain that they do not remember their password anymore, " +
"first, ask the user if they tried all passwords that come to mind" + "first, ask the user if they tried all passwords that come to mind" +
"if the user completed step 1, ask if they can provide proof that they own the account", "if the user completed step 1, ask if they can provide proof that they own the account",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "password", keyword: "password",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "forgotten", keyword: "forgotten",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "reset", keyword: "reset",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "account", keyword: "account",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "access", keyword: "access",
}), }),
], ],
}) })
const knowledgebaseEntry2: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry2: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "User cannot access account anymore", title: "User cannot access account anymore",
description: "A general entry for when the user cannot access their account", description: "A general entry for when the user cannot access their account",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "access", keyword: "access",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "account", keyword: "account",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "lost", keyword: "lost",
}), }),
], ],
@ -48,43 +49,43 @@ o.spec("KnowledgeBaseSearchFilter", function () {
o(knowledgeBaseSearch("password", allFakeEntries)).deepEquals([knowledgebaseEntry1]) // should find knowledgebaseEntry1 o(knowledgeBaseSearch("password", allFakeEntries)).deepEquals([knowledgebaseEntry1]) // should find knowledgebaseEntry1
}) })
o("finds in title without filtered keywords", function () { o("finds in title without filtered keywords", function () {
const knowledgebaseEntry1: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry1: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "User forgot their password", title: "User forgot their password",
description: description:
"When a user is certain that they do not remember their password anymore" + "When a user is certain that they do not remember their password anymore" +
"first, ask the user if they tried all passwords that come to mind" + "first, ask the user if they tried all passwords that come to mind" +
"if the user completed step 1, ask if they can provide proof that they own the account", "if the user completed step 1, ask if they can provide proof that they own the account",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "password", keyword: "password",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "forgotten", keyword: "forgotten",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "reset", keyword: "reset",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "account", keyword: "account",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "access", keyword: "access",
}), }),
], ],
}) })
const knowledgebaseEntry2: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry2: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "User cannot access account anymore", title: "User cannot access account anymore",
description: description:
"A general entry for when the user cannot access their account" + "A general entry for when the user cannot access their account" +
"ask user whether its because of the password or other factors as to why they cannot access their account", "ask user whether its because of the password or other factors as to why they cannot access their account",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "access", keyword: "access",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "account", keyword: "account",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "lost", keyword: "lost",
}), }),
], ],
@ -93,46 +94,46 @@ o.spec("KnowledgeBaseSearchFilter", function () {
o(knowledgeBaseSearch("user", allFakeEntries)).deepEquals([knowledgebaseEntry1, knowledgebaseEntry2]) // should find in both entries o(knowledgeBaseSearch("user", allFakeEntries)).deepEquals([knowledgebaseEntry1, knowledgebaseEntry2]) // should find in both entries
}) })
o("more than one filter word", function () { o("more than one filter word", function () {
const knowledgebaseEntry1: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry1: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "Payment has been booked but features arent accessible", title: "Payment has been booked but features arent accessible",
description: description:
"Something went wrong and the payment registered, but the user believes their features arent accessible yet" + "Something went wrong and the payment registered, but the user believes their features arent accessible yet" +
"first, check how long the time between payment and contact has been" + "first, check how long the time between payment and contact has been" +
"if it has been more than X days, ask the user to provide a bill or payment proof", "if it has been more than X days, ask the user to provide a bill or payment proof",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "payment", keyword: "payment",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "features", keyword: "features",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "inaccessible", keyword: "inaccessible",
}), }),
], ],
}) })
const knowledgebaseEntry2: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry2: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "Payment hasn't been booked yet, features aren't accessible either", title: "Payment hasn't been booked yet, features aren't accessible either",
description: description:
"Something went wrong and the payment never registered" + "Something went wrong and the payment never registered" +
"ask user if they can provide a bill or payment proof" + "ask user if they can provide a bill or payment proof" +
"if provided, re-do the booking and enable the features for the user", "if provided, re-do the booking and enable the features for the user",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "payment", keyword: "payment",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "unregistered", keyword: "unregistered",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "inaccessible", keyword: "inaccessible",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "features", keyword: "features",
}), }),
], ],
}) })
const knowledgebaseEntry3: KnowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgebaseEntry3: KnowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
title: "Features don't work as intended, or are buggy", title: "Features don't work as intended, or are buggy",
description: description:
"The user has reported features that do not work as intended and hinder the users' experience" + "The user has reported features that do not work as intended and hinder the users' experience" +
@ -140,16 +141,16 @@ o.spec("KnowledgeBaseSearchFilter", function () {
"if the problem is known, explain that the team is working on a fix, or explain a temporary fix" + "if the problem is known, explain that the team is working on a fix, or explain a temporary fix" +
"if its a new problem, tell the user that it has been reported to the team and will be taken care of", "if its a new problem, tell the user that it has been reported to the team and will be taken care of",
keywords: [ keywords: [
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "functionality", keyword: "functionality",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "not", keyword: "not",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "working", keyword: "working",
}), }),
createKnowledgeBaseEntryKeyword({ createTestEntity(KnowledgeBaseEntryKeywordTypeRef, {
keyword: "bug", keyword: "bug",
}), }),
], ],

View file

@ -5,7 +5,7 @@ import { spy } from "@tutao/tutanota-test-utils"
import type { MailboxDetail } from "../../../src/mail/model/MailModel.js" import type { MailboxDetail } from "../../../src/mail/model/MailModel.js"
import { MailModel } from "../../../src/mail/model/MailModel.js" import { MailModel } from "../../../src/mail/model/MailModel.js"
import { MailFolderType, OperationType } from "../../../src/api/common/TutanotaConstants.js" import { MailFolderType, OperationType } from "../../../src/api/common/TutanotaConstants.js"
import { createMailFolder, MailTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js" import { MailFolderTypeRef, MailTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js"
import type { EntityUpdateData } from "../../../src/api/main/EventController.js" import type { EntityUpdateData } from "../../../src/api/main/EventController.js"
import { EntityClient } from "../../../src/api/common/EntityClient.js" import { EntityClient } from "../../../src/api/common/EntityClient.js"
import { EntityRestClientMock } from "../api/worker/rest/EntityRestClientMock.js" import { EntityRestClientMock } from "../api/worker/rest/EntityRestClientMock.js"
@ -18,15 +18,16 @@ import { FolderSystem } from "../../../src/api/common/mail/FolderSystem.js"
import { WebsocketConnectivityModel } from "../../../src/misc/WebsocketConnectivityModel.js" import { WebsocketConnectivityModel } from "../../../src/misc/WebsocketConnectivityModel.js"
import { InboxRuleHandler } from "../../../src/mail/model/InboxRuleHandler.js" import { InboxRuleHandler } from "../../../src/mail/model/InboxRuleHandler.js"
import { UserController } from "../../../src/api/main/UserController.js" import { UserController } from "../../../src/api/main/UserController.js"
import { createTestEntity } from "../TestUtils.js"
o.spec("MailModelTest", function () { o.spec("MailModelTest", function () {
let notifications: Partial<Notifications> let notifications: Partial<Notifications>
let showSpy: Spy let showSpy: Spy
let model: MailModel let model: MailModel
const inboxFolder = createMailFolder({ _id: ["folderListId", "inboxId"] }) const inboxFolder = createTestEntity(MailFolderTypeRef, { _id: ["folderListId", "inboxId"] })
inboxFolder.mails = "instanceListId" inboxFolder.mails = "instanceListId"
inboxFolder.folderType = MailFolderType.INBOX inboxFolder.folderType = MailFolderType.INBOX
const anotherFolder = createMailFolder({ _id: ["folderListId", "archiveId"] }) const anotherFolder = createTestEntity(MailFolderTypeRef, { _id: ["folderListId", "archiveId"] })
anotherFolder.mails = "anotherListId" anotherFolder.mails = "anotherListId"
anotherFolder.folderType = MailFolderType.ARCHIVE anotherFolder.folderType = MailFolderType.ARCHIVE
let mailboxDetails: Partial<MailboxDetail>[] let mailboxDetails: Partial<MailboxDetail>[]

View file

@ -5,6 +5,7 @@ import type { UserController } from "../../../src/api/main/UserController.js"
import type { LoginController } from "../../../src/api/main/LoginController.js" import type { LoginController } from "../../../src/api/main/LoginController.js"
import { MailboxDetail, MailModel } from "../../../src/mail/model/MailModel.js" import { MailboxDetail, MailModel } from "../../../src/mail/model/MailModel.js"
import { import {
BodyTypeRef,
Contact, Contact,
ContactListTypeRef, ContactListTypeRef,
ContactTypeRef, ContactTypeRef,
@ -24,8 +25,10 @@ import {
MailboxGroupRootTypeRef, MailboxGroupRootTypeRef,
MailboxPropertiesTypeRef, MailboxPropertiesTypeRef,
MailBoxTypeRef, MailBoxTypeRef,
MailDetailsTypeRef,
MailTypeRef, MailTypeRef,
NotificationMailTypeRef, NotificationMailTypeRef,
TutanotaPropertiesTypeRef,
} from "../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { ContactModel } from "../../../src/contacts/model/ContactModel.js" import { ContactModel } from "../../../src/contacts/model/ContactModel.js"
import { assertThrows, verify } from "@tutao/tutanota-test-utils" import { assertThrows, verify } from "@tutao/tutanota-test-utils"
@ -39,6 +42,8 @@ import {
createGroupMembership, createGroupMembership,
createUser, createUser,
CustomerTypeRef, CustomerTypeRef,
GroupInfoTypeRef,
GroupMembershipTypeRef,
GroupTypeRef, GroupTypeRef,
UserTypeRef, UserTypeRef,
} from "../../../src/api/entities/sys/TypeRefs.js" } from "../../../src/api/entities/sys/TypeRefs.js"
@ -134,19 +139,19 @@ o.spec("SendMailModel", function () {
when(mailFacade.getRecipientKeyData(anything())).thenResolve(null) when(mailFacade.getRecipientKeyData(anything())).thenResolve(null)
when(mailFacade.getAttachmentIds(anything())).thenResolve([]) when(mailFacade.getAttachmentIds(anything())).thenResolve([])
const tutanotaProperties = createTutanotaProperties({ const tutanotaProperties = createTestEntity(TutanotaPropertiesTypeRef, {
defaultSender: DEFAULT_SENDER_FOR_TESTING, defaultSender: DEFAULT_SENDER_FOR_TESTING,
defaultUnconfidential: true, defaultUnconfidential: true,
notificationMailLanguage: "en", notificationMailLanguage: "en",
noAutomaticContacts: false, noAutomaticContacts: false,
}) })
const user = createUser({ const user = createTestEntity(UserTypeRef, {
userGroup: createGroupMembership({ userGroup: createTestEntity(GroupMembershipTypeRef, {
_id: testIdGenerator.newId(), _id: testIdGenerator.newId(),
group: testIdGenerator.newId(), group: testIdGenerator.newId(),
}), }),
memberships: [ memberships: [
createGroupMembership({ createTestEntity(GroupMembershipTypeRef, {
_id: testIdGenerator.newId(), _id: testIdGenerator.newId(),
groupType: GroupType.Contact, groupType: GroupType.Contact,
}), }),
@ -167,7 +172,7 @@ o.spec("SendMailModel", function () {
const mailboxDetails: MailboxDetail = { const mailboxDetails: MailboxDetail = {
mailbox: createTestEntity(MailBoxTypeRef), mailbox: createTestEntity(MailBoxTypeRef),
folders: new FolderSystem([]), folders: new FolderSystem([]),
mailGroupInfo: createGroupInfo({ mailGroupInfo: createTestEntity(GroupInfoTypeRef, {
mailAddress: "mailgroup@addre.ss", mailAddress: "mailgroup@addre.ss",
}), }),
mailGroup: createTestEntity(GroupTypeRef), mailGroup: createTestEntity(GroupTypeRef),
@ -270,7 +275,7 @@ o.spec("SendMailModel", function () {
o(initializedModel.hasMailChanged()).equals(false)("initialization should not flag mail changed") o(initializedModel.hasMailChanged()).equals(false)("initialization should not flag mail changed")
}) })
o("initWithDraft with blank data", async function () { o("initWithDraft with blank data", async function () {
const draftMail = createMail({ const draftMail = createTestEntity(MailTypeRef, {
confidential: false, confidential: false,
sender: createTestEntity(MailAddressTypeRef), sender: createTestEntity(MailAddressTypeRef),
toRecipients: [], toRecipients: [],
@ -282,14 +287,14 @@ o.spec("SendMailModel", function () {
}) })
const mailWrapper = MailWrapper.details( const mailWrapper = MailWrapper.details(
draftMail, draftMail,
createMailDetails({ createTestEntity(MailDetailsTypeRef, {
body: createBody({ body: createTestEntity(BodyTypeRef, {
text: BODY_TEXT_1, text: BODY_TEXT_1,
}), }),
}), }),
) )
when(entity.load(ConversationEntryTypeRef, draftMail.conversationEntry)).thenResolve( when(entity.load(ConversationEntryTypeRef, draftMail.conversationEntry)).thenResolve(
createConversationEntry({ conversationType: ConversationType.REPLY }), createTestEntity(ConversationEntryTypeRef, { conversationType: ConversationType.REPLY }),
) )
const initializedModel = await model.initWithDraft([], mailWrapper, new Map()) const initializedModel = await model.initWithDraft([], mailWrapper, new Map())
o(initializedModel.getConversationType()).equals(ConversationType.REPLY) o(initializedModel.getConversationType()).equals(ConversationType.REPLY)
@ -304,19 +309,19 @@ o.spec("SendMailModel", function () {
o(initializedModel.hasMailChanged()).equals(false)("initialization should not flag mail changed") o(initializedModel.hasMailChanged()).equals(false)("initialization should not flag mail changed")
}) })
o("initWithDraft with some data", async function () { o("initWithDraft with some data", async function () {
const draftMail = createMail({ const draftMail = createTestEntity(MailTypeRef, {
confidential: true, confidential: true,
sender: createTestEntity(MailAddressTypeRef), sender: createTestEntity(MailAddressTypeRef),
toRecipients: [ toRecipients: [
createMailAddress({ createTestEntity(MailAddressTypeRef, {
address: "", address: "",
}), }),
createMailAddress({ createTestEntity(MailAddressTypeRef, {
address: EXTERNAL_ADDRESS_1, address: EXTERNAL_ADDRESS_1,
}), }),
], ],
ccRecipients: [ ccRecipients: [
createMailAddress({ createTestEntity(MailAddressTypeRef, {
address: EXTERNAL_ADDRESS_2, address: EXTERNAL_ADDRESS_2,
}), }),
], ],
@ -325,10 +330,13 @@ o.spec("SendMailModel", function () {
replyTos: [], replyTos: [],
conversationEntry: testIdGenerator.newIdTuple(), conversationEntry: testIdGenerator.newIdTuple(),
}) })
const mailWrapper = MailWrapper.details(draftMail, createMailDetails({ body: createBody({ text: BODY_TEXT_1 }) })) const mailWrapper = MailWrapper.details(
draftMail,
createTestEntity(MailDetailsTypeRef, { body: createTestEntity(BodyTypeRef, { text: BODY_TEXT_1 }) }),
)
when(entity.load(ConversationEntryTypeRef, draftMail.conversationEntry)).thenResolve( when(entity.load(ConversationEntryTypeRef, draftMail.conversationEntry)).thenResolve(
createConversationEntry({ conversationType: ConversationType.FORWARD }), createTestEntity(ConversationEntryTypeRef, { conversationType: ConversationType.FORWARD }),
) )
const initializedModel = await model.initWithDraft([], mailWrapper, new Map()) const initializedModel = await model.initWithDraft([], mailWrapper, new Map())
@ -539,7 +547,7 @@ o.spec("SendMailModel", function () {
o("when a recipient has an existing contact, and the saved password changes, then the contact will be updated", async function () { o("when a recipient has an existing contact, and the saved password changes, then the contact will be updated", async function () {
const getConfirmation = func<(TranslationKey) => Promise<boolean>>() const getConfirmation = func<(TranslationKey) => Promise<boolean>>()
const contact = createContact({ const contact = createTestEntity(ContactTypeRef, {
_id: testIdGenerator.newIdTuple(), _id: testIdGenerator.newIdTuple(),
firstName: "my", firstName: "my",
lastName: "chippie", lastName: "chippie",
@ -563,7 +571,7 @@ o.spec("SendMailModel", function () {
let existingContact let existingContact
let recipients let recipients
o.before(function () { o.before(function () {
existingContact = createContact({ existingContact = createTestEntity(ContactTypeRef, {
_id: testIdGenerator.newIdTuple(), _id: testIdGenerator.newIdTuple(),
firstName: "james", firstName: "james",
lastName: "hetfield", lastName: "hetfield",
@ -600,10 +608,10 @@ o.spec("SendMailModel", function () {
firstName: "newfirstname", firstName: "newfirstname",
lastName: "newlastname", lastName: "newlastname",
mailAddresses: [ mailAddresses: [
createMailAddress({ createTestEntity(MailAddressTypeRef, {
address: "james@tuta.com", address: "james@tuta.com",
}), }),
createMailAddress({ createTestEntity(MailAddressTypeRef, {
address: "address2@hotmail.com", address: "address2@hotmail.com",
}), }),
], ],
@ -633,7 +641,7 @@ o.spec("SendMailModel", function () {
firstName: "james", firstName: "james",
lastName: "hetfield", lastName: "hetfield",
mailAddresses: [ mailAddresses: [
createMailAddress({ createTestEntity(MailAddressTypeRef, {
address: "nolongerjames@hotmail.com", address: "nolongerjames@hotmail.com",
}), }),
], ],

View file

@ -1,46 +1,52 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import type { EmailTemplate } from "../../../src/api/entities/tutanota/TypeRefs.js" import type { EmailTemplate } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { createEmailTemplate, createEmailTemplateContent } from "../../../src/api/entities/tutanota/TypeRefs.js" import {
createEmailTemplate,
createEmailTemplateContent,
EmailTemplateContentTypeRef,
EmailTemplateTypeRef,
} from "../../../src/api/entities/tutanota/TypeRefs.js"
import { searchInTemplates } from "../../../src/templates/model/TemplatePopupModel.js" import { searchInTemplates } from "../../../src/templates/model/TemplatePopupModel.js"
import { createTestEntity } from "../TestUtils.js"
o.spec("TemplateSearchFilter", function () { o.spec("TemplateSearchFilter", function () {
const abcTemplate = createEmailTemplate({ const abcTemplate = createTestEntity(EmailTemplateTypeRef, {
tag: "aBc_tag", tag: "aBc_tag",
title: "aBc_title", title: "aBc_title",
contents: [ contents: [
createEmailTemplateContent({ createTestEntity(EmailTemplateContentTypeRef, {
languageCode: "en", languageCode: "en",
text: "aBc english", text: "aBc english",
}), }),
createEmailTemplateContent({ createTestEntity(EmailTemplateContentTypeRef, {
languageCode: "de", languageCode: "de",
text: "aBc deutsch", text: "aBc deutsch",
}), }),
], ],
}) })
const defTemplate = createEmailTemplate({ const defTemplate = createTestEntity(EmailTemplateTypeRef, {
tag: "dEf_tag", tag: "dEf_tag",
title: "dEf_title", title: "dEf_title",
contents: [ contents: [
createEmailTemplateContent({ createTestEntity(EmailTemplateContentTypeRef, {
languageCode: "en", languageCode: "en",
text: "dEf english", text: "dEf english",
}), }),
createEmailTemplateContent({ createTestEntity(EmailTemplateContentTypeRef, {
languageCode: "de", languageCode: "de",
text: "dEf deutsch", text: "dEf deutsch",
}), }),
], ],
}) })
const abcdefTemplate = createEmailTemplate({ const abcdefTemplate = createTestEntity(EmailTemplateTypeRef, {
tag: "abcdef_tag", tag: "abcdef_tag",
title: "abcdef_title", title: "abcdef_title",
contents: [ contents: [
createEmailTemplateContent({ createTestEntity(EmailTemplateContentTypeRef, {
languageCode: "en", languageCode: "en",
text: "abcdef english", text: "abcdef english",
}), }),
createEmailTemplateContent({ createTestEntity(EmailTemplateContentTypeRef, {
languageCode: "de", languageCode: "de",
text: "abcdef deutsch", text: "abcdef deutsch",
}), }),

View file

@ -5,8 +5,10 @@ import {
createMail, createMail,
createMailAddress, createMailAddress,
FileTypeRef, FileTypeRef,
MailAddressTypeRef,
MailBodyTypeRef, MailBodyTypeRef,
MailHeadersTypeRef, MailHeadersTypeRef,
MailTypeRef,
} from "../../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../../src/api/entities/tutanota/TypeRefs.js"
import { MailState } from "../../../../src/api/common/TutanotaConstants.js" import { MailState } from "../../../../src/api/common/TutanotaConstants.js"
import { DataFile } from "../../../../src/api/common/DataFile.js" import { DataFile } from "../../../../src/api/common/DataFile.js"
@ -15,6 +17,7 @@ import { EntityClient } from "../../../../src/api/common/EntityClient.js"
import { FileController } from "../../../../src/file/FileController.js" import { FileController } from "../../../../src/file/FileController.js"
import { object, when } from "testdouble" import { object, when } from "testdouble"
import { MailFacade } from "../../../../src/api/worker/facades/lazy/MailFacade.js" import { MailFacade } from "../../../../src/api/worker/facades/lazy/MailFacade.js"
import { createTestEntity } from "../../TestUtils.js"
o.spec("Bundler", function () { o.spec("Bundler", function () {
let entityClientMock: EntityClient let entityClientMock: EntityClient
@ -43,8 +46,8 @@ o.spec("Bundler", function () {
const receivedOn = new Date() const receivedOn = new Date()
const headers = "this is the headers" const headers = "this is the headers"
const mailHeadersId = "mailheadersid" const mailHeadersId = "mailheadersid"
const attachmentListId = "attachmentListId" const attachmentListId: Id = "attachmentListId"
const attachmentIds = ["attachmentId1", "attachmentId2", "attachmentId3"] const attachmentIds: Id[] = ["attachmentId1", "attachmentId2", "attachmentId3"]
const attachments: Array<DataFile> = attachmentIds.map((id) => { const attachments: Array<DataFile> = attachmentIds.map((id) => {
return { return {
_type: "DataFile", _type: "DataFile",
@ -56,11 +59,11 @@ o.spec("Bundler", function () {
mimeType: "test", mimeType: "test",
} }
}) })
const mail = createMail({ const mail = createTestEntity(MailTypeRef, {
_id: mailId, _id: mailId,
body: mailBodyId, body: mailBodyId,
subject, subject,
sender: createMailAddress(sender), sender: createTestEntity(MailAddressTypeRef, sender),
toRecipients: to.map(createMailAddress), toRecipients: to.map(createMailAddress),
ccRecipients: cc.map(createMailAddress), ccRecipients: cc.map(createMailAddress),
bccRecipients: bcc.map(createMailAddress), bccRecipients: bcc.map(createMailAddress),
@ -70,7 +73,7 @@ o.spec("Bundler", function () {
receivedDate: receivedOn, receivedDate: receivedOn,
sentDate: sentOn, sentDate: sentOn,
headers: mailHeadersId, headers: mailHeadersId,
attachments: attachmentIds.map((id) => [attachmentListId, id]), attachments: attachmentIds.map((id) => [attachmentListId, id] as IdTuple),
}) })
when(entityClientMock.load(MailHeadersTypeRef, mailHeadersId)).thenResolve({ headers }) when(entityClientMock.load(MailHeadersTypeRef, mailHeadersId)).thenResolve({ headers })

View file

@ -1,31 +1,32 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { createMailFolder } from "../../../../src/api/entities/tutanota/TypeRefs.js" import { createMailFolder, MailFolderTypeRef } from "../../../../src/api/entities/tutanota/TypeRefs.js"
import { MailFolderType } from "../../../../src/api/common/TutanotaConstants.js" import { MailFolderType } from "../../../../src/api/common/TutanotaConstants.js"
import { FolderSystem } from "../../../../src/api/common/mail/FolderSystem.js" import { FolderSystem } from "../../../../src/api/common/mail/FolderSystem.js"
import { createTestEntity } from "../../TestUtils.js"
o.spec("FolderSystem", function () { o.spec("FolderSystem", function () {
const listId = "listId" const listId = "listId"
const inbox = createMailFolder({ _id: [listId, "inbox"], folderType: MailFolderType.INBOX }) const inbox = createTestEntity(MailFolderTypeRef, { _id: [listId, "inbox"], folderType: MailFolderType.INBOX })
const archive = createMailFolder({ _id: [listId, "archive"], folderType: MailFolderType.ARCHIVE }) const archive = createTestEntity(MailFolderTypeRef, { _id: [listId, "archive"], folderType: MailFolderType.ARCHIVE })
const customFolder = createMailFolder({ const customFolder = createTestEntity(MailFolderTypeRef, {
_id: [listId, "custom"], _id: [listId, "custom"],
folderType: MailFolderType.CUSTOM, folderType: MailFolderType.CUSTOM,
name: "X", name: "X",
}) })
const customSubfolder = createMailFolder({ const customSubfolder = createTestEntity(MailFolderTypeRef, {
_id: [listId, "customSub"], _id: [listId, "customSub"],
folderType: MailFolderType.CUSTOM, folderType: MailFolderType.CUSTOM,
parentFolder: customFolder._id, parentFolder: customFolder._id,
name: "AA", name: "AA",
mails: "customSubMailList", mails: "customSubMailList",
}) })
const customSubSubfolder = createMailFolder({ const customSubSubfolder = createTestEntity(MailFolderTypeRef, {
_id: [listId, "customSubSub"], _id: [listId, "customSubSub"],
folderType: MailFolderType.CUSTOM, folderType: MailFolderType.CUSTOM,
parentFolder: customSubfolder._id, parentFolder: customSubfolder._id,
name: "B", name: "B",
}) })
const customSubSubfolderAnother = createMailFolder({ const customSubSubfolderAnother = createTestEntity(MailFolderTypeRef, {
_id: [listId, "customSubSubAnother"], _id: [listId, "customSubSubAnother"],
folderType: MailFolderType.CUSTOM, folderType: MailFolderType.CUSTOM,
parentFolder: customSubfolder._id, parentFolder: customSubfolder._id,
@ -71,12 +72,12 @@ o.spec("FolderSystem", function () {
}) })
o("indented list sorts stepsiblings correctly", function () { o("indented list sorts stepsiblings correctly", function () {
const customFolderAnother = createMailFolder({ const customFolderAnother = createTestEntity(MailFolderTypeRef, {
_id: [listId, "customAnother"], _id: [listId, "customAnother"],
folderType: MailFolderType.CUSTOM, folderType: MailFolderType.CUSTOM,
name: "Another top-level custom", name: "Another top-level custom",
}) })
const customFolderAnotherSub = createMailFolder({ const customFolderAnotherSub = createTestEntity(MailFolderTypeRef, {
_id: [listId, "customAnotherSub"], _id: [listId, "customAnotherSub"],
folderType: MailFolderType.CUSTOM, folderType: MailFolderType.CUSTOM,
parentFolder: customFolderAnother._id, parentFolder: customFolderAnother._id,

View file

@ -2,6 +2,7 @@ import o from "@tutao/otest"
import { ConversationItem, ConversationPrefProvider, ConversationViewModel } from "../../../../src/mail/view/ConversationViewModel.js" import { ConversationItem, ConversationPrefProvider, ConversationViewModel } from "../../../../src/mail/view/ConversationViewModel.js"
import { import {
ConversationEntry, ConversationEntry,
ConversationEntryTypeRef,
createConversationEntry, createConversationEntry,
createMail, createMail,
createMailboxProperties, createMailboxProperties,
@ -9,6 +10,8 @@ import {
Mail, Mail,
MailboxProperties, MailboxProperties,
MailboxPropertiesTypeRef, MailboxPropertiesTypeRef,
MailFolderTypeRef,
MailTypeRef,
} from "../../../../src/api/entities/tutanota/TypeRefs.js" } from "../../../../src/api/entities/tutanota/TypeRefs.js"
import { ownerId } from "../../calendar/CalendarTestUtils.js" import { ownerId } from "../../calendar/CalendarTestUtils.js"
import { CreateMailViewerOptions } from "../../../../src/mail/view/MailViewer.js" import { CreateMailViewerOptions } from "../../../../src/mail/view/MailViewer.js"
@ -82,12 +85,12 @@ o.spec("ConversationViewModel", function () {
const addMail = (mailId: string): Mail => { const addMail = (mailId: string): Mail => {
const conversationId = "conversation" + mailId const conversationId = "conversation" + mailId
const newMail = createMail({ const newMail = createTestEntity(MailTypeRef, {
_id: [listId, mailId], _id: [listId, mailId],
conversationEntry: [listId, conversationId], conversationEntry: [listId, conversationId],
state: MailState.RECEIVED, state: MailState.RECEIVED,
}) })
const mailConversationEntry = createConversationEntry({ const mailConversationEntry = createTestEntity(ConversationEntryTypeRef, {
_id: [listId, conversationId], _id: [listId, conversationId],
mail: newMail._id, mail: newMail._id,
previous: primaryMail?._id, previous: primaryMail?._id,
@ -175,7 +178,7 @@ o.spec("ConversationViewModel", function () {
const trashDraftMail = addMail("trashDraftMail") const trashDraftMail = addMail("trashDraftMail")
trashDraftMail.state = MailState.DRAFT trashDraftMail.state = MailState.DRAFT
const trash = createMailFolder({ _id: [listId, "trashFolder"], folderType: MailFolderType.TRASH }) const trash = createTestEntity(MailFolderTypeRef, { _id: [listId, "trashFolder"], folderType: MailFolderType.TRASH })
entityRestClientMock.addListInstances(trash) entityRestClientMock.addListInstances(trash)
when(mailModel.getMailboxDetailsForMail(matchers.anything())).thenResolve(mailboxDetail) when(mailModel.getMailboxDetailsForMail(matchers.anything())).thenResolve(mailboxDetail)
@ -197,7 +200,7 @@ o.spec("ConversationViewModel", function () {
const trashDraftMail = addMail("trashDraftMail") const trashDraftMail = addMail("trashDraftMail")
trashDraftMail.state = MailState.DRAFT trashDraftMail.state = MailState.DRAFT
const trash = createMailFolder({ _id: [listId, "trashFolder"], folderType: MailFolderType.TRASH }) const trash = createTestEntity(MailFolderTypeRef, { _id: [listId, "trashFolder"], folderType: MailFolderType.TRASH })
entityRestClientMock.addListInstances(trash) entityRestClientMock.addListInstances(trash)
when(mailModel.getMailboxDetailsForMail(trashDraftMail)).thenResolve(mailboxDetail) when(mailModel.getMailboxDetailsForMail(trashDraftMail)).thenResolve(mailboxDetail)
@ -248,13 +251,13 @@ o.spec("ConversationViewModel", function () {
await loadingDefer.promise await loadingDefer.promise
conversation.pop() // "deleting" the mail conversation.pop() // "deleting" the mail
const mailConversationEntry = createConversationEntry({ const mailConversationEntry = createTestEntity(ConversationEntryTypeRef, {
_id: anotherMail.conversationEntry, _id: anotherMail.conversationEntry,
mail: anotherMail._id, mail: anotherMail._id,
previous: primaryMail?._id, previous: primaryMail?._id,
}) })
await entityRestClientMock.erase(mailConversationEntry) await entityRestClientMock.erase(mailConversationEntry)
const deletedmailConversationEntry = createConversationEntry({ const deletedmailConversationEntry = createTestEntity(ConversationEntryTypeRef, {
_id: anotherMail.conversationEntry, _id: anotherMail.conversationEntry,
previous: primaryMail?._id, previous: primaryMail?._id,
}) })
@ -313,7 +316,7 @@ o.spec("ConversationViewModel", function () {
await loadingDefer.promise await loadingDefer.promise
conversation.pop() conversation.pop()
const trash = createMailFolder({ _id: ["newListId", "trashFolder"], folderType: MailFolderType.TRASH }) const trash = createTestEntity(MailFolderTypeRef, { _id: ["newListId", "trashFolder"], folderType: MailFolderType.TRASH })
entityRestClientMock.addListInstances(trash) entityRestClientMock.addListInstances(trash)
// adding new mail (is the same mail, just moved to trash) // adding new mail (is the same mail, just moved to trash)
const newTrashDraftMail = addMail("trashDraftMail") const newTrashDraftMail = addMail("trashDraftMail")

View file

@ -2,11 +2,12 @@ import o from "@tutao/otest"
import { ListModel, ListModelConfig } from "../../../src/misc/ListModel.js" import { ListModel, ListModelConfig } from "../../../src/misc/ListModel.js"
import { GENERATED_MAX_ID, getElementId, sortCompareById, timestampToGeneratedId } from "../../../src/api/common/utils/EntityUtils.js" import { GENERATED_MAX_ID, getElementId, sortCompareById, timestampToGeneratedId } from "../../../src/api/common/utils/EntityUtils.js"
import { defer, DeferredObject } from "@tutao/tutanota-utils" import { defer, DeferredObject } from "@tutao/tutanota-utils"
import { createKnowledgeBaseEntry, KnowledgeBaseEntry } from "../../../src/api/entities/tutanota/TypeRefs.js" import { createKnowledgeBaseEntry, KnowledgeBaseEntry, KnowledgeBaseEntryTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { ListFetchResult } from "../../../src/gui/base/ListUtils.js" import { ListFetchResult } from "../../../src/gui/base/ListUtils.js"
import { ListLoadingState } from "../../../src/gui/base/List.js" import { ListLoadingState } from "../../../src/gui/base/List.js"
import { ConnectionError } from "../../../src/api/common/error/RestError.js" import { ConnectionError } from "../../../src/api/common/error/RestError.js"
import { OperationType } from "../../../src/api/common/TutanotaConstants.js" import { OperationType } from "../../../src/api/common/TutanotaConstants.js"
import { createTestEntity } from "../TestUtils.js"
o.spec("ListModel", function () { o.spec("ListModel", function () {
const listId = "listId" const listId = "listId"
@ -21,19 +22,19 @@ o.spec("ListModel", function () {
}, },
} }
const itemA = createKnowledgeBaseEntry({ const itemA = createTestEntity(KnowledgeBaseEntryTypeRef, {
_id: [listId, "a"], _id: [listId, "a"],
title: "a", title: "a",
}) })
const itemB = createKnowledgeBaseEntry({ const itemB = createTestEntity(KnowledgeBaseEntryTypeRef, {
_id: [listId, "b"], _id: [listId, "b"],
title: "b", title: "b",
}) })
const itemC = createKnowledgeBaseEntry({ const itemC = createTestEntity(KnowledgeBaseEntryTypeRef, {
_id: [listId, "c"], _id: [listId, "c"],
title: "c", title: "c",
}) })
const itemD = createKnowledgeBaseEntry({ const itemD = createTestEntity(KnowledgeBaseEntryTypeRef, {
_id: [listId, "d"], _id: [listId, "d"],
title: "d", title: "d",
}) })
@ -84,7 +85,7 @@ o.spec("ListModel", function () {
const moreLoading = listModel.loadMore() const moreLoading = listModel.loadMore()
o(listModel.state.loadingStatus).equals(ListLoadingState.Loading) o(listModel.state.loadingStatus).equals(ListLoadingState.Loading)
const knowledgeBaseEntry = createKnowledgeBaseEntry({ const knowledgeBaseEntry = createTestEntity(KnowledgeBaseEntryTypeRef, {
_id: [listId, timestampToGeneratedId(10)], _id: [listId, timestampToGeneratedId(10)],
}) })
fetchDefer.resolve({ fetchDefer.resolve({
@ -736,7 +737,7 @@ o.spec("ListModel", function () {
o.spec("Updating items", function () { o.spec("Updating items", function () {
o("update for item with id sorting updates item", async function () { o("update for item with id sorting updates item", async function () {
const updatedItemD = createKnowledgeBaseEntry({ ...itemD, title: "AA" }) const updatedItemD = createTestEntity(KnowledgeBaseEntryTypeRef, { ...itemD, title: "AA" })
const newConfig: ListModelConfig<KnowledgeBaseEntry> = { const newConfig: ListModelConfig<KnowledgeBaseEntry> = {
...defaultListConfig, ...defaultListConfig,
@ -758,7 +759,7 @@ o.spec("ListModel", function () {
}) })
o("update for item with custom sorting changes position", async function () { o("update for item with custom sorting changes position", async function () {
const updatedItemD = createKnowledgeBaseEntry({ ...itemD, title: "AA" }) const updatedItemD = createTestEntity(KnowledgeBaseEntryTypeRef, { ...itemD, title: "AA" })
const newConfig: ListModelConfig<KnowledgeBaseEntry> = { const newConfig: ListModelConfig<KnowledgeBaseEntry> = {
...defaultListConfig, ...defaultListConfig,

View file

@ -3,9 +3,10 @@ import { IServiceExecutor } from "../../../src/api/common/ServiceRequest.js"
import { object, verify, when } from "testdouble" import { object, verify, when } from "testdouble"
import { NewsItemStorage, NewsModel } from "../../../src/misc/news/NewsModel.js" import { NewsItemStorage, NewsModel } from "../../../src/misc/news/NewsModel.js"
import { NewsService } from "../../../src/api/entities/tutanota/Services.js" import { NewsService } from "../../../src/api/entities/tutanota/Services.js"
import { createNewsId, createNewsIn, createNewsOut, NewsId } from "../../../src/api/entities/tutanota/TypeRefs.js" import { createNewsId, createNewsIn, createNewsOut, NewsId, NewsIdTypeRef, NewsInTypeRef, NewsOutTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { NewsListItem } from "../../../src/misc/news/NewsListItem.js" import { NewsListItem } from "../../../src/misc/news/NewsListItem.js"
import { Children } from "mithril" import { Children } from "mithril"
import { createTestEntity } from "../TestUtils.js"
o.spec("NewsModel", function () { o.spec("NewsModel", function () {
let newsModel: NewsModel let newsModel: NewsModel
@ -30,14 +31,14 @@ o.spec("NewsModel", function () {
newsModel = new NewsModel(serviceExecutor, storage, async () => new DummyNews()) newsModel = new NewsModel(serviceExecutor, storage, async () => new DummyNews())
newsIds = [ newsIds = [
createNewsId({ createTestEntity(NewsIdTypeRef, {
newsItemId: "ID:dummyNews", newsItemId: "ID:dummyNews",
newsItemName: "dummyNews", newsItemName: "dummyNews",
}), }),
] ]
when(serviceExecutor.get(NewsService, null)).thenResolve( when(serviceExecutor.get(NewsService, null)).thenResolve(
createNewsOut({ createTestEntity(NewsOutTypeRef, {
newsItemIds: newsIds, newsItemIds: newsIds,
}), }),
) )
@ -56,7 +57,8 @@ o.spec("NewsModel", function () {
await newsModel.acknowledgeNews(newsIds[0].newsItemId) await newsModel.acknowledgeNews(newsIds[0].newsItemId)
verify(serviceExecutor.post(NewsService, createNewsIn({ newsItemId: newsIds[0].newsItemId }))) const expectedNewsIn = createTestEntity(NewsInTypeRef, { newsItemId: newsIds[0].newsItemId })
verify(serviceExecutor.post(NewsService, expectedNewsIn))
}) })
}) })
}) })

View file

@ -1,9 +1,10 @@
import o from "@tutao/otest" import o from "@tutao/otest"
import { createOutOfOfficeNotification } from "../../../src/api/entities/tutanota/TypeRefs.js" import { OutOfOfficeNotificationTypeRef } from "../../../src/api/entities/tutanota/TypeRefs.js"
import { mockAttribute, unmockAttribute } from "@tutao/tutanota-test-utils" import { mockAttribute, unmockAttribute } from "@tutao/tutanota-test-utils"
import { getDayShifted, getStartOfDay, getStartOfNextDay } from "@tutao/tutanota-utils" import { getDayShifted, getStartOfDay, getStartOfNextDay } from "@tutao/tutanota-utils"
import { lang } from "../../../src/misc/LanguageViewModel.js" import { lang } from "../../../src/misc/LanguageViewModel.js"
import { formatActivateState, isNotificationCurrentlyActive } from "../../../src/misc/OutOfOfficeNotificationUtils.js" import { formatActivateState, isNotificationCurrentlyActive } from "../../../src/misc/OutOfOfficeNotificationUtils.js"
import { createTestEntity } from "../TestUtils.js"
o.spec("OutOfOfficeNotificationTest", function () { o.spec("OutOfOfficeNotificationTest", function () {
const mockedAttributes: any = [] const mockedAttributes: any = []
@ -28,26 +29,26 @@ o.spec("OutOfOfficeNotificationTest", function () {
o("Active state formatting", function () { o("Active state formatting", function () {
lang._setLanguageTag("en") lang._setLanguageTag("en")
let notification = createOutOfOfficeNotification({ let notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: null, startDate: null,
endDate: null, endDate: null,
}) })
o(formatActivateState(notification)).equals("Activated") o(formatActivateState(notification)).equals("Activated")
notification = createOutOfOfficeNotification({ notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: new Date(2020, 11, 15), startDate: new Date(2020, 11, 15),
endDate: null, endDate: null,
}) })
o(formatActivateState(notification)).equals("Activated (12/15/2020)") o(formatActivateState(notification)).equals("Activated (12/15/2020)")
notification = createOutOfOfficeNotification({ notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: new Date(2020, 11, 15), startDate: new Date(2020, 11, 15),
endDate: new Date(2021, 0, 9), endDate: new Date(2021, 0, 9),
}) })
o(formatActivateState(notification)).equals("Activated (12/15/2020 - 1/8/2021)") // end date should be shifted o(formatActivateState(notification)).equals("Activated (12/15/2020 - 1/8/2021)") // end date should be shifted
notification = createOutOfOfficeNotification({ notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: false, enabled: false,
startDate: new Date(2020, 11, 15), startDate: new Date(2020, 11, 15),
endDate: new Date(2021, 0, 10), endDate: new Date(2021, 0, 10),
@ -58,7 +59,7 @@ o.spec("OutOfOfficeNotificationTest", function () {
const now = new Date() const now = new Date()
const oneDayBefore = getDayShifted(now, -1) const oneDayBefore = getDayShifted(now, -1)
const oneDayAfter = getDayShifted(now, +1) const oneDayAfter = getDayShifted(now, +1)
let notification = createOutOfOfficeNotification({ let notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: null, startDate: null,
endDate: null, endDate: null,
@ -71,7 +72,7 @@ o.spec("OutOfOfficeNotificationTest", function () {
const now = new Date() const now = new Date()
const oneDayBefore = getDayShifted(now, -1) const oneDayBefore = getDayShifted(now, -1)
const oneDayAfter = getDayShifted(now, +1) const oneDayAfter = getDayShifted(now, +1)
let notification = createOutOfOfficeNotification({ let notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: false, enabled: false,
startDate: null, startDate: null,
endDate: null, endDate: null,
@ -84,7 +85,7 @@ o.spec("OutOfOfficeNotificationTest", function () {
const now = new Date() const now = new Date()
const oneDayBefore = getDayShifted(now, -1) const oneDayBefore = getDayShifted(now, -1)
const oneDayAfter = getDayShifted(now, +1) const oneDayAfter = getDayShifted(now, +1)
let notification = createOutOfOfficeNotification({ let notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: getStartOfDay(now), startDate: getStartOfDay(now),
endDate: null, endDate: null,
@ -97,7 +98,7 @@ o.spec("OutOfOfficeNotificationTest", function () {
const now = new Date() const now = new Date()
const oneDayBefore = getDayShifted(now, -1) const oneDayBefore = getDayShifted(now, -1)
const oneDayAfter = getDayShifted(now, +1) const oneDayAfter = getDayShifted(now, +1)
let notification = createOutOfOfficeNotification({ let notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: getStartOfDay(now), startDate: getStartOfDay(now),
endDate: getStartOfNextDay(now), endDate: getStartOfNextDay(now),
@ -110,7 +111,7 @@ o.spec("OutOfOfficeNotificationTest", function () {
const now = new Date() const now = new Date()
const activeUntil = getDayShifted(now, +5) const activeUntil = getDayShifted(now, +5)
const oneDayAfter = getStartOfNextDay(activeUntil) const oneDayAfter = getStartOfNextDay(activeUntil)
let notification = createOutOfOfficeNotification({ let notification = createTestEntity(OutOfOfficeNotificationTypeRef, {
enabled: true, enabled: true,
startDate: getStartOfDay(now), startDate: getStartOfDay(now),
endDate: getStartOfNextDay(activeUntil), endDate: getStartOfNextDay(activeUntil),

Some files were not shown because too many files have changed in this diff Show more