Add Mailing lists to Administration
A mailing list is an address that passes mail on to everyone on it. To Stalwart it is its own object, x:MailingList, behind sysMailingList*, so it gets its own section under Directory after Groups: search, fifty to a page with each list's recipient count, and a panel to create, edit and delete one. Recipients are a property of the list, so unlike a group's members they save with the rest of the panel. What Save sends for them is only what was added and removed, one recipients/<address> pointer each -- the patch the live server accepted -- so a recipient added elsewhere while the panel was open is not taken out. They can be pasted several at a time, from a spreadsheet column, a comma-separated line or Name <address>; anything with an @ that is not an address stays in the box with a note. Past a dozen, a filter narrows them. That is all a list is in Stalwart -- no owners, moderation or posting rules -- so that is all the panel offers. The mock answers x:MailingList with two lists, the recipient set's live shape, and the refusals a wrong address, a clash with an account and a missing permission get. Twenty-five new strings and one plural, in all nine catalogues.
This commit is contained in:
@@ -190,3 +190,31 @@ test("a group is created without a password, with Default roles", () => {
|
||||
assert.equal(list[0]!["@type"], "Group");
|
||||
assert.ok(!("memberGroupIds" in list[0]!));
|
||||
});
|
||||
|
||||
/** Mailing lists: their own object, with a set of recipient addresses. */
|
||||
test("a list is created, found by text, and read back with its address", () => {
|
||||
const dir = make("admin");
|
||||
const r = dir.handlers["x:MailingList/set"]!({ create: { n: { name: "team", domainId: "d1", recipients: { "[email protected]": true }, aliases: {} } } }) as { created: Record<string, { id: string }> };
|
||||
const id = r.created.n!.id;
|
||||
const q = dir.handlers["x:MailingList/query"]!({ filter: { text: "team" }, calculateTotal: true }) as { ids: string[] };
|
||||
assert.deepEqual(q.ids, [id]);
|
||||
const { list } = dir.handlers["x:MailingList/get"]!({ ids: [id] }) as { list: Array<{ emailAddress: string; recipients: Record<string, boolean> }> };
|
||||
assert.match(list[0]!.emailAddress, /^team@/);
|
||||
assert.deepEqual(list[0]!.recipients, { "[email protected]": true });
|
||||
});
|
||||
|
||||
test("a recipient pointer moves one address, and a bad one is refused", () => {
|
||||
const dir = make("admin");
|
||||
dir.handlers["x:MailingList/set"]!({ update: { l2: { "recipients/[email protected]": true, "recipients/[email protected]": null } } });
|
||||
const read = () => (dir.handlers["x:MailingList/get"]!({ ids: ["l2"] }) as { list: Array<{ recipients: Record<string, boolean> }> }).list[0]!.recipients;
|
||||
assert.deepEqual(Object.keys(read()).sort(), ["[email protected]", "[email protected]"]);
|
||||
const bad = dir.handlers["x:MailingList/set"]!({ update: { l2: { "recipients/not-an-address": true } } }) as { notUpdated?: Record<string, { type: string }> };
|
||||
assert.equal(bad.notUpdated?.l2?.type, "invalidPatch");
|
||||
});
|
||||
|
||||
test("a list's address cannot be one an account already has, and a role without the permission is refused", () => {
|
||||
const dir = make("admin");
|
||||
const clash = dir.handlers["x:MailingList/set"]!({ create: { n: { name: "demo", domainId: "d1" } } }) as { notCreated?: Record<string, { type: string }> };
|
||||
assert.equal(clash.notCreated?.n?.type, "primaryKeyViolation");
|
||||
assert.throws(() => make("helpdesk").handlers["x:MailingList/query"]!({}), (e: Refused) => e.type === "forbidden");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user