diff --git a/server/frontend/package-lock.json b/server/frontend/package-lock.json
index 1a469ed8..5bf591f3 100644
--- a/server/frontend/package-lock.json
+++ b/server/frontend/package-lock.json
@@ -14,6 +14,7 @@
"handlebars": "^4.7.8",
"js-base64": "^3.7.7",
"lodash": "^4.17.21",
+ "mime": "^4.0.6",
"prismjs": "^1.29.0",
"sweetalert": "^2.1.2",
"vue": "^3.4.21",
@@ -8380,12 +8381,18 @@
"node": ">=8.6"
}
},
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "node_modules/mime": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.6.tgz",
+ "integrity": "sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==",
+ "funding": [
+ "https://github.com/sponsors/broofa"
+ ],
+ "bin": {
+ "mime": "bin/cli.js"
+ },
"engines": {
- "node": ">= 0.6"
+ "node": ">=16"
}
},
"node_modules/mime-types": {
@@ -8399,6 +8406,14 @@
"node": ">= 0.6"
}
},
+ "node_modules/mime-types/node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
diff --git a/server/frontend/package.json b/server/frontend/package.json
index 70358c42..e05d670f 100644
--- a/server/frontend/package.json
+++ b/server/frontend/package.json
@@ -19,6 +19,7 @@
"handlebars": "^4.7.8",
"js-base64": "^3.7.7",
"lodash": "^4.17.21",
+ "mime": "^4.0.6",
"prismjs": "^1.29.0",
"sweetalert": "^2.1.2",
"vue": "^3.4.21",
diff --git a/server/frontend/src/components/Bugs/Comments/PublicationForm.vue b/server/frontend/src/components/Bugs/Comments/PublicationForm.vue
index 30d41cdd..065124ad 100644
--- a/server/frontend/src/components/Bugs/Comments/PublicationForm.vue
+++ b/server/frontend/src/components/Bugs/Comments/PublicationForm.vue
@@ -124,8 +124,10 @@
:initial-not-attach-test="notAttachTest"
:entry="entry"
:template="template"
+ :file-extension="fileExtension"
+ :file-name="fileName"
@update-not-attach-test="notAttachTest = $event"
- @update-filename="entry.testcase = $event"
+ @update-filename="newFileName = $event"
@update-content="testCaseContent = $event"
/>
@@ -227,6 +229,7 @@
diff --git a/server/frontend/src/components/Bugs/PublicationForm.vue b/server/frontend/src/components/Bugs/PublicationForm.vue
index e44dc966..a5bcb1e0 100644
--- a/server/frontend/src/components/Bugs/PublicationForm.vue
+++ b/server/frontend/src/components/Bugs/PublicationForm.vue
@@ -521,12 +521,22 @@
>
+
+
+
+
@@ -545,8 +555,10 @@
:initial-not-attach-test="notAttachTest"
:entry="entry"
:template="template"
+ :file-extension="fileExtension"
+ :file-name="fileName"
@update-not-attach-test="notAttachTest = $event"
- @update-filename="entry.testcase = $event"
+ @update-filename="fileName = $event"
@update-content="testCaseContent = $event"
/>
@@ -693,6 +705,8 @@ import {
watch,
} from "vue";
import * as api from "../../api";
+
+import mime from "mime";
import * as bugzillaApi from "../../bugzilla_api";
import * as HandlebarsHelpers from "../../handlebars_helpers";
import { errorParser } from "../../helpers";
@@ -797,12 +811,49 @@ export default defineComponent({
fields: {},
server: null,
});
+ const fileExtension = ref(null);
+ const fileName = ref(null);
const formElement = ref(null);
const bugLink = computed(() => {
return `https://${provider.value.hostname}/${createdBugId.value}`;
});
+ const filenameWithExtension = computed(() => {
+ return `${fileName.value}.${fileExtension.value}`;
+ });
+
+ watch(() => {
+ if (entry.value) {
+ // extract file name
+ const splittedAttachmentFilename = template.value?.testcase_filename
+ ? template.value.testcase_filename
+ : entry.value.testcase.split("/");
+
+ const attachmentFilenameAndExtension =
+ splittedAttachmentFilename[
+ splittedAttachmentFilename?.length - 1
+ ].split(".");
+
+ fileName.value = attachmentFilenameAndExtension[0];
+ fileExtension.value = attachmentFilenameAndExtension[1];
+ }
+ });
+
+ const fileMimetype = computed(() => {
+ const mimeType = mime.getType(filenameWithExtension.value);
+
+ if (mimeType) {
+ return mimeType;
+ }
+
+ if (entry.value.testcase_isbinary) {
+ return "application/octet-stream";
+ }
+
+ return "text/plain";
+ });
+
const bugzillaToken = computed(() => {
return localStorage.getItem(
"provider-" + provider.value?.id + "-api-key",
@@ -860,7 +911,7 @@ export default defineComponent({
if (!template.value || !entry.value) return "";
try {
const compiled = Handlebars.compile(template.value.description);
- let rendered = compiled({
+ const renderedData = {
summary: summary.value,
shortsig: entry.value.shortSignature,
product: entry.value.product,
@@ -877,7 +928,15 @@ export default defineComponent({
? "(Crash data not available)"
: "For detailed crash information, see attachment.",
...metadataExtension(template.value.description),
- });
+ };
+
+ if (!notAttachTest.value) {
+ renderedData["testcase_attachment"] = filenameWithExtension.value;
+ } else {
+ delete renderedData["testcase_attachment"];
+ }
+
+ let rendered = compiled(renderedData);
// Remove the specified pathPrefix from traces and assertion
if (entryMetadata.value.pathprefix)
@@ -1071,6 +1130,7 @@ export default defineComponent({
const payload = {
...template.value,
+ testcase_filename: filenameWithExtension.value,
product: product.value,
component: component.value,
op_sys: opSys.value,
@@ -1135,11 +1195,9 @@ export default defineComponent({
data: entry.value.testcase_isbinary
? Base64.fromUint8Array(content)
: Base64.encode(content),
- file_name: entry.value.testcase,
+ file_name: filenameWithExtension.value,
summary: "Testcase",
- content_type: entry.value.testcase_isbinary
- ? "application/octet-stream"
- : "text/plain",
+ content_type: fileMimetype.value,
};
await bugzillaApi.createAttachment({
@@ -1285,6 +1343,10 @@ export default defineComponent({
goBack,
createExternalBug,
createOrUpdateBugzillaBugTemplate,
+ filenameWithExtension,
+ fileMimetype,
+ fileExtension,
+ fileName,
};
},
});
diff --git a/server/frontend/src/components/Bugs/TestCaseSection.vue b/server/frontend/src/components/Bugs/TestCaseSection.vue
index 417a583a..1904197e 100644
--- a/server/frontend/src/components/Bugs/TestCaseSection.vue
+++ b/server/frontend/src/components/Bugs/TestCaseSection.vue
@@ -27,6 +27,17 @@
type="text"
/>
+
+
+
+
+
@@ -72,20 +83,31 @@ export default defineComponent({
type: Object,
required: true,
},
+ fileExtension: {
+ type: String,
+ required: true,
+ },
+ fileName: {
+ type: String,
+ required: true,
+ },
},
- emits: ["update-not-attach-test", "update-filename", "update-content"],
-
+ emits: [
+ "update-not-attach-test",
+ "update-filename",
+ "update-content",
+ "update-attachment-extension",
+ ],
setup(props, { emit }) {
const notAttachTest = ref(false);
const filename = ref("");
+ const filenameExtension = ref("");
const content = ref("Content loading...");
onMounted(async () => {
notAttachTest.value = props.initialNotAttachTest;
- filename.value = props.template
- ? props.template.testcase_filename
- : props.entry.testcase.split(/[\\/]/).pop();
+ filename.value = props.fileName;
if (!props.entry.testcase_isbinary) {
content.value = await api.retrieveCrashTestCase(props.entry.id);
@@ -114,6 +136,7 @@ export default defineComponent({
notAttachTest,
filename,
content,
+ filenameExtension,
};
},
});