@social-mail/social-mail-web-server 1.5.415 → 1.5.416

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.
Files changed (174) hide show
  1. package/dist/common/Mailto.d.ts +17 -0
  2. package/dist/common/Mailto.d.ts.map +1 -0
  3. package/dist/common/Mailto.js +27 -0
  4. package/dist/common/Mailto.js.map +1 -0
  5. package/dist/common/cacheFor.d.ts +10 -1
  6. package/dist/common/cacheFor.d.ts.map +1 -1
  7. package/dist/common/cacheFor.js +18 -2
  8. package/dist/common/cacheFor.js.map +1 -1
  9. package/dist/server/model/SocialMailContext.d.ts +2 -0
  10. package/dist/server/model/SocialMailContext.d.ts.map +1 -1
  11. package/dist/server/model/SocialMailContext.js +2 -0
  12. package/dist/server/model/SocialMailContext.js.map +1 -1
  13. package/dist/server/model/SocialMailContextEvents.d.ts.map +1 -1
  14. package/dist/server/model/SocialMailContextEvents.js +3 -0
  15. package/dist/server/model/SocialMailContextEvents.js.map +1 -1
  16. package/dist/server/model/entities/Email.d.ts +2 -0
  17. package/dist/server/model/entities/Email.d.ts.map +1 -1
  18. package/dist/server/model/entities/Email.js.map +1 -1
  19. package/dist/server/model/entities/EmailAddress.d.ts +2 -0
  20. package/dist/server/model/entities/EmailAddress.d.ts.map +1 -1
  21. package/dist/server/model/entities/EmailAddress.js.map +1 -1
  22. package/dist/server/model/entities/EmailRecipient.d.ts +1 -1
  23. package/dist/server/model/entities/EmailRecipient.d.ts.map +1 -1
  24. package/dist/server/model/entities/EmailRecipient.js +2 -2
  25. package/dist/server/model/entities/EmailRecipient.js.map +1 -1
  26. package/dist/server/model/entities/Mailbox.d.ts +1 -0
  27. package/dist/server/model/entities/Mailbox.d.ts.map +1 -1
  28. package/dist/server/model/entities/Mailbox.js +4 -0
  29. package/dist/server/model/entities/Mailbox.js.map +1 -1
  30. package/dist/server/model/entities/ThreadParticipant.d.ts +22 -0
  31. package/dist/server/model/entities/ThreadParticipant.d.ts.map +1 -0
  32. package/dist/server/model/entities/ThreadParticipant.js +53 -0
  33. package/dist/server/model/entities/ThreadParticipant.js.map +1 -0
  34. package/dist/server/model/events/EmailEvents.d.ts.map +1 -1
  35. package/dist/server/model/events/EmailEvents.js +17 -7
  36. package/dist/server/model/events/EmailEvents.js.map +1 -1
  37. package/dist/server/model/events/MailboxEvents.d.ts.map +1 -1
  38. package/dist/server/model/events/MailboxEvents.js +2 -0
  39. package/dist/server/model/events/MailboxEvents.js.map +1 -1
  40. package/dist/server/model/events/ThreadParticipantEvents.d.ts +8 -0
  41. package/dist/server/model/events/ThreadParticipantEvents.d.ts.map +1 -0
  42. package/dist/server/model/events/ThreadParticipantEvents.js +19 -0
  43. package/dist/server/model/events/ThreadParticipantEvents.js.map +1 -0
  44. package/dist/server/seed/ui/seed-ui.js +1 -1
  45. package/dist/server/services/EmailAddressService.d.ts +4 -2
  46. package/dist/server/services/EmailAddressService.d.ts.map +1 -1
  47. package/dist/server/services/EmailAddressService.js +4 -4
  48. package/dist/server/services/EmailAddressService.js.map +1 -1
  49. package/dist/server/services/StoreFileService.d.ts +3 -1
  50. package/dist/server/services/StoreFileService.d.ts.map +1 -1
  51. package/dist/server/services/StoreFileService.js.map +1 -1
  52. package/dist/server/services/TemplateExpander.js +1 -1
  53. package/dist/server/services/TemplateExpander.js.map +1 -1
  54. package/dist/server/services/accounts/sales/SalesInvoiceService.d.ts +3 -1
  55. package/dist/server/services/accounts/sales/SalesInvoiceService.d.ts.map +1 -1
  56. package/dist/server/services/accounts/sales/SalesInvoiceService.js.map +1 -1
  57. package/dist/server/services/channels/ChannelModerationService.d.ts +8 -0
  58. package/dist/server/services/channels/ChannelModerationService.d.ts.map +1 -0
  59. package/dist/server/{smtp/services/EmailThreadService.js → services/channels/ChannelModerationService.js} +19 -7
  60. package/dist/server/services/channels/ChannelModerationService.js.map +1 -0
  61. package/dist/server/services/dom/HtmlSanitizer.d.ts.map +1 -1
  62. package/dist/server/services/dom/HtmlSanitizer.js +7 -1
  63. package/dist/server/services/dom/HtmlSanitizer.js.map +1 -1
  64. package/dist/server/services/domain-keys/DomainKeyService.d.ts +3 -1
  65. package/dist/server/services/domain-keys/DomainKeyService.d.ts.map +1 -1
  66. package/dist/server/services/domain-keys/DomainKeyService.js.map +1 -1
  67. package/dist/server/services/files/FileAccessService.d.ts +3 -1
  68. package/dist/server/services/files/FileAccessService.d.ts.map +1 -1
  69. package/dist/server/services/files/FileAccessService.js +0 -2
  70. package/dist/server/services/files/FileAccessService.js.map +1 -1
  71. package/dist/server/services/files/SnapshotService.d.ts +3 -1
  72. package/dist/server/services/files/SnapshotService.d.ts.map +1 -1
  73. package/dist/server/services/files/SnapshotService.js.map +1 -1
  74. package/dist/server/services/files/WebSiteService.d.ts +3 -1
  75. package/dist/server/services/files/WebSiteService.d.ts.map +1 -1
  76. package/dist/server/services/files/WebSiteService.js.map +1 -1
  77. package/dist/server/services/store/StoreConfigService.d.ts +3 -1
  78. package/dist/server/services/store/StoreConfigService.d.ts.map +1 -1
  79. package/dist/server/services/store/StoreConfigService.js.map +1 -1
  80. package/dist/server/services/threads/EmailThreadService.d.ts +7 -0
  81. package/dist/server/services/threads/EmailThreadService.d.ts.map +1 -0
  82. package/dist/server/services/threads/EmailThreadService.js +45 -0
  83. package/dist/server/services/threads/EmailThreadService.js.map +1 -0
  84. package/dist/server/smtp/dns/DnsService.d.ts +3 -1
  85. package/dist/server/smtp/dns/DnsService.d.ts.map +1 -1
  86. package/dist/server/smtp/dns/DnsService.js.map +1 -1
  87. package/dist/server/smtp/services/AccessTokenService.d.ts +4 -2
  88. package/dist/server/smtp/services/AccessTokenService.d.ts.map +1 -1
  89. package/dist/server/smtp/services/AccessTokenService.js +23 -28
  90. package/dist/server/smtp/services/AccessTokenService.js.map +1 -1
  91. package/dist/server/smtp/services/CachedEmailService.d.ts.map +1 -1
  92. package/dist/server/smtp/services/CachedEmailService.js +6 -1
  93. package/dist/server/smtp/services/CachedEmailService.js.map +1 -1
  94. package/dist/server/smtp/services/EmailPostReceiveService.d.ts +8 -0
  95. package/dist/server/smtp/services/EmailPostReceiveService.d.ts.map +1 -1
  96. package/dist/server/smtp/services/EmailPostReceiveService.js +48 -6
  97. package/dist/server/smtp/services/EmailPostReceiveService.js.map +1 -1
  98. package/dist/server/smtp/services/EngagementService.d.ts.map +1 -1
  99. package/dist/server/smtp/services/EngagementService.js +5 -0
  100. package/dist/server/smtp/services/EngagementService.js.map +1 -1
  101. package/dist/server/smtp/services/WebSiteChannelService.d.ts +3 -3
  102. package/dist/server/smtp/services/WebSiteChannelService.d.ts.map +1 -1
  103. package/dist/server/smtp/services/WebSiteChannelService.js +27 -26
  104. package/dist/server/smtp/services/WebSiteChannelService.js.map +1 -1
  105. package/dist/server/storage/TempFileService.d.ts.map +1 -1
  106. package/dist/server/storage/TempFileService.js +7 -2
  107. package/dist/server/storage/TempFileService.js.map +1 -1
  108. package/dist/server/templates/channel/SubscriberRequested.d.ts.map +1 -1
  109. package/dist/server/templates/channel/SubscriberRequested.js +5 -1
  110. package/dist/server/templates/channel/SubscriberRequested.js.map +1 -1
  111. package/dist/server/workflows/pending/PendingPostReceiveWorkflow.d.ts.map +1 -1
  112. package/dist/server/workflows/pending/PendingPostReceiveWorkflow.js +3 -14
  113. package/dist/server/workflows/pending/PendingPostReceiveWorkflow.js.map +1 -1
  114. package/dist/server/workflows/smtp/DispatchEmailToMX.d.ts +3 -1
  115. package/dist/server/workflows/smtp/DispatchEmailToMX.d.ts.map +1 -1
  116. package/dist/server/workflows/smtp/DispatchEmailToMX.js +30 -4
  117. package/dist/server/workflows/smtp/DispatchEmailToMX.js.map +1 -1
  118. package/dist/server/workflows/smtp/MailDispatcherService.d.ts.map +1 -1
  119. package/dist/server/workflows/smtp/MailDispatcherService.js +5 -1
  120. package/dist/server/workflows/smtp/MailDispatcherService.js.map +1 -1
  121. package/dist/server/workflows/smtp/PrepareEmailToSend.d.ts +3 -1
  122. package/dist/server/workflows/smtp/PrepareEmailToSend.d.ts.map +1 -1
  123. package/dist/server/workflows/smtp/PrepareEmailToSend.js +15 -4
  124. package/dist/server/workflows/smtp/PrepareEmailToSend.js.map +1 -1
  125. package/dist/tsconfig.tsbuildinfo +1 -1
  126. package/dist/wwwroot/routes/@[channel]/[slug]/index.js +4 -4
  127. package/dist/wwwroot/routes/@[channel]/[slug]/index.js.map +1 -1
  128. package/dist/wwwroot/routes/api/site/snapshot/index.d.ts.map +1 -1
  129. package/dist/wwwroot/routes/api/site/snapshot/index.js.map +1 -1
  130. package/package.json +3 -3
  131. package/src/common/Mailto.ts +39 -0
  132. package/src/common/cacheFor.ts +26 -4
  133. package/src/server/model/SocialMailContext.ts +3 -0
  134. package/src/server/model/SocialMailContextEvents.ts +4 -0
  135. package/src/server/model/entities/Email.ts +2 -0
  136. package/src/server/model/entities/EmailAddress.ts +2 -0
  137. package/src/server/model/entities/EmailRecipient.ts +2 -2
  138. package/src/server/model/entities/Mailbox.ts +3 -0
  139. package/src/server/model/entities/ThreadParticipant.ts +45 -0
  140. package/src/server/model/events/EmailEvents.ts +19 -7
  141. package/src/server/model/events/MailboxEvents.ts +2 -0
  142. package/src/server/model/events/ThreadParticipantEvents.ts +27 -0
  143. package/src/server/seed/ui/seed-ui.ts +1 -1
  144. package/src/server/services/EmailAddressService.ts +8 -5
  145. package/src/server/services/StoreFileService.ts +6 -2
  146. package/src/server/services/TemplateExpander.ts +1 -1
  147. package/src/server/services/accounts/sales/SalesInvoiceService.ts +5 -2
  148. package/src/server/services/channels/ChannelModerationService.ts +27 -0
  149. package/src/server/services/dom/HtmlSanitizer.ts +7 -1
  150. package/src/server/services/domain-keys/DomainKeyService.ts +4 -2
  151. package/src/server/services/files/FileAccessService.ts +4 -5
  152. package/src/server/services/files/SnapshotService.ts +5 -2
  153. package/src/server/services/files/WebSiteService.ts +5 -2
  154. package/src/server/services/store/StoreConfigService.ts +5 -2
  155. package/src/server/services/tags/TagService.ts +1 -1
  156. package/src/server/services/threads/EmailThreadService.ts +39 -0
  157. package/src/server/smtp/dns/DnsService.ts +4 -3
  158. package/src/server/smtp/services/AccessTokenService.ts +20 -22
  159. package/src/server/smtp/services/CachedEmailService.ts +5 -1
  160. package/src/server/smtp/services/EmailPostReceiveService.ts +54 -9
  161. package/src/server/smtp/services/EngagementService.ts +6 -0
  162. package/src/server/smtp/services/WebSiteChannelService.ts +17 -17
  163. package/src/server/storage/TempFileService.ts +7 -2
  164. package/src/server/templates/channel/SubscriberRequested.tsx +5 -1
  165. package/src/server/workflows/pending/PendingPostReceiveWorkflow.ts +3 -16
  166. package/src/server/workflows/smtp/DispatchEmailToMX.ts +33 -3
  167. package/src/server/workflows/smtp/MailDispatcherService.ts +6 -1
  168. package/src/server/workflows/smtp/PrepareEmailToSend.ts +16 -3
  169. package/src/wwwroot/routes/@[channel]/[slug]/index.tsx +4 -4
  170. package/src/wwwroot/routes/api/site/snapshot/index.ts +1 -0
  171. package/dist/server/smtp/services/EmailThreadService.d.ts +0 -7
  172. package/dist/server/smtp/services/EmailThreadService.d.ts.map +0 -1
  173. package/dist/server/smtp/services/EmailThreadService.js.map +0 -1
  174. package/src/server/smtp/services/EmailThreadService.ts +0 -15
