Skip to content

Commit 23c6cf3

Browse files
authored
Feat: Add HtmlValidation ruleset to config. (#1697)
1 parent 6644acd commit 23c6cf3

20 files changed

+212
-119
lines changed

Rnwood.Smtp4dev/ApiModel/Server.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class Server
6666
public string CurrentUserName { get; set; }
6767

6868
public string CurrentUserDefaultMailboxName { get; set; }
69+
public string HtmlValidateConfig { get; set; }
6970
}
7071

7172
}

Rnwood.Smtp4dev/ClientApp/src/ApiClient/Server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ export default class Server {
2626
smtpEnabledAuthTypesWhenSecureConnection: string[],
2727
mailboxes: Mailbox[],
2828
currentUserName: string,
29-
currentUserDefaultMailboxName: string
29+
currentUserDefaultMailboxName: string,
30+
htmlValidateConfig: string
3031
) {
3132

3233
this.isRunning = isRunning;
@@ -66,6 +67,7 @@ export default class Server {
6667
this.mailboxes = mailboxes;
6768
this.currentUserName = currentUserName;
6869
this.currentUserDefaultMailboxName = currentUserDefaultMailboxName;
70+
this.htmlValidateConfig = htmlValidateConfig;
6971
}
7072

7173

@@ -104,4 +106,5 @@ export default class Server {
104106
smtpEnabledAuthTypesWhenNotSecureConnection: string[];
105107
smtpEnabledAuthTypesWhenSecureConnection: string[];
106108
mailboxes: Mailbox[];
109+
htmlValidateConfig: string;
107110
}

Rnwood.Smtp4dev/ClientApp/src/ApiClient/ServerController.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11

22

3+
import HubConnectionManager from '../HubConnectionManager';
34
import Server from './Server';
45
import axios from "axios";
56

67
export default class ServerController {
78

8-
constructor(){
9-
}
109

11-
12-
1310
// get: api/Server
1411
public getServer_url(): string {
1512
return `api/Server`;

Rnwood.Smtp4dev/ClientApp/src/HubConnectionManager.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
2+
import Server from './ApiClient/Server';
3+
import ServerController from './ApiClient/ServerController';
24

35
export default class HubConnectionManager {
46

57
private _connection: HubConnection;
68
connected: boolean = false;
79
private connectedCallbacks: (() => void)[] = [];
810
started: boolean = false;
9-
error: Error|null = null;
11+
error: Error | null = null;
1012

1113
constructor(url: string) {
1214
this._connection = new HubConnectionBuilder().withUrl(url, { logMessageContent: true }).configureLogging(LogLevel.Trace).build();
@@ -16,6 +18,7 @@ export default class HubConnectionManager {
1618
connectedCallback();
1719
}
1820
});
21+
this._connection.on("serverchanged", this.fireServerChanged.bind(this));
1922
}
2023

2124
async addOnConnectedCallback(connectedCallback: () => void) {
@@ -39,10 +42,12 @@ export default class HubConnectionManager {
3942
await this._connection.start();
4043
this.connected = true;
4144

45+
this.fireServerChanged();
4246
for (const connectedCallback of this.connectedCallbacks) {
4347
connectedCallback();
4448
}
45-
} catch (e : any) {
49+
50+
} catch (e: any) {
4651
this.error = e;
4752
}
4853
}
@@ -52,7 +57,7 @@ export default class HubConnectionManager {
5257
await this._connection.stop();
5358
}
5459

55-
onConnectionClosed(e: Error|undefined) {
60+
onConnectionClosed(e: Error | undefined) {
5661
this.connected = false;
5762
this.started = false;
5863
this.error = e || null;
@@ -63,6 +68,31 @@ export default class HubConnectionManager {
6368
this._connection.on(eventName, handler);
6469
}
6570

71+
fireServerChanged(...args: any[]) {
72+
this.serverPromise = null;
6673

74+
for (let handler of this.onServerChangedHandlers) {
75+
handler.call(this);
76+
}
77+
}
78+
79+
onServerChanged(handler: (...args: any[]) => void) {
80+
this.onServerChangedHandlers.push(handler);
81+
}
82+
83+
private onServerChangedHandlers: ((...args: any[]) => void)[] = []
84+
85+
async getServer() {
86+
if (!this.serverPromise) {
87+
this.serverPromise = new ServerController().getServer();
88+
}
89+
90+
return this.serverPromise;
91+
}
92+
93+
serverPromise: Promise<Server> | null = null;
94+
95+
96+
97+
}
6798

68-
}

Rnwood.Smtp4dev/ClientApp/src/components/home/home.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
:connection="connection" />
4949
</pane>
5050
<pane class="hfillpanel" :size="100 - messageListPaneSize">
51-
<messageview class="fill" v-bind:message-summary="selectedMessage" />
51+
<messageview class="fill" :connection="connection" v-bind:message-summary="selectedMessage" />
5252
</pane>
5353
</splitpanes>
5454
</el-tab-pane>

Rnwood.Smtp4dev/ClientApp/src/components/messagehtmlvalidation.vue

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,22 @@
5757
5858
warnings: HtmlValidateMessage[] = [];
5959
60+
61+
@Prop({ default: null })
62+
connection: HubConnectionManager | null = null;
63+
64+
65+
@Watch("connection")
66+
onConnectionChanged() {
67+
if (this.connection) {
68+
this.connection.onServerChanged( async () => {
69+
await this.refresh();
70+
});
71+
72+
this.connection.addOnConnectedCallback(() => this.refresh());
73+
}
74+
}
75+
6076
@Watch("message")
6177
async onMessageChanged(value: Message | null, oldValue: Message | null) {
6278
@@ -87,8 +103,9 @@
87103
if (this.message != null && this.message.hasHtmlBody) {
88104
89105
this.html = await new MessagesController().getMessageHtml(this.message.id);
106+
const config = JSON.parse((await this.connection.getServer()).htmlValidateConfig);
90107
91-
const report = await new HtmlValidate().validateString(this.html, "messagebody");
108+
const report = await new HtmlValidate(config).validateString(this.html, "messagebody");
92109
for (const r of report.results) {
93110
newWarnings.push(...r.messages);
94111
}

Rnwood.Smtp4dev/ClientApp/src/components/messagelist.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@
356356
this.loading = !silent;
357357
this.error = null;
358358
359-
const server = await new ServerController().getServer()
359+
const server = await this.connection.getServer()
360360
this.isRelayAvailable = !!server.relaySmtpServer;
361361
362362
this.availableMailboxes = await new MailboxesController().getAll();
@@ -460,7 +460,7 @@
460460
this.connection.on("messageschanged", async () => {
461461
await this.refresh(true, true);
462462
});
463-
this.connection.on("serverchanged", async () => {
463+
this.connection.onServerChanged(async () => {
464464
await this.refresh(true, true);
465465
});
466466
this.connection.on("mailboxeschanged", async () => {

Rnwood.Smtp4dev/ClientApp/src/components/messageview.vue

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div class="messageview fill vfillpanel" v-loading.body="loading">
33
<el-alert v-if="error" type="error">
44
{{error.message}}
5-
<el-button v-on:click="loadMessage">Retry</el-button>
5+
<el-button v-on:click="refresh">Retry</el-button>
66
</el-alert>
77

88
<el-dialog v-model="replyDialogVisible" :title="replyAll ? 'Reply All' : 'Reply'" destroy-on-close append-to-body align-center width="80%">
@@ -100,7 +100,7 @@
100100
</template>
101101
<messageviewattachments :message="message" v-if="message && messageSummary.attachmentCount"></messageviewattachments>
102102

103-
<messageview-html v-if="message && message.hasHtmlBody && !message.hasPlainTextBody" :message="message" class="fill messagepreview"></messageview-html>
103+
<messageview-html v-if="message && message.hasHtmlBody && !message.hasPlainTextBody" :connection="connection" :message="message" class="fill messagepreview"></messageview-html>
104104
<messageview-plaintext v-if="message && !message.hasHtmlBody && message.hasPlainTextBody" :message="message" class="fill messageplaintext"></messageview-plaintext>
105105
<div v-if="message && !message.hasHtmlBody && !message.hasPlainTextBody">This MIME message has no HTML or plain text body.</div>
106106

@@ -137,7 +137,7 @@
137137
HTML Validation
138138
<el-tag v-if="analysisWarningCount.html" style="margin-left: 6px;" type="warning" size="small" effect="dark" round><el-icon><WarnTriangleFilled /></el-icon> {{analysisWarningCount.html ? analysisWarningCount.html : ''}}</el-tag>
139139
</template>
140-
<messagehtmlvalidation class="fill" :message="message" @warning-count-changed="n => this.analysisWarningCount.html=n"></messagehtmlvalidation>
140+
<messagehtmlvalidation class="fill" :connection="connection" :message="message" @warning-count-changed="n => this.analysisWarningCount.html=n"></messagehtmlvalidation>
141141
</el-tab-pane>
142142
</el-tabs>
143143
</el-tab-pane>
@@ -254,6 +254,9 @@
254254
})
255255
class MessageView extends Vue {
256256
257+
@Prop({ default: null })
258+
connection: HubConnectionManager | null = null;
259+
257260
@Prop({})
258261
messageSummary: MessageSummary | null = null;
259262
selectedTabId = "view";
@@ -262,6 +265,13 @@
262265
warnings: MessageWarning[] = [];
263266
analysisWarningCount = { clients: 0, html: 0 };
264267
268+
@Watch("connection")
269+
async onConnectionChanged() {
270+
if (this.connection) {
271+
this.isRelayAvailable = !!await (await this.connection?.getServer())?.relaySmtpServer;
272+
}
273+
}
274+
265275
get totalAnalysisWarningCount() { return Object.values(this.analysisWarningCount).reduce((a, c) => a + c) }
266276
267277
error: Error | null = null;
@@ -285,16 +295,17 @@
285295
value: MessageSummary | null,
286296
oldValue: MessageSummary | null
287297
) {
288-
await this.loadMessage();
298+
await this.refresh();
289299
}
290300
291-
async loadMessage() {
301+
async refresh() {
292302
this.error = null;
293303
this.loading = true;
294304
this.message = null;
295305
this.selectedPart = null;
296306
297307
try {
308+
298309
if (this.messageSummary != null) {
299310
this.message = await new MessagesController().getMessage(
300311
this.messageSummary.id
@@ -409,8 +420,7 @@
409420
}
410421
411422
async mounted() {
412-
await this.loadMessage();
413-
this.isRelayAvailable = !!await (await new ServerController().getServer()).relaySmtpServer;
423+
await this.refresh();
414424
}
415425
416426
async destroyed() { }

Rnwood.Smtp4dev/ClientApp/src/components/messageviewhtml.vue

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<el-alert v-if="error" type="error">
3535
{{error.message}}
3636

37-
<el-button v-on:click="loadMessage">Retry</el-button>
37+
<el-button v-on:click="refresh">Retry</el-button>
3838
</el-alert>
3939
<el-alert v-if="wasSanitized" type="warning">
4040
Message HTML was sanitized for display. <el-button type="danger" size="small" v-on:click="disableSanitization">Disable (DANGER!)</el-button>
@@ -70,6 +70,9 @@
7070
7171
@Component
7272
class MessageViewHtml extends Vue {
73+
@Prop({ default: null })
74+
connection: HubConnectionManager | null = null;
75+
7376
@Prop({ default: null })
7477
message: Message | null | undefined;
7578
html: string | null = null;
@@ -114,11 +117,12 @@
114117
error: Error | null = null;
115118
loading = false;
116119
120+
117121
@Watch("message")
118122
async onMessageChanged(value: Message | null, oldValue: Message | null) {
119123
120124
this.html = "";
121-
await this.loadMessage();
125+
await this.refresh();
122126
123127
}
124128
@@ -156,15 +160,20 @@
156160
doc.body.appendChild(baseElement);
157161
}
158162
159-
async loadMessage() {
163+
@Watch("connection")
164+
async onConnectionChanged() {
165+
if (this.connection) {
166+
this.enableSanitization = !(await this.connection.getServer()).disableMessageSanitisation;
167+
}
168+
}
169+
170+
async refresh() {
160171
161172
this.error = null;
162173
this.loading = true;
163174
this.html = null;
164175
this.wasSanitized = false;
165176
166-
this.enableSanitization = !(await new ServerController().getServer()).disableMessageSanitisation;
167-
168177
169178
try {
170179
if (this.message != null) {
@@ -179,7 +188,7 @@
179188
}
180189
181190
async created() {
182-
this.loadMessage();
191+
this.refresh();
183192
}
184193
185194
async destroyed() {

Rnwood.Smtp4dev/ClientApp/src/components/serverstatus.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
this.error = null;
3535
this.loading = !silent;
3636
37-
this.server = await new ServerController().getServer();
37+
this.server = await this.connection.getServer();
3838
} catch (e: any) {
3939
this.error = e;
4040
} finally {
@@ -63,7 +63,7 @@
6363
@Watch("connection")
6464
onConnectionChanged() {
6565
if (this.connection) {
66-
this.connection.on("serverchanged", async () => {
66+
this.connection.onServerChanged( async () => {
6767
await this.refresh();
6868
});
6969

0 commit comments

Comments
 (0)