Skip to content

Commit

Permalink
feature: Allow toggle between HTML/plain text alternative body if it …
Browse files Browse the repository at this point in the history
…exists (implements #1079) (#1346)
  • Loading branch information
rnwood committed Mar 10, 2024
1 parent 46998bc commit a68ee4a
Show file tree
Hide file tree
Showing 8 changed files with 458 additions and 315 deletions.
10 changes: 9 additions & 1 deletion Rnwood.Smtp4dev/ApiModel/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public Message(DbModel.Message dbMessage)
{
MimeParseError = dbMessage.MimeParseError;
Headers = new List<Header>(0);
HasPlainTextBody = true;
}
else
{
Expand Down Expand Up @@ -72,6 +73,8 @@ public Message(DbModel.Message dbMessage)

Headers = MimeMessage.Headers.Select(h => new Header { Name = h.Field, Value = PunyCodeReplacer.DecodePunycode(h.Value) }).ToList();
Parts.Add(HandleMimeEntity(MimeMessage.Body));
HasHtmlBody = MimeMessage.HtmlBody != null;
HasPlainTextBody = MimeMessage.TextBody != null;
}
}

Expand Down Expand Up @@ -145,7 +148,8 @@ internal static FileStreamResult GetPartContent(Message result, string cid)
{
return new FileStreamResult(mimePart.Content.Open(), contentEntity.ContentType?.MimeType ?? "application/text")
{
FileDownloadName = mimePart.FileName
FileDownloadName = mimePart.FileName ??
((contentEntity.ContentId ?? "content") + (MimeTypes.TryGetExtension(mimePart.ContentType.MimeType, out string extn) ? extn : ""))
};
}
else
Expand All @@ -158,6 +162,10 @@ internal static FileStreamResult GetPartContent(Message result, string cid)
}
}

public bool HasHtmlBody { get; set; }

public bool HasPlainTextBody { get; set; }