@@ -1,5 +1,5 @@
1
1
  import Inject, { RegisterSingleton, ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
2
- import { cacheFor } from "../../../common/cacheFor.js";
2
+ import {ICacheContainer, ObjectCache, cacheFor } from "../../../common/cacheFor.js";
3
3
  import { globalServices } from "../../../globalServices.js";
4
4
  import SocialMailContext from "../../model/SocialMailContext.js";
5
5
  import EncryptionService from "../encryption/EncryptionService.js";
@@ -7,8 +7,11 @@ import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
7
7
  import { chainToCamel } from "../../../common/chainToCamel.js";
8
8
  import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
9
9
 
10
+
10
11
  @RegisterSingleton
11
- export default class StoreConfigService {
12
+ export default class StoreConfigService implements ICacheContainer<StoreConfigService> {
13
+
14
+ cache: ObjectCache<StoreConfigService>;
12
15
 
13
16
  @Inject
14
17
  encryptionService: EncryptionService;
@@ -2,7 +2,7 @@
2
2
  import { RegisterSingleton, ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
3
3
  import SocialMailContext from "../../model/SocialMailContext.js";
4
4
  import { ConsoleLogger } from "@entity-access/entity-access/dist/common/Logger.js";
5
- import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
5
+
6
6
  import Tag from "../../model/entities/Tag.js";
7
7
 
8
8
  @RegisterSingleton
@@ -0,0 +1,39 @@
1
+ import Inject, { RegisterScoped } from "@entity-access/entity-access/dist/di/di.js";
2
+ import SocialMailContext from "../../model/SocialMailContext.js";
3
+
4
+ @RegisterScoped
5
+ export default class EmailThreadService {
6
+
7
+ @Inject
8
+ db: SocialMailContext;
9
+
10
+ async unsubscribe(senderID, emailID) {
11
+
12
+ const { db } = this;
13
+
14
+ const threadID = (await db.emails.where({ emailID }, (p) => (x) => x.emailID === p.emailID)
15
+ .map(void 0, (p) => (x) => ({ threadID: x.threadID})).first())?.threadID ?? emailID;
16
+ await db.threadParticipants.statements.update({
17
+ unsubscribed: true
18
+ }, {
19
+ emailAddressID: senderID,
20
+ emailID: threadID
21
+ });
22
+
23
+ }
24
+
25
+ async saveParticipant(senderID, emailID) {
26
+ const { db } = this;
27
+
28
+ const threadID = (await db.emails.where({ emailID }, (p) => (x) => x.emailID === p.emailID)
29
+ .map(void 0, (p) => (x) => ({ threadID: x.threadID})).first())?.threadID ?? emailID;
30
+ await db.threadParticipants.statements.selectOrInsert({
31
+ emailAddressID: senderID,
32
+ emailID: threadID
33
+ }, {
34
+ emailAddressID: senderID,
35
+ emailID: threadID
36
+ });
37
+ }
38
+
39
+ }
@@ -1,8 +1,8 @@
1
1
  import { RegisterSingleton } from "@entity-access/entity-access/dist/di/di.js";
2
2
  import dns2 from "dns2";
3
3
  import { SPFRecords } from "./SPFRecords.js";
4
- import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
5
- import { cacheFor } from "../../../common/cacheFor.js";
4
+
5
+ import {ICacheContainer, ObjectCache, cacheFor } from "../../../common/cacheFor.js";
6
6
 
7
7
  export interface IDKIMRecord {
8
8
  keyType: string;
@@ -11,8 +11,9 @@ export interface IDKIMRecord {
11
11
 
12
12
 
13
13
  @RegisterSingleton
14
- export default class DnsService {
14
+ export default class DnsService implements ICacheContainer<DnsService> {
15
15
 
16
+ cache: ObjectCache<DnsService>;
16
17
 
17
18
  @cacheFor()
18
19
  public async getDomainKey(selector: string, domain: string, nameServers?: string[]): Promise<IDKIMRecord> {
@@ -1,33 +1,31 @@
1
- import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
1
+
2
2
  import { RegisterSingleton, ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
3
3
  import SocialMailContext from "../../model/SocialMailContext.js";
4
4
  import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
5
5
  import EntityAccessError from "@entity-access/entity-access/dist/common/EntityAccessError.js";
6
-
7
- const timedCache = new TimedCache();
6
+ import { ICacheContainer, ObjectCache } from "../../../common/cacheFor.js";
8
7
 
9
8
  @RegisterSingleton
10
- export default class AccessTokenService {
9
+ export default class AccessTokenService implements ICacheContainer<AccessTokenService> {
10
+
11
+ cache: ObjectCache<AccessTokenService>;
11
12
 
12
13
  async login(tokenID, secret) {
13
- const key = `${tokenID}-${secret}`;
14
- return timedCache.getOrCreateAsync(key, async (k) => {
15
- using scope = ServiceProvider.createScope(this);
16
- const db = scope.resolve(SocialMailContext);
17
- const tokens = await db.accessTokens
18
- .where({ tokenID, secret } , (p) => (x) =>
19
- x.tokenID === p.tokenID as any
20
- && x.secret === p.secret)
21
- .updateSelect(void 0, (p) => (x) => ({
22
- lastUsed: Sql.date.now()
23
- }));
24
- const token = tokens[0];
25
- if (!token) {
26
- throw new EntityAccessError(`Invalid access token`);
27
- }
28
- await db.changeSet.getEntry(token).loadNavigationAsync((x) => x.user);
29
- return token.user;
30
- });
14
+ using scope = ServiceProvider.createScope(this);
15
+ const db = scope.resolve(SocialMailContext);
16
+ const tokens = await db.accessTokens
17
+ .where({ tokenID, secret } , (p) => (x) =>
18
+ x.tokenID === p.tokenID as any
19
+ && x.secret === p.secret)
20
+ .updateSelect(void 0, (p) => (x) => ({
21
+ lastUsed: Sql.date.now()
22
+ }));
23
+ const token = tokens[0];
24
+ if (!token) {
25
+ throw new EntityAccessError(`Invalid access token`);
26
+ }
27
+ await db.changeSet.getEntry(token).loadNavigationAsync((x) => x.user);
28
+ return token.user;
31
29
  }
32
30
 
33
31
  }
@@ -38,7 +38,11 @@ export default class CachedEmailService {
38
38
 
39
39
  let logFile: EmailLog;
40
40
 
41
- if (!signedFileLogID) {
41
+ if (signedFileLogID) {
42
+ logFile = await this.db.emailLogs
43
+ .where({ signedFileLogID }, (p) => (x) => x.logID === p.signedFileLogID)
44
+ .first();
45
+ } else {
42
46
 
43
47
  if (emailAddressID) {
44
48
 
@@ -13,6 +13,8 @@ import SendWebPushNotification from "../../workflows/web-push/SendWebPushNotific
13
13
  import TempFileService from "../../storage/TempFileService.js";
14
14
  import CachedEmailService from "./CachedEmailService.js";
15
15
  import QueueInvokeWebHookWorkflow from "../../workflows/web-hooks/QueueInvokeWebHookWorkflow.js";
16
+ import EmailThreadService from "../../services/threads/EmailThreadService.js";
17
+ import ChannelModerationService from "../../services/channels/ChannelModerationService.js";
16
18
 
17
19
  @RegisterScoped
18
20
  export default class EmailPostReceiveService {
@@ -35,6 +37,29 @@ export default class EmailPostReceiveService {
35
37
  @Inject
36
38
  context?: WorkflowContext;
37
39
 
40
+ @Inject
41
+ ets?: EmailThreadService;
42
+
43
+ @Inject
44
+ cms?: ChannelModerationService;
45
+
46
+ async executeAll({ senderID, emailID }) {
47
+ const { db } = this;
48
+ const mcs = await db.mailboxContactEmails.where({ emailID, senderID}, (p) => (x) => x.emailID === p.emailID
49
+ && x.mailboxID !== p.senderID )
50
+ .select(void 0, (p) => ({ mailboxID }) => ({ mailboxID }))
51
+ .toArray();
52
+
53
+ for (const { mailboxID } of mcs) {
54
+ await this.execute({
55
+ senderID,
56
+ emailID,
57
+ recipientID: mailboxID
58
+ });
59
+ }
60
+ await db.emails.statements.update({ statePostReceiveInvoked: true}, { emailID });
61
+ }
62
+
38
63
  async execute(input: { senderID, emailID, recipientID }) {
39
64
  await this.dispatchChannel(input);
40
65
  await this.queueWebHooks(input);
@@ -93,7 +118,8 @@ export default class EmailPostReceiveService {
93
118
  return;
94
119
  }
95
120
 
96
- const isHostedChannelID = await eas.isHostedChannelID(recipientID);
121
+ let channel = await eas.getHostedMailbox(recipientID);
122
+ channel = channel?.isChannel ? channel : void 0;
97
123
 
98
124
  if (ne.engagement) {
99
125
 
@@ -104,17 +130,20 @@ export default class EmailPostReceiveService {
104
130
 
105
131
  switch(ne.engagement) {
106
132
  case "✅":
107
- if (isHostedChannelID) {
133
+ if (channel) {
108
134
  return await channelService.approveSubscriber(emailID);
109
135
  }
110
136
  return;
111
137
  case "🔔":
112
- case "🔕":
113
- case "❌":
114
138
  case "📈":
115
139
  return;
140
+ case "🔕":
141
+ case "❌":
142
+ // unsubscribe particular thread...
143
+ await this.ets.unsubscribe(senderID, emailID);
144
+ return;
116
145
  case "➕":
117
- if (isHostedChannelID) {
146
+ if (channel) {
118
147
  await BroadcastEmail.broadcast(this.context, {
119
148
  mailboxID: recipientID,
120
149
  emailID,
@@ -125,13 +154,21 @@ export default class EmailPostReceiveService {
125
154
  return;
126
155
  case "💬":
127
156
  // following will make comment appear publicly
128
- // todo: moderation...
129
- await db.emails.where(input, (p) => (x) => x.emailID === p.emailID
157
+ if (channel && !channel.isPrivateChannel && channel.requiresCommentModeration) {
158
+ await db.emails.where(input, (p) => (x) => x.emailID === p.emailID
130
159
  && x.parent.status === "published"
131
160
  )
132
- .update(void 0, (p) => (x) => ({ status: "published" }));
161
+ .update(void 0, (p) => (x) => ({ status: "pending-approval" }));
162
+ return;
163
+ }
164
+ await db.emails.where(input, (p) => (x) => x.emailID === p.emailID
165
+ && x.parent.status === "published"
166
+ )
167
+ .update(void 0, (p) => (x) => ({ status: "published" }));
168
+ await this.ets.saveParticipant(senderID, emailID);
133
169
  return;
134
170
  default:
171
+ await this.ets.saveParticipant(senderID, emailID);
135
172
  return;
136
173
  }
137
174
  }
@@ -141,7 +178,7 @@ export default class EmailPostReceiveService {
141
178
  && x.emailAddressID === p.senderID)
142
179
  .first();
143
180
 
144
- if(!isHostedChannelID) {
181
+ if(!channel) {
145
182
 
146
183
  // send push notification here...
147
184
  if (mc?.blocked) {
@@ -160,6 +197,12 @@ export default class EmailPostReceiveService {
160
197
  return;
161
198
  }
162
199
 
200
+ if (!channel.isPrivateChannel && channel.requiresPostModeration) {
201
+ if(await this.cms.addToQueue(channel, emailID, mc)) {
202
+ return;
203
+ }
204
+ }
205
+
163
206
  // can send...
164
207
  if (!mc || !(mc.canContribute || mc.isOwner)) {
165
208
  return;
@@ -205,6 +248,8 @@ export default class EmailPostReceiveService {
205
248
  }
206
249
  }
207
250
 
251
+ await this.ets.saveParticipant(senderID, emailID);
252
+
208
253
  await BroadcastEmail.broadcast(this.context, {
209
254
  mailboxID: recipientID,
210
255
  emailID,
@@ -137,6 +137,12 @@ export default class EngagementService {
137
137
  engagement: p.engagement
138
138
  }));
139
139
  }
140
+ return;
141
+ }
142
+
143
+ const en = await this.extractEngagementFromBody(email);
144
+ if (en) {
145
+ await this.db.emails.statements.update({ engagement: en}, { emailID: email.emailID});
140
146
  }
141
147
  }
142
148
 
@@ -1,30 +1,30 @@
1
- import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
1
+
2
2
  import Inject, { RegisterScoped, RegisterSingleton, RegisterTransient, ServiceCollection, ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
3
3
  import SocialMailContext from "../../model/SocialMailContext.js";
4
4
  import GlobalEvents from "../../../common/GlobalEvents.js";
5
+ import { cacheFor, ICacheContainer, ObjectCache } from "../../../common/cacheFor.js";
6
+
7
+ export default class WebSiteChannelService implements ICacheContainer<WebSiteChannelService> {
5
8
 
6
- export default class WebSiteChannelService {
9
+ cache: ObjectCache<WebSiteChannelService>;
7
10
 
8
11
  @Inject
9
12
  globalEvents: GlobalEvents;
10
13
 
11
- cache = new TimedCache<string, number[]>();
12
-
13
- getMailboxes(host: string) {
14
- return this.cache.getOrCreateAsync(host, async (host) => {
15
- using scope = ServiceProvider.createScope(this);
16
- const db = scope.resolve(SocialMailContext);
14
+ @cacheFor()
15
+ async getMailboxes(host: string) {
16
+ using scope = ServiceProvider.createScope(this);
17
+ const db = scope.resolve(SocialMailContext);
17
18
 
18
- host = host?.toLocaleLowerCase() ?? "localhost";
19
+ host = host?.toLocaleLowerCase() ?? "localhost";
19
20
 
20
- const mailboxes = await db.mailboxes.where({ host}, (p) => (x) =>
21
- x.websiteChannels
22
- .some((w) => w.website.hosts
23
- .some((h)=> h.host === p.host)))
24
- .toArray();
21
+ const mailboxes = await db.mailboxes.where({ host}, (p) => (x) =>
22
+ x.websiteChannels
23
+ .some((w) => w.website.hosts
24
+ .some((h)=> h.host === p.host)))
25
+ .toArray();
25
26
 
26
- return mailboxes.map((x) => x.mailboxID);
27
- });
27
+ return mailboxes.map((x) => x.mailboxID);
28
28
  }
29
29
 
30
30
  clear() {
@@ -32,7 +32,7 @@ export default class WebSiteChannelService {
32
32
  }
33
33
 
34
34
  protected postInit() {
35
- this.globalEvents.on("web-site-channel-host-clear" as any, () => this.cache.clear() );
35
+ this.globalEvents.on("web-site-channel-host-clear" as any, () => this.cache?.clear("getMailboxes") );
36
36
  }
37
37
 
38
38
  }
@@ -19,6 +19,7 @@ import GZip from "./compression/gz.js";
19
19
  import DiskCacheService from "../services/cache/DiskCacheService.js";
20
20
  import ensureDir from "../../common/FileApi.js";
21
21
  import { globalEnv } from "../../common/globalEnv.js";
22
+ import { platform } from "os";
22
23
 
23
24
  const tmpdir = globalEnv.tmpDir;
24
25
  const tmpPath = path.join(tmpdir, "t");
@@ -184,8 +185,12 @@ export default class TempFileService {
184
185
  // and remove folder's write permission so file cannot be deleted
185
186
 
186
187
  const tf = await this.createTempFile(fileInfo.ext, fileName, contentType);
187
- if (existsSync(tf.path)) {
188
- await fsp.unlink(tf.path);
188
+ if (platform() !== "win32") {
189
+ // this fails in docker alpine
190
+ // don't know why...
191
+ if (existsSync(tf.path)) {
192
+ await fsp.unlink(tf.path);
193
+ }
189
194
  }
190
195
  // await fsp.symlink(typeof src === "string" ? src : src.path, tf.path);
191
196
  // This operation would be fast
@@ -1,4 +1,5 @@
1
1
  import XNode from "@entity-access/server-pages/dist/html/XNode.js";
2
+ import { Mailto } from "../../../common/Mailto.js";
2
3
 
3
4
  export default function SubscriberRequested({
4
5
  channelEmail,
@@ -6,6 +7,9 @@ export default function SubscriberRequested({
6
7
  emailAddress,
7
8
  html
8
9
  }) {
10
+ const link = Mailto.templateLink({
11
+ emoji: "✅",
12
+ });
9
13
  return <div>
10
14
  Subscriber: {name} &lt; {emailAddress} &gt; wants to join your network.
11
15
  <br/>
@@ -18,7 +22,7 @@ export default function SubscriberRequested({
18
22
  <br/>
19
23
  <a
20
24
  style="border: none; text-decoration: none;"
21
- data-social-mail-command="approve"
25
+ href={link}
22
26
  title="Approve">
23
27
  <button style="margin: 1px;padding:2px;padding-left: 5px;padding-right: 5px; border: solid 1px lightgray; border-radius: 9999px; display: inline-flex; align-items: center;">
24
28
  ✅ Approve
@@ -46,29 +46,16 @@ export default class PendingPostReceiveWorkflow extends Workflow {
46
46
  return 0;
47
47
  }
48
48
 
49
- for (const { emailID, senderID } of items) {
49
+ for (const item of items) {
50
50
  try {
51
-
52
51
  // channels can never send an email
53
-
54
- const mcs = await db.mailboxContactEmails.where({ emailID, senderID}, (p) => (x) => x.emailID === p.emailID
55
- && x.mailboxID !== p.senderID )
56
- .select(void 0, (p) => ({ mailboxID }) => ({ mailboxID }))
57
- .toArray();
58
- for(const { mailboxID } of mcs) {
59
- await prs.execute({
60
- senderID,
61
- emailID,
62
- recipientID: mailboxID
63
- });
64
- }
65
- await db.emails.statements.update({ statePostReceiveInvoked: true}, { emailID });
52
+ await prs.executeAll(item);
66
53
  } catch (error) {
67
54
  console.warn(error);
68
55
  // we will ignore and continue?
69
56
  }
70
57
  db.changeSet.clear();
71
- start = emailID;
58
+ start = item.emailID;
72
59
  }
73
60
 
74
61
  return start;
@@ -17,6 +17,8 @@ import ESmtpClient from "../../../protocols/smtp/ESmtpClient.js";
17
17
  import DnsService from "../../smtp/dns/DnsService.js";
18
18
  import EncryptionService from "../../services/encryption/EncryptionService.js";
19
19
  import EmailReferenceService from "../../smtp/services/EmailReferenceService.js";
20
+ import EmailPostReceiveService from "../../smtp/services/EmailPostReceiveService.js";
21
+ import EngagementService from "../../smtp/services/EngagementService.js";
20
22
 
21
23
  export const smtpPool = new NamedObjectPool<SMTPClient>((host) => ({
22
24
  asyncFactory: () => new SMTPClient({ host }).connect(),
@@ -167,7 +169,9 @@ export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
167
169
  @Inject els?: EmailLogService,
168
170
  @Inject eas?: EmailAddressService,
169
171
  @Inject db?: SocialMailContext,
170
- @Inject ers?: EmailReferenceService
172
+ @Inject ers?: EmailReferenceService,
173
+ @Inject eps?: EmailPostReceiveService,
174
+ @Inject ees?: EngagementService
171
175
  ) {
172
176
 
173
177
  // if it is local...
@@ -177,9 +181,34 @@ export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
177
181
  const mailboxID = await eas.getHostedMailboxID(this.input.to[0]);
178
182
 
179
183
  if (!external && mailboxID) {
180
- // const dateReceived = DateTime.now;
181
184
 
182
- // await ers.updateReferences({ emailID, dateUpdated: dateReceived, silent: false, timeRead: null });
185
+ const dateReceived = DateTime.now;
186
+ try {
187
+
188
+ // internal broad casting is not working
189
+ // we either need to create an email or add the recipient
190
+
191
+ await db.mailboxEmails.statements.selectOrInsert({
192
+ mailboxID,
193
+ emailID
194
+ });
195
+
196
+ await db.mailboxContactEmails.statements.selectOrInsert({
197
+ mailboxID,
198
+ emailID,
199
+ emailAddressID,
200
+ signedFileLogID,
201
+ dateReceived
202
+ });
203
+
204
+
205
+ // await ers.updateReferences({ emailID, dateUpdated: dateReceived, silent: false, timeRead: null });
206
+ if (senderID !== emailAddressID) {
207
+ await eps.execute({ senderID, emailID, recipientID: emailAddressID });
208
+ }
209
+ } catch {
210
+
211
+ }
183
212
 
184
213
  // await PostReceiveWorkflow.queue(this.context, {
185
214
  // senderID: this.input.senderID,
@@ -188,6 +217,7 @@ export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
188
217
  // sent: false
189
218
  // });
190
219
 
220
+
191
221
  return {
192
222
  statusCode: SmtpStatusCodes.Ok,
193
223
  status: "Ok",
@@ -78,7 +78,11 @@ export default class MailDispatcherService {
78
78
  .include((x) => x.emailAddress)
79
79
  .first();
80
80
 
81
- to ??= email.recipients.map((r) => r.replyTo ?? r.emailAddress.emailAddress);
81
+ to ??= email.recipients.filter((r) => r.type === "to")
82
+ .map((r) => r.replyTo ?? r.emailAddress.emailAddress);
83
+
84
+ const cc = email.recipients.filter((r) => r.type === "cc")
85
+ .map((r) => r.emailAddress.emailAddress);
82
86
 
83
87
  if (!email.senderName) {
84
88
  email.senderName = email.senderEmail.mailbox.emailAddress.name;
@@ -140,6 +144,7 @@ export default class MailDispatcherService {
140
144
  const mail = new MailComposer({
141
145
  from: { name: email.senderName, address: mb.emailAddress.emailAddress },
142
146
  to,
147
+ cc,
143
148
  html,
144
149
  text: email.textBody,
145
150
  subject: email.subject,
@@ -4,6 +4,9 @@ import Workflow, { UniqueActivity } from "@entity-access/entity-access/dist/work
4
4
  // import BroadcastEmailToMX from "../channel/BroadcastEmailToMX.js";
5
5
  import DispatchEmailToMX from "./DispatchEmailToMX.js";
6
6
  import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
7
+ import PendingReferencesWorkflow from "../pending/PendingReferencesWorkflow.js";
8
+ import EmailReferenceService from "../../smtp/services/EmailReferenceService.js";
9
+ import EmailPostReceiveService from "../../smtp/services/EmailPostReceiveService.js";
7
10
 
8
11
  const pad = (n, max) => {
9
12
  if (n < 0) {
@@ -102,12 +105,22 @@ export default class PrepareEmailToSend extends Workflow<number, string> {
102
105
 
103
106
  @UniqueActivity
104
107
  async updateStatus(
105
- @Inject db?: SocialMailContext
108
+ @Inject db?: SocialMailContext,
109
+ @Inject ers?: EmailReferenceService,
110
+ @Inject eps?: EmailPostReceiveService
106
111
  ) {
107
- await db.emails.where({ id: this.input}, (p) => (x) => x.emailID === p.id && x.status !== "published")
108
- .update(void 0, (p) => (x) => ({
112
+ const [sent] = await db.emails.where({ id: this.input}, (p) => (x) => x.emailID === p.id && x.status !== "published")
113
+ .updateSelect(void 0, (p) => (x) => ({
109
114
  status: "sent",
110
115
  dateUpdated: Sql.date.now()
111
116
  }));
117
+
118
+ const emailID = this.input;
119
+
120
+ await ers.updateReferences({ emailID, silent: true });
121
+ await db.emails.statements.update({ stateReferencesUpdated: true}, { emailID });
122
+
123
+ // load recipients...
124
+ await eps.executeAll(sent);
112
125
  }
113
126
  }
@@ -84,14 +84,14 @@ export default class extends Page {
84
84
 
85
85
  if (meta?.length) {
86
86
  body = body.replace(/\<head[^\>]*\>/, (s, v) => {
87
- return s + meta.map((x) => x.render()).join("\r\n");
87
+ return s + meta.map((x) => x.render()).join("\r\n") + "\r\n";
88
88
  });
89
89
  }
90
- body = body.replace(/\<head[^\>]*\>/, (s, v) => {
91
- return s + `<script>var socialMail = ${socialMail};</script>`;
92
- });
93
90
  }
94
91
 
92
+ body = body.replace(/\<head[^\>]*\>/, (s, v) => {
93
+ return s + `\r\n<script>var socialMail = ${socialMail};</script>\r\n`;
94
+ });
95
95
  // const body = await this.channelPageService.modifyPage({
96
96
  // host,
97
97
  // url: this.request.URL.toString(),
@@ -12,6 +12,7 @@ import CacheService from "../../../../../server/services/cache/CacheService.js";
12
12
  import { globalEnv } from "../../../../../common/globalEnv.js";
13
13
  import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
14
14
 
15
+
15
16
  const cache = new TimedCache();
16
17
 
17
18
  /**
@@ -1,7 +0,0 @@
1
- import SocialMailContext from "../../model/SocialMailContext.js";
2
- import { Email } from "../../model/entities/Email.js";
3
- export declare class EmailThreadService {
4
- db: SocialMailContext;
5
- fixThreads(email: Email): Promise<void>;
6
- }
7
- //# sourceMappingURL=EmailThreadService.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EmailThreadService.d.ts","sourceRoot":"","sources":["../../../../src/server/smtp/services/EmailThreadService.ts"],"names":[],"mappings":"AACA,OAAO,iBAAiB,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAEtD,qBACa,kBAAkB;IAG3B,EAAE,EAAE,iBAAiB,CAAC;IAEhB,UAAU,CAAC,KAAK,EAAE,KAAK;CAIhC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"EmailThreadService.js","sourceRoot":"","sources":["../../../../src/server/smtp/services/EmailThreadService.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,iBAAiB,MAAM,kCAAkC,CAAC;AAI1D,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAK3B,KAAK,CAAC,UAAU,CAAC,KAAY;IAE7B,CAAC;CAEJ,CAAA;AANG;IADC,MAAM;8BACH,iBAAiB;8CAAC;AAHb,kBAAkB;IAD9B,cAAc;GACF,kBAAkB,CAS9B"}
@@ -1,15 +0,0 @@
1
- import Inject, { RegisterScoped } from "@entity-access/entity-access/dist/di/di.js";
2
- import SocialMailContext from "../../model/SocialMailContext.js";
3
- import { Email } from "../../model/entities/Email.js";
4
-
5
- @RegisterScoped
6
- export class EmailThreadService {
7
-
8
- @Inject
9
- db: SocialMailContext;
10
-
11
- async fixThreads(email: Email) {
12
-
13
- }
14
-
15
- }