Skip to content

Commit 396b645

Browse files
committed
Feat: Complete adding only option
1 parent d65a842 commit 396b645

File tree

9 files changed

+87
-20
lines changed

9 files changed

+87
-20
lines changed

email/mailmerge-cli/src/commands/send.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ export default class Send extends Command {
2323
sleepBetween: Flags.integer({
2424
char: "s",
2525
description: "Time to sleep between sending emails to prevent hitting rate limits",
26-
default: 0,
2726
}),
2827
yes: Flags.boolean({
2928
char: "y",
3029
description: "Skip confirmation prompt",
3130
default: false,
3231
}),
32+
only: Flags.integer({
33+
char: "n",
34+
description: "Only send this many emails (i.e. the first X emails)",
35+
}),
3336
};
3437

3538
public async run(): Promise<void> {
@@ -48,7 +51,10 @@ export default class Send extends Command {
4851
getDefaultDoCSocFromLine(),
4952
ENGINES_MAP,
5053
flags.yes,
51-
flags.sleepBetween,
54+
{
55+
sleepBetween: flags.sleepBetween,
56+
onlySend: flags.only,
57+
},
5258
);
5359
}
5460
}

email/mailmerge-cli/src/commands/upload-drafts.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ export default class UploadDrafts extends Command {
3030
description: "Skip confirmation prompt",
3131
default: false,
3232
}),
33+
only: Flags.integer({
34+
char: "n",
35+
description: "Only send this many emails (i.e. the first X emails)",
36+
}),
3337
};
3438

3539
public async run(): Promise<void> {
@@ -42,6 +46,9 @@ export default class UploadDrafts extends Command {
4246
namer: (record) => record[DEFAULT_FIELD_NAMES.to],
4347
});
4448

45-
await uploadDrafts(storageBackend, ENGINES_MAP, flags.yes, flags.sleepBetween);
49+
await uploadDrafts(storageBackend, ENGINES_MAP, flags.yes, {
50+
sleepBetween: flags.sleepBetween,
51+
onlySend: flags.only,
52+
});
4653
}
4754
}

email/mailmerge/src/pipelines/send.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ describe("sendEmails", () => {
8181
[],
8282
{ cc: [], bcc: [] },
8383
);
84-
expect(mockStorageBackend.postSendAction).toHaveBeenCalledWith(mergeResults[0]);
84+
expect(mockStorageBackend.postSendAction).toHaveBeenCalledWith(mergeResults[0], "sent");
8585
});
8686

8787
it("should send only the number emails we want if only specified", async () => {

email/mailmerge/src/pipelines/send.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ENGINES_MAP } from "../engines/index.js";
88
import { TemplateEngineConstructor } from "../engines/types.js";
99
import Mailer from "../mailer/mailer.js";
1010
import { EmailString, FromEmail } from "../util/types.js";
11-
import { StorageBackend, MergeResultWithMetadata } from "./storage/types";
11+
import { StorageBackend, MergeResultWithMetadata, PostSendActionMode } from "./storage/types.js";
1212

1313
interface SendEmailsOptions {
1414
/** Time to sleep between sending emails to prevent hitting rate limits */
@@ -143,7 +143,7 @@ You are about to send ${pendingEmails.length} emails. The esitmated time for thi
143143

144144
if (storageBackend.postSendAction) {
145145
logger.debug("Calling post-send hook...");
146-
await storageBackend.postSendAction(originalResult);
146+
await storageBackend.postSendAction(originalResult, PostSendActionMode.SMTP_SEND);
147147
}
148148

149149
logger.info("Email sent!");

email/mailmerge/src/pipelines/storage/sidecar.spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,31 @@ describe("JSONSidecarsBackend", () => {
138138
namer: jest.fn(),
139139
});
140140
/// @ts-expect-error: Mocking things
141-
await backend.postSendAction(resultSent);
141+
await backend.postSendAction(resultSent, "sent");
142142

143143
expect(mkdirp).toHaveBeenCalledWith("output/root/sent");
144144
expect(move).toHaveBeenCalledWith("output/root/file1", "output/root/sent");
145145
});
146+
147+
it("should move sent emails to drafts folder when in drafts mode", async () => {
148+
const sidecar = {
149+
name: "test",
150+
files: [{ filename: "file1" }],
151+
};
152+
const resultSent = {
153+
storageBackendMetadata: { sideCar: sidecar },
154+
};
155+
156+
const backend = new JSONSidecarsBackend("output/root", {
157+
type: "fixed",
158+
namer: jest.fn(),
159+
});
160+
/// @ts-expect-error: Mocking things
161+
await backend.postSendAction(resultSent, "drafts");
162+
163+
expect(mkdirp).toHaveBeenCalledWith("output/root/drafts");
164+
expect(move).toHaveBeenCalledWith("output/root/file1", "output/root/drafts");
165+
});
146166
});
147167