internal static string GetPartContentAsText(Message result, string id)
{
var contentEntity = GetPart(result, id);
Expand Down
6 changes: 6 additions & 0 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export default class Message {
mimeParseError: string,
relayError: string,
secureConnection: boolean,
hasHtmlBody: boolean,
hasPlainTextBody: boolean
) {
this.id = id;
this.from = from;
Expand All @@ -29,6 +31,8 @@ export default class Message {
this.mimeParseError = mimeParseError;
this.relayError = relayError;
this.secureConnection = secureConnection;
this.hasHtmlBody = hasHtmlBody;
this.hasPlainTextBody = hasPlainTextBody;
}

id: string;
Expand All @@ -43,4 +47,6 @@ export default class Message {
mimeParseError: string;
relayError: string;
secureConnection: boolean;
hasHtmlBody: boolean;
hasPlainTextBody: boolean;
}
10 changes: 10 additions & 0 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/MessagesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ export default class MessagesController {

return (await axios.get(this.getMessageHtml_url(id), null || undefined)).data as string;
}

// get: api/Messages/${encodeURIComponent(id)}/plaintext
public getMessagePlainText_url(id: string): string {
return `${this.apiBaseUrl}/${encodeURIComponent(id)}/plaintext`;
}

public async getMessagePlainText(id: string): Promise<string> {

return (await axios.get(this.getMessagePlainText_url(id), null || undefined)).data as string;
}

// delete: api/Messages/${encodeURIComponent(id)}
public delete_url(id: string): string {
Expand Down
151 changes: 82 additions & 69 deletions Rnwood.Smtp4dev/ClientApp/src/components/messagepartsource.vue
Original file line number Diff line number Diff line change
@@ -1,90 +1,103 @@
<template>
<div class="hfillpanel" v-loading="loading">
<el-alert v-if="error" type="error">
{{error.message}}
<div class="hfillpanel" v-loading="loading">
<el-alert v-if="error" type="error">
{{ error.message }}

<el-button v-on:click="loadMessage">Retry</el-button>
</el-alert>
<el-button v-on:click="loadMessage">Retry</el-button>
</el-alert>

<div class="toolbar"><el-button size="small" icon="el-icon-document" @click="download">Open</el-button></div>
<div v-show="source" class="vfillpanel fill">
<textview :text="source" class="fill"></textview>
</div>
<div class="toolbar">
<el-button size="small" icon="el-icon-document" @click="viewSource">Open</el-button>

<el-button size="small" icon="el-icon-download" @click="download" v-show="downloadurl">Download</el-button>
</div>
<div v-show="source" class="vfillpanel fill">
<textview :text="source" class="fill"></textview>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Watch } from 'vue-property-decorator'
import Vue from 'vue'
import MessagesController from "../ApiClient/MessagesController";
import MessageEntitySummary from "../ApiClient/MessageEntitySummary";
import TextView from "@/components/textview.vue";
@Component({
components: {
textview: TextView
}
})
import {Component, Prop, Watch} from 'vue-property-decorator'
import Vue from 'vue'
import MessagesController from "../ApiClient/MessagesController";
import MessageEntitySummary from "../ApiClient/MessageEntitySummary";
import TextView from "@/components/textview.vue";
@Component({
components: {
textview: TextView
}
})
export default class MessagePartSource extends Vue {
constructor() {
super();
}
constructor() {
super();
}
@Prop()
messageEntitySummary: MessageEntitySummary | null = null;
@Prop()
messageEntitySummary: MessageEntitySummary | null = null;
source: string | null = null;
sourceurl: string | null = null;
error: Error | null = null;
loading = false;
source: string | null = null;
sourceurl: string | null = null;
downloadurl: string | null = null;
error: Error | null = null;
loading = false;
@Prop({ default: "source" } )
type!: "source" | "raw";
@Prop({default: "source"})
type!: "source" | "raw";
@Watch("messageEntitySummary")
async onMessageEntitySummaryChanged(value: MessageEntitySummary, oldValue: MessageEntitySummary) {
@Watch("messageEntitySummary")
async onMessageEntitySummaryChanged(value: MessageEntitySummary, oldValue: MessageEntitySummary) {
await this.loadMessage();
await this.loadMessage();
}
}
download() {
if (this.sourceurl) {
window.open(this.sourceurl);
}
}
download() {
if (this.downloadurl) {
window.open(this.downloadurl);
}
}
viewSource() {
if (this.sourceurl) {
window.open(this.sourceurl);
}
}
async loadMessage() {
async loadMessage() {
this.error = null;
this.loading = true;
this.source = null;
this.sourceurl = null;
this.error = null;
this.loading = true;
this.source = null;
this.sourceurl = null;
this.downloadurl = null;
try {
if (this.messageEntitySummary != null) {
if (this.type === "raw") {
this.sourceurl = new MessagesController().getPartSourceRaw_url(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
this.source = await new MessagesController().getPartSourceRaw(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
try {
if (this.messageEntitySummary != null) {
if (this.type === "raw") {
this.sourceurl = new MessagesController().getPartSourceRaw_url(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
this.source = await new MessagesController().getPartSourceRaw(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
} else {
this.sourceurl = new MessagesController().getPartSource_url(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
this.source = await new MessagesController().getPartSource(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
} else {
}
}
} catch (e: any) {
this.error = e;
} finally {
this.loading = false;
}
}
async created() {
this.loadMessage();
}
this.sourceurl = new MessagesController().getPartSource_url(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
this.downloadurl = new MessagesController().getPartContent_url(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
this.source = await new MessagesController().getPartSource(this.messageEntitySummary.messageId, this.messageEntitySummary.id);
async destroyed() {
}
}
}
}
} catch (e: any) {
this.error = e;
} finally {
this.loading = false;
}
}
async created() {
this.loadMessage();
}
async destroyed() {
}
}
</script>

0 comments on commit a68ee4a

Please sign in to comment.