@rapidmx/activesync-plugin 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +382 -0
- package/README.md +57 -0
- package/dist/lib/BaseDeviceSyncStateRoute.js +90 -0
- package/dist/lib/BaseDeviceSyncStateRoute.js.map +1 -0
- package/dist/lib/BaseEasRoute.js +213 -0
- package/dist/lib/BaseEasRoute.js.map +1 -0
- package/dist/lib/CompactDateTime.js +43 -0
- package/dist/lib/CompactDateTime.js.map +1 -0
- package/dist/lib/EasCommandHandler.js +2 -0
- package/dist/lib/EasCommandHandler.js.map +1 -0
- package/dist/lib/EasSyncKeyUtils.js +119 -0
- package/dist/lib/EasSyncKeyUtils.js.map +1 -0
- package/dist/lib/adapters/CalendarSyncAdapter.js +255 -0
- package/dist/lib/adapters/CalendarSyncAdapter.js.map +1 -0
- package/dist/lib/adapters/ContactsSyncAdapter.js +164 -0
- package/dist/lib/adapters/ContactsSyncAdapter.js.map +1 -0
- package/dist/lib/adapters/EasCollectionSyncAdapter.js +2 -0
- package/dist/lib/adapters/EasCollectionSyncAdapter.js.map +1 -0
- package/dist/lib/adapters/EmailSyncAdapter.js +269 -0
- package/dist/lib/adapters/EmailSyncAdapter.js.map +1 -0
- package/dist/lib/adapters/TasksSyncAdapter.js +100 -0
- package/dist/lib/adapters/TasksSyncAdapter.js.map +1 -0
- package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js +16 -0
- package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js.map +1 -0
- package/dist/lib/adapters/mongo/index.js +6 -0
- package/dist/lib/adapters/mongo/index.js.map +1 -0
- package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js +16 -0
- package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js.map +1 -0
- package/dist/lib/adapters/sql/index.js +6 -0
- package/dist/lib/adapters/sql/index.js.map +1 -0
- package/dist/lib/codec/WbxmlCodePages.js +706 -0
- package/dist/lib/codec/WbxmlCodePages.js.map +1 -0
- package/dist/lib/codec/WbxmlDecoder.js +154 -0
- package/dist/lib/codec/WbxmlDecoder.js.map +1 -0
- package/dist/lib/codec/WbxmlElement.js +31 -0
- package/dist/lib/codec/WbxmlElement.js.map +1 -0
- package/dist/lib/codec/WbxmlEncoder.js +88 -0
- package/dist/lib/codec/WbxmlEncoder.js.map +1 -0
- package/dist/lib/commands/ComposeMailCommand.js +187 -0
- package/dist/lib/commands/ComposeMailCommand.js.map +1 -0
- package/dist/lib/commands/FolderSyncCommand.js +155 -0
- package/dist/lib/commands/FolderSyncCommand.js.map +1 -0
- package/dist/lib/commands/GetItemEstimateCommand.js +149 -0
- package/dist/lib/commands/GetItemEstimateCommand.js.map +1 -0
- package/dist/lib/commands/ItemOperationsCommand.js +337 -0
- package/dist/lib/commands/ItemOperationsCommand.js.map +1 -0
- package/dist/lib/commands/MeetingResponseCommand.js +120 -0
- package/dist/lib/commands/MeetingResponseCommand.js.map +1 -0
- package/dist/lib/commands/MoveItemsCommand.js +103 -0
- package/dist/lib/commands/MoveItemsCommand.js.map +1 -0
- package/dist/lib/commands/PingCommand.js +145 -0
- package/dist/lib/commands/PingCommand.js.map +1 -0
- package/dist/lib/commands/ProvisionCommand.js +164 -0
- package/dist/lib/commands/ProvisionCommand.js.map +1 -0
- package/dist/lib/commands/ResolveRecipientsCommand.js +123 -0
- package/dist/lib/commands/ResolveRecipientsCommand.js.map +1 -0
- package/dist/lib/commands/SearchCommand.js +234 -0
- package/dist/lib/commands/SearchCommand.js.map +1 -0
- package/dist/lib/commands/SendMailCommand.js +18 -0
- package/dist/lib/commands/SendMailCommand.js.map +1 -0
- package/dist/lib/commands/SettingsCommand.js +138 -0
- package/dist/lib/commands/SettingsCommand.js.map +1 -0
- package/dist/lib/commands/SmartForwardCommand.js +22 -0
- package/dist/lib/commands/SmartForwardCommand.js.map +1 -0
- package/dist/lib/commands/SmartReplyCommand.js +22 -0
- package/dist/lib/commands/SmartReplyCommand.js.map +1 -0
- package/dist/lib/commands/SyncCommand.js +406 -0
- package/dist/lib/commands/SyncCommand.js.map +1 -0
- package/dist/lib/commands/mongo/FolderSyncCommandMongo.js +16 -0
- package/dist/lib/commands/mongo/FolderSyncCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js +21 -0
- package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js +18 -0
- package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js +17 -0
- package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/MoveItemsCommandMongo.js +17 -0
- package/dist/lib/commands/mongo/MoveItemsCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/ResolveRecipientsCommandMongo.js +16 -0
- package/dist/lib/commands/mongo/ResolveRecipientsCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SearchCommandMongo.js +19 -0
- package/dist/lib/commands/mongo/SearchCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SendMailCommandMongo.js +17 -0
- package/dist/lib/commands/mongo/SendMailCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SettingsCommandMongo.js +16 -0
- package/dist/lib/commands/mongo/SettingsCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SmartForwardCommandMongo.js +17 -0
- package/dist/lib/commands/mongo/SmartForwardCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SmartReplyCommandMongo.js +17 -0
- package/dist/lib/commands/mongo/SmartReplyCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SyncCommandMongo.js +26 -0
- package/dist/lib/commands/mongo/SyncCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/index.js +14 -0
- package/dist/lib/commands/mongo/index.js.map +1 -0
- package/dist/lib/commands/sql/FolderSyncCommandSQL.js +16 -0
- package/dist/lib/commands/sql/FolderSyncCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js +21 -0
- package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/ItemOperationsCommandSQL.js +18 -0
- package/dist/lib/commands/sql/ItemOperationsCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/MeetingResponseCommandSQL.js +17 -0
- package/dist/lib/commands/sql/MeetingResponseCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/MoveItemsCommandSQL.js +17 -0
- package/dist/lib/commands/sql/MoveItemsCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/ResolveRecipientsCommandSQL.js +16 -0
- package/dist/lib/commands/sql/ResolveRecipientsCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SearchCommandSQL.js +19 -0
- package/dist/lib/commands/sql/SearchCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SendMailCommandSQL.js +17 -0
- package/dist/lib/commands/sql/SendMailCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SettingsCommandSQL.js +16 -0
- package/dist/lib/commands/sql/SettingsCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SmartForwardCommandSQL.js +17 -0
- package/dist/lib/commands/sql/SmartForwardCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SmartReplyCommandSQL.js +17 -0
- package/dist/lib/commands/sql/SmartReplyCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SyncCommandSQL.js +26 -0
- package/dist/lib/commands/sql/SyncCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/index.js +14 -0
- package/dist/lib/commands/sql/index.js.map +1 -0
- package/dist/lib/index.js +58 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/jobs/EasDeviceStateCleanupJob.js +101 -0
- package/dist/lib/jobs/EasDeviceStateCleanupJob.js.map +1 -0
- package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js +13 -0
- package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js.map +1 -0
- package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js +13 -0
- package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js.map +1 -0
- package/dist/lib/models/DeviceSyncState.js +2 -0
- package/dist/lib/models/DeviceSyncState.js.map +1 -0
- package/dist/lib/models/mongo/DeviceSyncStateMongo.js +130 -0
- package/dist/lib/models/mongo/DeviceSyncStateMongo.js.map +1 -0
- package/dist/lib/models/sql/DeviceSyncStateSQL.js +130 -0
- package/dist/lib/models/sql/DeviceSyncStateSQL.js.map +1 -0
- package/dist/lib/mongo/DeviceSyncStateRouteMongo.js +28 -0
- package/dist/lib/mongo/DeviceSyncStateRouteMongo.js.map +1 -0
- package/dist/lib/mongo/EasRouteMongo.js +63 -0
- package/dist/lib/mongo/EasRouteMongo.js.map +1 -0
- package/dist/lib/mongo/index.js +9 -0
- package/dist/lib/mongo/index.js.map +1 -0
- package/dist/lib/mongo.js +15 -0
- package/dist/lib/mongo.js.map +1 -0
- package/dist/lib/sql/DeviceSyncStateRouteSQL.js +28 -0
- package/dist/lib/sql/DeviceSyncStateRouteSQL.js.map +1 -0
- package/dist/lib/sql/EasRouteSQL.js +63 -0
- package/dist/lib/sql/EasRouteSQL.js.map +1 -0
- package/dist/lib/sql/index.js +9 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql.js +15 -0
- package/dist/lib/sql.js.map +1 -0
- package/dist/types/BaseDeviceSyncStateRoute.d.ts +34 -0
- package/dist/types/BaseEasRoute.d.ts +65 -0
- package/dist/types/CompactDateTime.d.ts +22 -0
- package/dist/types/EasCommandHandler.d.ts +59 -0
- package/dist/types/EasSyncKeyUtils.d.ts +89 -0
- package/dist/types/adapters/CalendarSyncAdapter.d.ts +52 -0
- package/dist/types/adapters/ContactsSyncAdapter.d.ts +33 -0
- package/dist/types/adapters/EasCollectionSyncAdapter.d.ts +55 -0
- package/dist/types/adapters/EmailSyncAdapter.d.ts +71 -0
- package/dist/types/adapters/TasksSyncAdapter.d.ts +32 -0
- package/dist/types/adapters/mongo/EmailSyncAdapterMongo.d.ts +7 -0
- package/dist/types/adapters/mongo/index.d.ts +1 -0
- package/dist/types/adapters/sql/EmailSyncAdapterSQL.d.ts +7 -0
- package/dist/types/adapters/sql/index.d.ts +1 -0
- package/dist/types/codec/WbxmlCodePages.d.ts +45 -0
- package/dist/types/codec/WbxmlDecoder.d.ts +33 -0
- package/dist/types/codec/WbxmlElement.d.ts +43 -0
- package/dist/types/codec/WbxmlEncoder.d.ts +20 -0
- package/dist/types/commands/ComposeMailCommand.d.ts +50 -0
- package/dist/types/commands/FolderSyncCommand.d.ts +25 -0
- package/dist/types/commands/GetItemEstimateCommand.d.ts +43 -0
- package/dist/types/commands/ItemOperationsCommand.d.ts +72 -0
- package/dist/types/commands/MeetingResponseCommand.d.ts +32 -0
- package/dist/types/commands/MoveItemsCommand.d.ts +29 -0
- package/dist/types/commands/PingCommand.d.ts +33 -0
- package/dist/types/commands/ProvisionCommand.d.ts +54 -0
- package/dist/types/commands/ResolveRecipientsCommand.d.ts +36 -0
- package/dist/types/commands/SearchCommand.d.ts +60 -0
- package/dist/types/commands/SendMailCommand.d.ts +10 -0
- package/dist/types/commands/SettingsCommand.d.ts +37 -0
- package/dist/types/commands/SmartForwardCommand.d.ts +17 -0
- package/dist/types/commands/SmartReplyCommand.d.ts +17 -0
- package/dist/types/commands/SyncCommand.d.ts +100 -0
- package/dist/types/commands/mongo/FolderSyncCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/GetItemEstimateCommandMongo.d.ts +7 -0
- package/dist/types/commands/mongo/ItemOperationsCommandMongo.d.ts +9 -0
- package/dist/types/commands/mongo/MeetingResponseCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/MoveItemsCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/ResolveRecipientsCommandMongo.d.ts +7 -0
- package/dist/types/commands/mongo/SearchCommandMongo.d.ts +9 -0
- package/dist/types/commands/mongo/SendMailCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/SettingsCommandMongo.d.ts +7 -0
- package/dist/types/commands/mongo/SmartForwardCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/SmartReplyCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/SyncCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/index.d.ts +9 -0
- package/dist/types/commands/sql/FolderSyncCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/GetItemEstimateCommandSQL.d.ts +7 -0
- package/dist/types/commands/sql/ItemOperationsCommandSQL.d.ts +9 -0
- package/dist/types/commands/sql/MeetingResponseCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/MoveItemsCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/ResolveRecipientsCommandSQL.d.ts +7 -0
- package/dist/types/commands/sql/SearchCommandSQL.d.ts +9 -0
- package/dist/types/commands/sql/SendMailCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/SettingsCommandSQL.d.ts +7 -0
- package/dist/types/commands/sql/SmartForwardCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/SmartReplyCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/SyncCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/index.d.ts +9 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/jobs/EasDeviceStateCleanupJob.d.ts +26 -0
- package/dist/types/jobs/mongo/EasDeviceStateCleanupJobMongo.d.ts +5 -0
- package/dist/types/jobs/sql/EasDeviceStateCleanupJobSQL.d.ts +5 -0
- package/dist/types/models/DeviceSyncState.d.ts +30 -0
- package/dist/types/models/mongo/DeviceSyncStateMongo.d.ts +22 -0
- package/dist/types/models/sql/DeviceSyncStateSQL.d.ts +22 -0
- package/dist/types/mongo/DeviceSyncStateRouteMongo.d.ts +8 -0
- package/dist/types/mongo/EasRouteMongo.d.ts +14 -0
- package/dist/types/mongo/index.d.ts +4 -0
- package/dist/types/mongo.d.ts +10 -0
- package/dist/types/sql/DeviceSyncStateRouteSQL.d.ts +8 -0
- package/dist/types/sql/EasRouteSQL.d.ts +14 -0
- package/dist/types/sql/index.d.ts +4 -0
- package/dist/types/sql.d.ts +10 -0
- package/package.json +238 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
12
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
13
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
import { ApiError, ObjectDecorators, StringUtils } from "@rapidrest/core";
|
|
15
|
+
import { ACLAction, ACLUtils, ApiErrorMessages, ApiErrors, RepoUtils } from "@rapidrest/service-core";
|
|
16
|
+
import { WbxmlCodePage } from "../codec/WbxmlCodePages.js";
|
|
17
|
+
import { childText, element, findChild, textElement } from "../codec/WbxmlElement.js";
|
|
18
|
+
const { Config, Init, Inject } = ObjectDecorators;
|
|
19
|
+
/** Parses a `Range` value (`"m-n"`, a zero-based inclusive index pair) into `{ start, end }`, falling back to
|
|
20
|
+
* `defaultEnd` for a missing/malformed value - never trusting the client to request more than `maxEnd` rows. */
|
|
21
|
+
function parseRange(raw, defaultEnd, maxEnd) {
|
|
22
|
+
const match = raw?.match(/^(\d+)-(\d+)$/);
|
|
23
|
+
if (!match) {
|
|
24
|
+
return { start: 0, end: Math.min(defaultEnd, maxEnd) };
|
|
25
|
+
}
|
|
26
|
+
const start = Number(match[1]);
|
|
27
|
+
const end = Math.min(Number(match[2]), maxEnd);
|
|
28
|
+
return start <= end ? { start, end } : { start: 0, end: Math.min(defaultEnd, maxEnd) };
|
|
29
|
+
}
|
|
30
|
+
/** Clamps a matched-results array against a requested `[start, end]` Range, reporting both the sliced page and
|
|
31
|
+
* the actual Range/Total to echo back - shared by the `GAL` and `Mailbox` branches below, which otherwise
|
|
32
|
+
* differ only in how they produce `matches` and render one entry. Both ends are forced to `0` when there are no
|
|
33
|
+
* matches at all - `start` alone (from a client-requested Range like `"5-10"`) would otherwise survive
|
|
34
|
+
* unclamped, producing a malformed `"5-0"` (start > end) once `end` collapses to `0`. */
|
|
35
|
+
function paginate(matches, start, end) {
|
|
36
|
+
return {
|
|
37
|
+
page: matches.slice(start, end + 1),
|
|
38
|
+
rangeStart: matches.length === 0 ? 0 : start,
|
|
39
|
+
rangeEnd: matches.length === 0 ? 0 : Math.min(end, matches.length - 1),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Handles EAS `Search` for the `GAL` and `Mailbox` stores - `DocumentLibrary` (the real spec's third store type)
|
|
44
|
+
* remains out of scope, matching `ItemOperationsCommand`'s identical scope decision; this library has no
|
|
45
|
+
* document-library model.
|
|
46
|
+
*
|
|
47
|
+
* **`GAL`**: this library's `Contact` records are also the source of truth for GAL lookups against a mailbox's
|
|
48
|
+
* own address book (see the architecture note on `Contact` itself). A simple case-insensitive substring match
|
|
49
|
+
* via `RepoUtils.find()` directly, not the heavier `SearchProvider` full-text index - GAL lookups are
|
|
50
|
+
* small-scale exact/prefix matching against a personal address book, not relevance-ranked full text over large
|
|
51
|
+
* content. Only `displayName`/`givenName`/`surname`/`company` are matched - `Contact.emails`/`phones` are
|
|
52
|
+
* embedded arrays of objects, which a plain per-field regex query can't reach into on either backend (confirmed:
|
|
53
|
+
* MongoDB's `$regex` against an array-of-objects field matches nothing useful, and this library's own
|
|
54
|
+
* query-injection guard rejects dot-notation field paths like `"emails.address"` outright) - a documented gap,
|
|
55
|
+
* not an oversight.
|
|
56
|
+
*
|
|
57
|
+
* **`Mailbox`**: real full-text search over the caller's own `Email` messages, backed by `restapi`'s
|
|
58
|
+
* `SearchProvider` (its own full-text index, kept eventually-consistent with the primary datastore via
|
|
59
|
+
* `SearchIndexJob` - a just-sent/just-received message may briefly not be findable yet). **Pragmatic subset**:
|
|
60
|
+
* only `Class` `Email` is supported (a `Query` naming any other class is rejected, matching the `GAL`-only
|
|
61
|
+
* precedent this file already established for search generally); only the common real-world `Query` shape -
|
|
62
|
+
* `Class`/`CollectionId`/`FreeText`, optionally grouped under one `And` - is parsed, not the full recursive
|
|
63
|
+
* `And`/`Or`/`EqualTo`/`GreaterThan`/`LessThan` boolean-tree grammar MS-ASCMD's schema allows for, so a
|
|
64
|
+
* multi-level nested query silently only sees the first `And` group's own direct children. Each match is
|
|
65
|
+
* re-verified for `READ` on its own current `folderUid` before being included - `SearchProvider`'s index is
|
|
66
|
+
* scoped by `mailboxUid` alone, not per-folder ACL, so this is the one place that check still has to happen
|
|
67
|
+
* per-result rather than once up front. `SearchResultPage` carries no total count (the underlying providers
|
|
68
|
+
* don't compute one cheaply over a relevance-ranked query), so `Total` here means "how many matches this
|
|
69
|
+
* request's own capped fetch actually returned" - a client requesting a `Range` past that cap sees fewer
|
|
70
|
+
* results than may really exist, a documented approximation rather than exact server-side paging.
|
|
71
|
+
*
|
|
72
|
+
* `contactClass`/`messageClass`/`emailAdapterClass` are supplied by the Mongo/SQL concrete subclasses.
|
|
73
|
+
*
|
|
74
|
+
* @author Jean-Philippe Steinmetz
|
|
75
|
+
*/
|
|
76
|
+
export class SearchCommand {
|
|
77
|
+
constructor() {
|
|
78
|
+
this.command = "Search";
|
|
79
|
+
this.defaultRangeEnd = 9;
|
|
80
|
+
this.maxRangeEnd = 99;
|
|
81
|
+
}
|
|
82
|
+
async init() {
|
|
83
|
+
this.contactRepo = await this._objectFactory.newInstance(RepoUtils, {
|
|
84
|
+
name: this.contactClass.name,
|
|
85
|
+
args: [this.contactClass],
|
|
86
|
+
});
|
|
87
|
+
this.messageRepo = await this._objectFactory.newInstance(RepoUtils, {
|
|
88
|
+
name: this.messageClass.name,
|
|
89
|
+
args: [this.messageClass],
|
|
90
|
+
});
|
|
91
|
+
this.emailAdapter = await this._objectFactory.newInstance(this.emailAdapterClass);
|
|
92
|
+
}
|
|
93
|
+
async handle(ctx) {
|
|
94
|
+
if (!this.contactRepo || !this.messageRepo || !this.searchProvider || !this.emailAdapter) {
|
|
95
|
+
throw new ApiError(ApiErrors.INTERNAL_ERROR, 500, ApiErrorMessages.INTERNAL_ERROR);
|
|
96
|
+
}
|
|
97
|
+
const storeEl = ctx.request ? findChild(ctx.request, "Store") : undefined;
|
|
98
|
+
const name = storeEl ? childText(storeEl, "Name") : undefined;
|
|
99
|
+
if (!storeEl || (name !== "GAL" && name !== "Mailbox")) {
|
|
100
|
+
throw new ApiError(ApiErrors.INVALID_REQUEST, 400, "Search requires a Store with Name 'GAL' or 'Mailbox'.");
|
|
101
|
+
}
|
|
102
|
+
const optionsEl = findChild(storeEl, "Options");
|
|
103
|
+
const { start, end } = parseRange(optionsEl ? childText(optionsEl, "Range") : undefined, this.defaultRangeEnd, this.maxRangeEnd);
|
|
104
|
+
const storeResponse = name === "GAL" ? await this.handleGal(ctx, storeEl, start, end) : await this.handleMailbox(ctx, storeEl, start, end);
|
|
105
|
+
return element(WbxmlCodePage.Search, "Search", [
|
|
106
|
+
textElement(WbxmlCodePage.Search, "Status", "1"),
|
|
107
|
+
element(WbxmlCodePage.Search, "Response", [storeResponse]),
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
async handleGal(ctx, storeEl, start, end) {
|
|
111
|
+
const query = childText(storeEl, "Query");
|
|
112
|
+
if (!query) {
|
|
113
|
+
throw new ApiError(ApiErrors.INVALID_REQUEST, 400, "Search requires a Store with Name 'GAL' and a Query.");
|
|
114
|
+
}
|
|
115
|
+
// `$or` is a Mongo-only feature of this framework's query builder - `buildSearchQuerySQL` (confirmed by
|
|
116
|
+
// reading its source) has no handling for it at all, so passing one on the SQL backend silently builds
|
|
117
|
+
// a broken TypeORM `where` clause (a literal `$or` property, not a real OR) and 500s. Querying each
|
|
118
|
+
// field separately and merging in memory - the same workaround `EasSyncKeyUtils.computeChanges()`
|
|
119
|
+
// already uses for its own two-backend query gap - works identically on both backends instead.
|
|
120
|
+
//
|
|
121
|
+
// Uses `regex()`, not `like()`: `like()` (`@rapidrest/service-core` ^2.0) compiles a **glob** pattern
|
|
122
|
+
// (`*`/`?` as wildcards), anchored on both backends, so a substring match needs wrapping the term in
|
|
123
|
+
// `*...*` - and even then a literal `*`/`?` the user typed still acts as a wildcard, since glob syntax
|
|
124
|
+
// has no escape mechanism for either character. `regex()` takes a real, unanchored regular expression
|
|
125
|
+
// compiled case-insensitively on both backends (`$regex`/driver-native `REGEXP`), so escaping the term
|
|
126
|
+
// with `StringUtils.escapeRegExp` gives a genuine literal-substring match with no residual wildcard
|
|
127
|
+
// ambiguity - no `*...*` wrapping needed, `regex()` already matches anywhere in the field by default.
|
|
128
|
+
const pattern = StringUtils.escapeRegExp(query);
|
|
129
|
+
const findOptions = { ignoreACL: true, limit: this.maxRangeEnd + 1 };
|
|
130
|
+
const perField = await Promise.all(["displayName", "givenName", "surname", "company"].map((field) => this.contactRepo.find({ mailboxUid: ctx.mailboxUid, [field]: `regex(${pattern})`, limit: this.maxRangeEnd + 1 }, findOptions)));
|
|
131
|
+
const byUid = new Map();
|
|
132
|
+
for (const contact of perField.flat()) {
|
|
133
|
+
byUid.set((contact).uid, contact);
|
|
134
|
+
}
|
|
135
|
+
const matches = Array.from(byUid.values()).sort((a, b) => a.displayName.localeCompare(b.displayName));
|
|
136
|
+
const { page, rangeStart, rangeEnd } = paginate(matches, start, end);
|
|
137
|
+
return element(WbxmlCodePage.Search, "Store", [
|
|
138
|
+
textElement(WbxmlCodePage.Search, "Status", "1"),
|
|
139
|
+
...page.map((contact) => this.contactToResult(contact)),
|
|
140
|
+
textElement(WbxmlCodePage.Search, "Range", `${rangeStart}-${rangeEnd}`),
|
|
141
|
+
textElement(WbxmlCodePage.Search, "Total", String(matches.length)),
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
async handleMailbox(ctx, storeEl, start, end) {
|
|
145
|
+
const queryEl = findChild(storeEl, "Query");
|
|
146
|
+
if (!queryEl) {
|
|
147
|
+
throw new ApiError(ApiErrors.INVALID_REQUEST, 400, "Search requires a Store with Name 'Mailbox' and a Query.");
|
|
148
|
+
}
|
|
149
|
+
// The common real-world shape groups Class/CollectionId/FreeText under one And - see this class's own
|
|
150
|
+
// doc comment for why a deeper And/Or tree isn't parsed. Falling back to Query's own direct children
|
|
151
|
+
// also accepts a client that omits the And wrapper entirely, which the schema itself permits.
|
|
152
|
+
const container = findChild(queryEl, "And") ?? queryEl;
|
|
153
|
+
const className = childText(container, "Class");
|
|
154
|
+
const folderUid = childText(container, "CollectionId");
|
|
155
|
+
const freeText = childText(container, "FreeText");
|
|
156
|
+
if (className !== "Email" || !freeText) {
|
|
157
|
+
throw new ApiError(ApiErrors.INVALID_REQUEST, 400, "Search on the 'Mailbox' store requires a Query with Class 'Email' and a FreeText term.");
|
|
158
|
+
}
|
|
159
|
+
const resultPage = await this.searchProvider.search({
|
|
160
|
+
mailboxUid: ctx.mailboxUid,
|
|
161
|
+
text: freeText,
|
|
162
|
+
entityTypes: ["message"],
|
|
163
|
+
folderUid,
|
|
164
|
+
limit: this.maxRangeEnd + 1,
|
|
165
|
+
});
|
|
166
|
+
const matches = [];
|
|
167
|
+
for (const result of resultPage.results) {
|
|
168
|
+
const message = await this.messageRepo.findOne(result.entityUid, { ignoreACL: true });
|
|
169
|
+
if (!message) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (!(await this.aclUtils.hasPermission(ctx.user, message.folderUid, ACLAction.READ))) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
matches.push(message);
|
|
176
|
+
}
|
|
177
|
+
const { page, rangeStart, rangeEnd } = paginate(matches, start, end);
|
|
178
|
+
const results = await Promise.all(page.map((message) => this.messageToResult(message)));
|
|
179
|
+
return element(WbxmlCodePage.Search, "Store", [
|
|
180
|
+
textElement(WbxmlCodePage.Search, "Status", "1"),
|
|
181
|
+
...results,
|
|
182
|
+
textElement(WbxmlCodePage.Search, "Range", `${rangeStart}-${rangeEnd}`),
|
|
183
|
+
textElement(WbxmlCodePage.Search, "Total", String(matches.length)),
|
|
184
|
+
]);
|
|
185
|
+
}
|
|
186
|
+
contactToResult(contact) {
|
|
187
|
+
const properties = [
|
|
188
|
+
textElement(WbxmlCodePage.Gal, "DisplayName", contact.displayName),
|
|
189
|
+
...(contact.givenName ? [textElement(WbxmlCodePage.Gal, "FirstName", contact.givenName)] : []),
|
|
190
|
+
...(contact.surname ? [textElement(WbxmlCodePage.Gal, "LastName", contact.surname)] : []),
|
|
191
|
+
...(contact.company ? [textElement(WbxmlCodePage.Gal, "Company", contact.company)] : []),
|
|
192
|
+
...(contact.jobTitle ? [textElement(WbxmlCodePage.Gal, "Title", contact.jobTitle)] : []),
|
|
193
|
+
...(contact.emails[0] ? [textElement(WbxmlCodePage.Gal, "EmailAddress", contact.emails[0].address)] : []),
|
|
194
|
+
...(contact.phones[0] ? [textElement(WbxmlCodePage.Gal, "Phone", contact.phones[0].phoneNumber)] : []),
|
|
195
|
+
];
|
|
196
|
+
return element(WbxmlCodePage.Search, "Result", [element(WbxmlCodePage.Search, "Properties", properties)]);
|
|
197
|
+
}
|
|
198
|
+
/** Reuses `EmailSyncAdapter.toApplicationData()`'s own field mapping (Subject/From/To/Cc/Bcc/DateReceived/
|
|
199
|
+
* Importance/Read/Flag/Body/ConversationId) for a Mailbox-store search hit's `Properties` - the same
|
|
200
|
+
* per-field shape `Sync` already renders for this message, rather than a second, parallel mapping that
|
|
201
|
+
* could drift out of sync with it. */
|
|
202
|
+
async messageToResult(message) {
|
|
203
|
+
const applicationData = await this.emailAdapter.toApplicationData(message);
|
|
204
|
+
return element(WbxmlCodePage.Search, "Result", [
|
|
205
|
+
textElement(WbxmlCodePage.AirSync, "Class", "Email"),
|
|
206
|
+
textElement(WbxmlCodePage.AirSync, "CollectionId", message.folderUid),
|
|
207
|
+
textElement(WbxmlCodePage.AirSync, "ServerId", message.uid),
|
|
208
|
+
element(WbxmlCodePage.Search, "Properties", applicationData.children),
|
|
209
|
+
]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
__decorate([
|
|
213
|
+
Inject("SearchProvider"),
|
|
214
|
+
__metadata("design:type", Object)
|
|
215
|
+
], SearchCommand.prototype, "searchProvider", void 0);
|
|
216
|
+
__decorate([
|
|
217
|
+
Inject(ACLUtils),
|
|
218
|
+
__metadata("design:type", ACLUtils)
|
|
219
|
+
], SearchCommand.prototype, "aclUtils", void 0);
|
|
220
|
+
__decorate([
|
|
221
|
+
Config("mail:eas:search_default_range", 9),
|
|
222
|
+
__metadata("design:type", Number)
|
|
223
|
+
], SearchCommand.prototype, "defaultRangeEnd", void 0);
|
|
224
|
+
__decorate([
|
|
225
|
+
Config("mail:eas:search_max_range", 99),
|
|
226
|
+
__metadata("design:type", Number)
|
|
227
|
+
], SearchCommand.prototype, "maxRangeEnd", void 0);
|
|
228
|
+
__decorate([
|
|
229
|
+
Init,
|
|
230
|
+
__metadata("design:type", Function),
|
|
231
|
+
__metadata("design:paramtypes", []),
|
|
232
|
+
__metadata("design:returntype", Promise)
|
|
233
|
+
], SearchCommand.prototype, "init", null);
|
|
234
|
+
//# sourceMappingURL=SearchCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchCommand.js","sourceRoot":"","sources":["../../../src/commands/SearchCommand.ts"],"names":[],"mappings":";;;;;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAiB,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACrH,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAqB,MAAM,0BAA0B,CAAC;AAKzG,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC;AAElD;gHACgH;AAChH,SAAS,UAAU,CAAC,GAAuB,EAAE,UAAkB,EAAE,MAAc;IAC3E,MAAM,KAAK,GAAG,GAAG,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;IAC3D,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED;;;;yFAIyF;AACzF,SAAS,QAAQ,CAAI,OAAY,EAAE,KAAa,EAAE,GAAW;IACzD,OAAO;QACH,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC;QACnC,UAAU,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;QAC5C,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;KACzE,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAgB,aAAa;IAAnC;QACoB,YAAO,GAAG,QAAQ,CAAC;QAoB3B,oBAAe,GAAW,CAAC,CAAC;QAG5B,gBAAW,GAAW,EAAE,CAAC;IA6JrC,CAAC;IA1JgB,AAAN,KAAK,CAAC,IAAI;QACb,IAAI,CAAC,WAAW,GAAG,MAAM,IAAI,CAAC,cAAe,CAAC,WAAW,CAAC,SAAS,EAAE;YACjE,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;YAC5B,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,GAAG,MAAM,IAAI,CAAC,cAAe,CAAC,WAAW,CAAC,SAAS,EAAE;YACjE,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;YAC5B,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,CAAC,cAAe,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACvF,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAsB;QACtC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvF,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,GAAG,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;QACvF,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,MAAM,IAAI,GAAuB,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,uDAAuD,CAAC,CAAC;QAChH,CAAC;QAED,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAChD,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,UAAU,CAC7B,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EACrD,IAAI,CAAC,eAAe,EACpB,IAAI,CAAC,WAAW,CACnB,CAAC;QAEF,MAAM,aAAa,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAE3I,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE;YAC3C,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC;YAChD,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,aAAa,CAAC,CAAC;SAC7D,CAAC,CAAC;IACP,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,GAAsB,EAAE,OAAqB,EAAE,KAAa,EAAE,GAAW;QAC7F,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,sDAAsD,CAAC,CAAC;QAC/G,CAAC;QAED,wGAAwG;QACxG,uGAAuG;QACvG,oGAAoG;QACpG,kGAAkG;QAClG,+FAA+F;QAC/F,EAAE;QACF,sGAAsG;QACtG,qGAAqG;QACrG,uGAAuG;QACvG,sGAAsG;QACtG,uGAAuG;QACvG,oGAAoG;QACpG,sGAAsG;QACtG,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,WAAW,GAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC1E,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,CAAC,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7D,IAAI,CAAC,WAAY,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,EAAS,EAAE,WAAW,CAAC,CACxI,CACJ,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqC,CAAC;QAC3D,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,OAAO,GAAc,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QACjH,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAErE,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE;YAC1C,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC;YAChD,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACvD,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;YACvE,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;SACrE,CAAC,CAAC;IACP,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,GAAsB,EAAE,OAAqB,EAAE,KAAa,EAAE,GAAW;QACjG,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,0DAA0D,CAAC,CAAC;QACnH,CAAC;QACD,sGAAsG;QACtG,qGAAqG;QACrG,8FAA8F;QAC9F,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC;QACvD,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAClD,IAAI,SAAS,KAAK,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;YACrC,MAAM,IAAI,QAAQ,CACd,SAAS,CAAC,eAAe,EACzB,GAAG,EACH,wFAAwF,CAC3F,CAAC;QACN,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,cAAe,CAAC,MAAM,CAAC;YACjD,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,CAAC,SAAS,CAAC;YACxB,SAAS;YACT,KAAK,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC;SAC9B,CAAC,CAAC;QAEH,MAAM,OAAO,GAAc,EAAE,CAAC;QAC9B,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YACtC,MAAM,OAAO,GAAwB,MAAM,IAAI,CAAC,WAAY,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5G,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,SAAS;YACb,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,QAAS,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACrF,SAAS;YACb,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAExF,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE;YAC1C,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC;YAChD,GAAG,OAAO;YACV,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,IAAI,QAAQ,EAAE,CAAC;YACvE,WAAW,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;SACrE,CAAC,CAAC;IACP,CAAC;IAEO,eAAe,CAAC,OAAgB;QACpC,MAAM,UAAU,GAAmB;YAC/B,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,CAAC,WAAW,CAAC;YAClE,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9F,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzF,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACzG,CAAC;QACF,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC9G,CAAC;IAED;;;0CAGsC;IAC9B,KAAK,CAAC,eAAe,CAAC,OAAgB;QAC1C,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,YAAa,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC5E,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE;YAC3C,WAAW,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;YACpD,WAAW,CAAC,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,SAAS,CAAC;YACrE,WAAW,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAG,OAAe,CAAC,GAAG,CAAC;YACpE,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,eAAe,CAAC,QAAQ,CAAC;SACxE,CAAC,CAAC;IACP,CAAC;CACJ;AAtKW;IADP,MAAM,CAAC,gBAAgB,CAAC;;qDACe;AAGhC;IADP,MAAM,CAAC,QAAQ,CAAC;8BACE,QAAQ;+CAAC;AAGpB;IADP,MAAM,CAAC,+BAA+B,EAAE,CAAC,CAAC;;sDACP;AAG5B;IADP,MAAM,CAAC,2BAA2B,EAAE,EAAE,CAAC;;kDACP;AAGpB;IADZ,IAAI;;;;yCAWJ"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { ComposeMailCommand } from "./ComposeMailCommand.js";
|
|
6
|
+
/**
|
|
7
|
+
* Handles EAS `SendMail`: relays a freshly composed message with no referenced original - see
|
|
8
|
+
* `ComposeMailCommand`'s own doc comment for the full shared implementation.
|
|
9
|
+
*
|
|
10
|
+
* @author Jean-Philippe Steinmetz
|
|
11
|
+
*/
|
|
12
|
+
export class SendMailCommand extends ComposeMailCommand {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.command = "SendMail";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=SendMailCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SendMailCommand.js","sourceRoot":"","sources":["../../../src/commands/SendMailCommand.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,OAAgB,eAAgB,SAAQ,kBAAkB;IAAhE;;QACoB,YAAO,GAAG,UAAU,CAAC;IACzC,CAAC;CAAA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
12
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
13
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
import { ApiError, ObjectDecorators } from "@rapidrest/core";
|
|
15
|
+
import { ApiErrorMessages, ApiErrors, RepoUtils } from "@rapidrest/service-core";
|
|
16
|
+
import { WbxmlCodePage } from "../codec/WbxmlCodePages.js";
|
|
17
|
+
import { childText, element, findChild, textElement } from "../codec/WbxmlElement.js";
|
|
18
|
+
const { Init } = ObjectDecorators;
|
|
19
|
+
/**
|
|
20
|
+
* Handles EAS `Settings`: the first-run/general-purpose device<->server settings exchange. This pragmatic
|
|
21
|
+
* subset supports the sub-elements every real client actually depends on:
|
|
22
|
+
*
|
|
23
|
+
* - `UserInformation`/`Get`: returns the mailbox's `primarySmtpAddress`/`aliasAddresses` as `EmailAddresses`.
|
|
24
|
+
* - `DeviceInformation`/`Set`: acknowledged with `Status 1` but not persisted anywhere - `DeviceSyncState` has
|
|
25
|
+
* no fields for a device's model/IMEI/OS/friendly name, and nothing else in this library currently consumes
|
|
26
|
+
* them. A real client only requires the acknowledgement to proceed past first-run setup, not that the values
|
|
27
|
+
* are retrievable later.
|
|
28
|
+
* - `Oof`/`Get` and `Oof`/`Set`: reads/writes `Mailbox.oofEnabled`/`oofMessage`/`oofStartTime`/`oofEndTime`.
|
|
29
|
+
* `StartTime`/`EndTime` use MS-ASDTYPE's plain `dateTime` type (`Date.prototype.toISOString()`), not Compact
|
|
30
|
+
* DateTime - confirmed against MS-ASSETTINGS directly, unlike `Calendar`/`Tasks`' timestamp fields (see
|
|
31
|
+
* `CompactDateTime.ts`'s own doc comment on that exact distinction). A single combined reply message is stored
|
|
32
|
+
* rather than the spec's three audience-specific `OofMessage` variants (internal/external-known/
|
|
33
|
+
* external-unknown) - matches this codebase's existing "one thing, not three" simplification precedent (e.g.
|
|
34
|
+
* `ContactsSyncAdapter`'s single-slot phone/email handling).
|
|
35
|
+
* - `RightsManagementInformation` is not implemented - deferred, matching this library's "pragmatic subset"
|
|
36
|
+
* precedent elsewhere (e.g. `ComposeMailCommand`'s own documented gaps).
|
|
37
|
+
*
|
|
38
|
+
* `mailboxClass` is supplied by the Mongo/SQL concrete subclasses.
|
|
39
|
+
*
|
|
40
|
+
* @author Jean-Philippe Steinmetz
|
|
41
|
+
*/
|
|
42
|
+
export class SettingsCommand {
|
|
43
|
+
constructor() {
|
|
44
|
+
this.command = "Settings";
|
|
45
|
+
}
|
|
46
|
+
async init() {
|
|
47
|
+
this.mailboxRepo = await this._objectFactory.newInstance(RepoUtils, {
|
|
48
|
+
name: this.mailboxClass.name,
|
|
49
|
+
args: [this.mailboxClass],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async handle(ctx) {
|
|
53
|
+
if (!this.mailboxRepo) {
|
|
54
|
+
throw new ApiError(ApiErrors.INTERNAL_ERROR, 500, ApiErrorMessages.INTERNAL_ERROR);
|
|
55
|
+
}
|
|
56
|
+
const children = [textElement(WbxmlCodePage.Settings, "Status", "1")];
|
|
57
|
+
if (ctx.request && findChild(ctx.request, "DeviceInformation")) {
|
|
58
|
+
children.push(element(WbxmlCodePage.Settings, "DeviceInformation", [textElement(WbxmlCodePage.Settings, "Status", "1")]));
|
|
59
|
+
}
|
|
60
|
+
if (ctx.request && findChild(ctx.request, "UserInformation")) {
|
|
61
|
+
const mailbox = await this.mailboxRepo.findOne(ctx.mailboxUid, { ignoreACL: true });
|
|
62
|
+
if (!mailbox) {
|
|
63
|
+
throw new ApiError(ApiErrors.NOT_FOUND, 404, ApiErrorMessages.NOT_FOUND);
|
|
64
|
+
}
|
|
65
|
+
children.push(element(WbxmlCodePage.Settings, "UserInformation", [
|
|
66
|
+
textElement(WbxmlCodePage.Settings, "Status", "1"),
|
|
67
|
+
element(WbxmlCodePage.Settings, "EmailAddresses", [
|
|
68
|
+
textElement(WbxmlCodePage.Settings, "SmtpAddress", mailbox.primarySmtpAddress),
|
|
69
|
+
...mailbox.aliasAddresses.map((address) => textElement(WbxmlCodePage.Settings, "SmtpAddress", address)),
|
|
70
|
+
]),
|
|
71
|
+
]));
|
|
72
|
+
}
|
|
73
|
+
const oofEl = ctx.request ? findChild(ctx.request, "Oof") : undefined;
|
|
74
|
+
if (oofEl) {
|
|
75
|
+
const mailbox = await this.mailboxRepo.findOne(ctx.mailboxUid, { ignoreACL: true });
|
|
76
|
+
if (!mailbox) {
|
|
77
|
+
throw new ApiError(ApiErrors.NOT_FOUND, 404, ApiErrorMessages.NOT_FOUND);
|
|
78
|
+
}
|
|
79
|
+
const setEl = findChild(oofEl, "Set");
|
|
80
|
+
children.push(setEl ? await this.setOof(ctx, mailbox, setEl) : this.getOof(mailbox));
|
|
81
|
+
}
|
|
82
|
+
return element(WbxmlCodePage.Settings, "Settings", children);
|
|
83
|
+
}
|
|
84
|
+
/** `OofState`: `0`=disabled, `1`=enabled indefinitely, `2`=time-based (only while now is within
|
|
85
|
+
* `StartTime`/`EndTime`). */
|
|
86
|
+
getOof(mailbox) {
|
|
87
|
+
const timed = mailbox.oofEnabled && !!mailbox.oofStartTime && !!mailbox.oofEndTime;
|
|
88
|
+
return element(WbxmlCodePage.Settings, "Oof", [
|
|
89
|
+
textElement(WbxmlCodePage.Settings, "Status", "1"),
|
|
90
|
+
element(WbxmlCodePage.Settings, "Get", [
|
|
91
|
+
textElement(WbxmlCodePage.Settings, "OofState", mailbox.oofEnabled ? (timed ? "2" : "1") : "0"),
|
|
92
|
+
...(timed
|
|
93
|
+
? [
|
|
94
|
+
textElement(WbxmlCodePage.Settings, "StartTime", mailbox.oofStartTime.toISOString()),
|
|
95
|
+
textElement(WbxmlCodePage.Settings, "EndTime", mailbox.oofEndTime.toISOString()),
|
|
96
|
+
]
|
|
97
|
+
: []),
|
|
98
|
+
element(WbxmlCodePage.Settings, "OofMessage", [
|
|
99
|
+
element(WbxmlCodePage.Settings, "AppliesToInternal", []),
|
|
100
|
+
textElement(WbxmlCodePage.Settings, "Enabled", mailbox.oofEnabled ? "1" : "0"),
|
|
101
|
+
textElement(WbxmlCodePage.Settings, "ReplyMessage", mailbox.oofMessage),
|
|
102
|
+
textElement(WbxmlCodePage.Settings, "BodyType", "Text"),
|
|
103
|
+
]),
|
|
104
|
+
]),
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
async setOof(ctx, mailbox, setEl) {
|
|
108
|
+
const oofState = childText(setEl, "OofState") ?? "0";
|
|
109
|
+
const oofMessageEl = findChild(setEl, "OofMessage");
|
|
110
|
+
const replyMessage = oofMessageEl ? (childText(oofMessageEl, "ReplyMessage") ?? "") : "";
|
|
111
|
+
const startTime = childText(setEl, "StartTime");
|
|
112
|
+
const endTime = childText(setEl, "EndTime");
|
|
113
|
+
const timed = oofState === "2" && startTime !== undefined && endTime !== undefined;
|
|
114
|
+
// `null`, not `undefined`, to clear a previously-set window when switching away from time-based Oof:
|
|
115
|
+
// TypeORM's `UpdateQueryBuilder` silently drops any `undefined`-valued key from the generated SQL `SET`
|
|
116
|
+
// clause (confirmed by reading its source), so `undefined` here would leave a stale StartTime/EndTime
|
|
117
|
+
// in place on the SQL backend while correctly clearing it on Mongo - `null` clears it on both.
|
|
118
|
+
await this.mailboxRepo.update({
|
|
119
|
+
uid: mailbox.uid,
|
|
120
|
+
version: mailbox.version,
|
|
121
|
+
oofEnabled: oofState !== "0",
|
|
122
|
+
oofMessage: replyMessage,
|
|
123
|
+
oofStartTime: timed ? new Date(startTime) : null,
|
|
124
|
+
oofEndTime: timed ? new Date(endTime) : null,
|
|
125
|
+
}, mailbox, { ignoreACL: true, user: ctx.user });
|
|
126
|
+
return element(WbxmlCodePage.Settings, "Oof", [
|
|
127
|
+
textElement(WbxmlCodePage.Settings, "Status", "1"),
|
|
128
|
+
element(WbxmlCodePage.Settings, "Set", [textElement(WbxmlCodePage.Settings, "Status", "1")]),
|
|
129
|
+
]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
__decorate([
|
|
133
|
+
Init,
|
|
134
|
+
__metadata("design:type", Function),
|
|
135
|
+
__metadata("design:paramtypes", []),
|
|
136
|
+
__metadata("design:returntype", Promise)
|
|
137
|
+
], SettingsCommand.prototype, "init", null);
|
|
138
|
+
//# sourceMappingURL=SettingsCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SettingsCommand.js","sourceRoot":"","sources":["../../../src/commands/SettingsCommand.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { ComposeMailCommand } from "./ComposeMailCommand.js";
|
|
6
|
+
/**
|
|
7
|
+
* Handles EAS `SmartForward`: relays a freshly composed message threaded to (and referencing) the original via
|
|
8
|
+
* `<Source>`, then flips the original's `Forwarded` flag - see `ComposeMailCommand`'s own doc comment for the
|
|
9
|
+
* full shared implementation and this pragmatic subset's scope.
|
|
10
|
+
*
|
|
11
|
+
* @author Jean-Philippe Steinmetz
|
|
12
|
+
*/
|
|
13
|
+
export class SmartForwardCommand extends ComposeMailCommand {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.command = "SmartForward";
|
|
17
|
+
}
|
|
18
|
+
async markOriginal(ctx, original) {
|
|
19
|
+
await this.messageRepo.update({ uid: original.uid, version: original.version, flags: { ...original.flags, forwarded: true } }, original, { ignoreACL: true, user: ctx.user });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SmartForwardCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartForwardCommand.js","sourceRoot":"","sources":["../../../src/commands/SmartForwardCommand.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D;;;;;;GAMG;AACH,MAAM,OAAgB,mBAAoB,SAAQ,kBAAkB;IAApE;;QACoB,YAAO,GAAG,cAAc,CAAC;IAS7C,CAAC;IAPsB,KAAK,CAAC,YAAY,CAAC,GAAsB,EAAE,QAAoD;QAC9G,MAAM,IAAI,CAAC,WAAY,CAAC,MAAM,CAC1B,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,EAAS,EACtG,QAAQ,EACR,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CACtC,CAAC;IACN,CAAC;CACJ"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { ComposeMailCommand } from "./ComposeMailCommand.js";
|
|
6
|
+
/**
|
|
7
|
+
* Handles EAS `SmartReply`: relays a freshly composed message threaded to (and referencing) the original via
|
|
8
|
+
* `<Source>`, then flips the original's `Answered` flag - see `ComposeMailCommand`'s own doc comment for the
|
|
9
|
+
* full shared implementation and this pragmatic subset's scope.
|
|
10
|
+
*
|
|
11
|
+
* @author Jean-Philippe Steinmetz
|
|
12
|
+
*/
|
|
13
|
+
export class SmartReplyCommand extends ComposeMailCommand {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.command = "SmartReply";
|
|
17
|
+
}
|
|
18
|
+
async markOriginal(ctx, original) {
|
|
19
|
+
await this.messageRepo.update({ uid: original.uid, version: original.version, flags: { ...original.flags, answered: true } }, original, { ignoreACL: true, user: ctx.user });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=SmartReplyCommand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartReplyCommand.js","sourceRoot":"","sources":["../../../src/commands/SmartReplyCommand.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAI7D;;;;;;GAMG;AACH,MAAM,OAAgB,iBAAkB,SAAQ,kBAAkB;IAAlE;;QACoB,YAAO,GAAG,YAAY,CAAC;IAS3C,CAAC;IAPsB,KAAK,CAAC,YAAY,CAAC,GAAsB,EAAE,QAAoD;QAC9G,MAAM,IAAI,CAAC,WAAY,CAAC,MAAM,CAC1B,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAS,EACrG,QAAQ,EACR,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CACtC,CAAC;IACN,CAAC;CACJ"}
|