148168
describe("storeOriginalMergeResults", () => {

email/mailmerge/src/pipelines/storage/sidecar.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import {
1414
getSidecarMetadata,
1515
} from "../../previews/index.js";
1616
import { MappedRecord } from "../../util/index.js";
17-
import { StorageBackend, MergeResultWithMetadata, MergeResult } from "./types";
17+
import {
18+
StorageBackend,
19+
MergeResultWithMetadata,
20+
MergeResult,
21+
PostSendActionMode,
22+
} from "./types.js";
1823

1924
/** Metadata the JSON backend passes on {@link MergeResultWithMetadata.storageBackendMetadata} - bsically the original sidecar file with the path it came from */
2025
export interface JSONSidecarsBackendMetadata {
@@ -141,9 +146,21 @@ export class JSONSidecarsBackend implements StorageBackend<JSONSidecarsBackendMe
141146
*/
142147
public async postSendAction(
143148
resultSent: MergeResultWithMetadata<JSONSidecarsBackendMetadata>,
149+
mode: PostSendActionMode,
144150
): Promise<void> {
145151
const sidecar = resultSent.storageBackendMetadata.sideCar;
146-
const sentRoot = join(this.outputRoot, "sent");
152+
let directoryName;
153+
switch (mode) {
154+
case PostSendActionMode.DRAFTS_UPLOAD:
155+
directoryName = "drafts";
156+
break;
157+
case PostSendActionMode.SMTP_SEND:
158+
directoryName = "sent";
159+
break;
160+
default:
161+
throw new Error(`Invalid post-send action mode: ${mode}`);
162+
}
163+
const sentRoot = join(this.outputRoot, directoryName);
147164
this.logger.info(`Moving sent emails for ${sidecar.name} to ${sentRoot}...`);
148165
await mkdirp(sentRoot);
149166
await Promise.all(

email/mailmerge/src/pipelines/storage/types.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ export type MergeResultWithMetadata<Metadata = unknown> = MergeResult & {
4242
storageBackendMetadata: Metadata;
4343
};
4444

45+
/**
46+
* Modes for a post-send action
47+
*/
48+
export enum PostSendActionMode {
49+
/** The email was sent */
50+
SMTP_SEND = "sent",
51+
/** The email was uploaded to drafts intead */
52+
DRAFTS_UPLOAD = "drafts",
53+
}
54+
4555
/**
4656
* Interface for a storage backend, which is responsible for loading and storing merge results.
4757
*
@@ -69,9 +79,14 @@ export interface StorageBackend<Metadata = unknown> {
6979
*/
7080
storeUpdatedMergeResults(results: MergeResultWithMetadata<Metadata>[]): PromiseLike<void>;
7181
/**
72-
* Called after a merge result has been sent, so that you can do any post processing.
82+
* Called after a merge result has been sent or uploaded to drafts, so that you can do any post processing.
83+
*
84+
* Note that you must handle both cases of sending and uploading to drafts, as the mode is passed to you.
7385
*
7486
* E.g. Move file around, mark as sent in database
7587
*/
76-
postSendAction?(resultSent: MergeResultWithMetadata<Metadata>): PromiseLike<void>;
88+
postSendAction?(
89+
resultSent: MergeResultWithMetadata<Metadata>,
90+
mode: PostSendActionMode,
91+
): PromiseLike<void>;
7792
}

email/mailmerge/src/pipelines/uploadDrafts.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import readlineSync from "readline-sync";
77
import { TemplateEngineConstructor, ENGINES_MAP } from "../engines/index.js";
88
import { EmailUploader } from "../graph/index.js";
99
import { EmailString } from "../util/index.js";
10-
import { StorageBackend, MergeResultWithMetadata } from "./storage";
10+
import { StorageBackend, MergeResultWithMetadata, PostSendActionMode } from "./storage/index.js";
1111

1212
interface UploadDraftsOptions {
1313
/** Time to sleep between sending emails to prevent hitting rate limits */
@@ -101,10 +101,6 @@ export async function uploadDrafts(
101101
You are about to upload ${pendingEmails.length} emails.
102102
This action is IRREVERSIBLE.
103103
104-
If the system crashes, you will need to manually upload the emails.
105-
Re-running this after a partial upload will end up uploading duplicate emails.
106-
Unlike with send, emails will not be moved to a different folder after upload.
107-
108104
Check that:
109105
1. The template was correct
110106
1. You are satisfied with ALL previews, including the HTML previews
@@ -134,7 +130,7 @@ export async function uploadDrafts(
134130
let sent = 0;
135131
const uploader = new EmailUploader(logger);
136132
await uploader.authenticate(expectedEmail, entraTenantId, entraClientId);
137-
for (const { to, subject, html, attachments, cc, bcc } of pendingEmails) {
133+
for (const { to, subject, html, attachments, cc, bcc, originalResult } of pendingEmails) {
138134
logger.info(
139135
`(${++sent} / ${total}) Uploading email to ${to} with subject ${subject} to Drafts...`,
140136
);
@@ -155,6 +151,12 @@ export async function uploadDrafts(
155151
options,
156152
);
157153

154+
// Execute post-send action
155+
if (storageBackend.postSendAction) {
156+
logger.debug("Calling post-send hook...");
157+
await storageBackend.postSendAction(originalResult, PostSendActionMode.DRAFTS_UPLOAD);
158+
}
159+
158160
// Only send check
159161
if (onlySend && sent >= onlySend) {
160162
logger.warn(`Only sending ${onlySend} emails as requested.`);

email/workspace/quick-run.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
docsoc-mailmerge generate nunjucks ./data/names3.csv -o ./output -n test -b -c
1+
docsoc-mailmerge generate nunjucks ./data/names.csv -o ./output -n test -b -c
22
docsoc-mailmerge regenerate ./output/test
3-
docsoc-mailmerge upload-drafts ./output/test -y -s 2
4-
docsoc-mailmerge send ./output/test -s 5
3+
docsoc-mailmerge upload-drafts ./output/test -y -s 2 -n 1
4+
docsoc-mailmerge send ./output/test -s 5 -n 1

0 commit comments

Comments
 (0)