Fix issue with duplicate images (#30073)
* ensure export file paths are unique * add unit test for filepath uniqueness. fix createMessagesRequest mock. * add return types
This commit is contained in:
@@ -25,8 +25,17 @@ type BlobFile = {
|
|||||||
blob: Blob;
|
blob: Blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type FileDetails = {
|
||||||
|
directory: string;
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
extension: string;
|
||||||
|
count?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export default abstract class Exporter {
|
export default abstract class Exporter {
|
||||||
protected files: BlobFile[] = [];
|
protected files: BlobFile[] = [];
|
||||||
|
protected fileNames: Map<string, number> = new Map();
|
||||||
protected cancelled = false;
|
protected cancelled = false;
|
||||||
|
|
||||||
protected constructor(
|
protected constructor(
|
||||||
@@ -241,6 +250,19 @@ export default abstract class Exporter {
|
|||||||
return [fileName, "." + ext];
|
return [fileName, "." + ext];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected makeUniqueFilePath(details: FileDetails): string {
|
||||||
|
const makePath = ({ directory, name, date, extension, count = 0 }: FileDetails): string =>
|
||||||
|
`${directory}/${name}-${date}${count > 0 ? ` (${count})` : ""}${extension}`;
|
||||||
|
const defaultPath = makePath(details);
|
||||||
|
const count = this.fileNames.get(defaultPath) || 0;
|
||||||
|
this.fileNames.set(defaultPath, count + 1);
|
||||||
|
if (count > 0) {
|
||||||
|
return makePath({ ...details, count });
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultPath;
|
||||||
|
}
|
||||||
|
|
||||||
public getFilePath(event: MatrixEvent): string {
|
public getFilePath(event: MatrixEvent): string {
|
||||||
const mediaType = event.getContent().msgtype;
|
const mediaType = event.getContent().msgtype;
|
||||||
let fileDirectory: string;
|
let fileDirectory: string;
|
||||||
@@ -263,7 +285,12 @@ export default abstract class Exporter {
|
|||||||
if (event.getType() === "m.sticker") fileExt = ".png";
|
if (event.getType() === "m.sticker") fileExt = ".png";
|
||||||
if (isVoiceMessage(event)) fileExt = ".ogg";
|
if (isVoiceMessage(event)) fileExt = ".ogg";
|
||||||
|
|
||||||
return fileDirectory + "/" + fileName + "-" + fileDate + fileExt;
|
return this.makeUniqueFilePath({
|
||||||
|
directory: fileDirectory,
|
||||||
|
name: fileName,
|
||||||
|
date: fileDate,
|
||||||
|
extension: fileExt,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected isReply(event: MatrixEvent): boolean {
|
protected isReply(event: MatrixEvent): boolean {
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ describe("HTMLExport", () => {
|
|||||||
const chunk = events.slice(from, limit);
|
const chunk = events.slice(from, limit);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
chunk,
|
chunk,
|
||||||
from: from.toString(),
|
start: from.toString(),
|
||||||
to: (from + limit).toString(),
|
end: (from + limit).toString(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -419,6 +419,36 @@ describe("HTMLExport", () => {
|
|||||||
expect(text).toBe(attachmentBody);
|
expect(text).toBe(attachmentBody);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle attachments with identical names and dates", async () => {
|
||||||
|
mockMessages(EVENT_MESSAGE, EVENT_ATTACHMENT, EVENT_ATTACHMENT);
|
||||||
|
|
||||||
|
const exporter = new HTMLExporter(
|
||||||
|
room,
|
||||||
|
ExportType.LastNMessages,
|
||||||
|
{
|
||||||
|
attachmentsIncluded: true,
|
||||||
|
maxSize: 1_024 * 1_024,
|
||||||
|
numberOfMessages: 40,
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
|
||||||
|
await exporter.export();
|
||||||
|
|
||||||
|
const files = getFiles(exporter);
|
||||||
|
|
||||||
|
// There should be 5 files: 2 attachments, 1 html file, 1 css file and 1 js file
|
||||||
|
expect(Object.keys(files)).toHaveLength(5);
|
||||||
|
|
||||||
|
// Ensure that the attachment is present
|
||||||
|
const file = files[Object.keys(files).find((k) => k.endsWith(".txt"))!];
|
||||||
|
expect(file).not.toBeUndefined();
|
||||||
|
|
||||||
|
// Ensure that the duplicate attachment has been uniquely named
|
||||||
|
const duplicateFile = files[Object.keys(files).find((k) => k.endsWith("(1).txt"))!];
|
||||||
|
expect(duplicateFile).not.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it("should handle when attachment cannot be fetched", async () => {
|
it("should handle when attachment cannot be fetched", async () => {
|
||||||
mockMessages(EVENT_MESSAGE, EVENT_ATTACHMENT_MALFORMED, EVENT_ATTACHMENT);
|
mockMessages(EVENT_MESSAGE, EVENT_ATTACHMENT_MALFORMED, EVENT_ATTACHMENT);
|
||||||
const attachmentBody = "Lorem ipsum dolor sit amet";
|
const attachmentBody = "Lorem ipsum dolor sit amet";
|
||||||
|
|||||||
Reference in New Issue
Block a user