Implement exporting from a specific start date and fix few bugs
This commit is contained in:
parent
80e5d4cd77
commit
a1b614f2b3
6 changed files with 52 additions and 41 deletions
|
@ -432,7 +432,7 @@ export default class MImageBody extends React.Component {
|
||||||
|
|
||||||
// Overidden by MStickerBody
|
// Overidden by MStickerBody
|
||||||
wrapImage(contentUrl, children) {
|
wrapImage(contentUrl, children) {
|
||||||
return <a href={contentUrl} onClick={this.onClick}>
|
return <a href={contentUrl} target={this.props.forExport ? "__blank" : undefined} onClick={this.onClick}>
|
||||||
{children}
|
{children}
|
||||||
</a>;
|
</a>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,12 @@ export default class RoomHeader extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
_exportConversationalHistory = async () => {
|
_exportConversationalHistory = async () => {
|
||||||
await exportConversationalHistory(this.props.room, exportFormats.HTML, exportTypes.LAST_N_MESSAGES, 100);
|
await exportConversationalHistory(
|
||||||
|
this.props.room,
|
||||||
|
exportFormats.HTML,
|
||||||
|
exportTypes.START_DATE,
|
||||||
|
{ startDate: parseInt(new Date("2021.05.20").getTime().toFixed(0)) },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,37 +1,15 @@
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
import { TimelineWindow } from "matrix-js-sdk/src/timeline-window";
|
|
||||||
import { arrayFastClone } from "../arrays";
|
|
||||||
import { exportTypes } from "./exportUtils";
|
import { exportTypes } from "./exportUtils";
|
||||||
|
import { exportOptions } from "./exportUtils";
|
||||||
|
|
||||||
export default abstract class Exporter {
|
export default abstract class Exporter {
|
||||||
protected constructor(protected room: Room, protected exportType: exportTypes, protected numberOfEvents?: number) {}
|
protected constructor(
|
||||||
|
protected room: Room,
|
||||||
protected getTimelineConversation = (): MatrixEvent[] => {
|
protected exportType: exportTypes,
|
||||||
if (!this.room) return;
|
protected exportOptions?: exportOptions,
|
||||||
|
) {}
|
||||||
const cli = MatrixClientPeg.get();
|
|
||||||
|
|
||||||
const timelineSet = this.room.getUnfilteredTimelineSet();
|
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(
|
|
||||||
cli, timelineSet,
|
|
||||||
{windowLimit: Number.MAX_VALUE});
|
|
||||||
|
|
||||||
timelineWindow.load(null, 30);
|
|
||||||
|
|
||||||
const events: MatrixEvent[] = timelineWindow.getEvents();
|
|
||||||
|
|
||||||
// Clone and reverse the events so that we preserve the order
|
|
||||||
arrayFastClone(events)
|
|
||||||
.reverse()
|
|
||||||
.forEach(async (event) => {
|
|
||||||
await cli.decryptEventIfNeeded(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
return events;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected setEventMetadata = (event: MatrixEvent) => {
|
protected setEventMetadata = (event: MatrixEvent) => {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
@ -47,12 +25,27 @@ export default abstract class Exporter {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getLimit = () => {
|
||||||
|
let limit: number;
|
||||||
|
switch (this.exportType) {
|
||||||
|
case exportTypes.LAST_N_MESSAGES:
|
||||||
|
limit = this.exportOptions.numberOfMessages;
|
||||||
|
break;
|
||||||
|
case exportTypes.TIMELINE:
|
||||||
|
limit = 40;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
limit = Number.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
|
||||||
protected getRequiredEvents = async () : Promise<MatrixEvent[]> => {
|
protected getRequiredEvents = async () : Promise<MatrixEvent[]> => {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const eventMapper = client.getEventMapper();
|
const eventMapper = client.getEventMapper();
|
||||||
|
|
||||||
let prevToken: string|null = null;
|
let prevToken: string|null = null;
|
||||||
let limit = this.numberOfEvents || Number.MAX_VALUE;
|
let limit = this.getLimit();
|
||||||
let events: MatrixEvent[] = [];
|
let events: MatrixEvent[] = [];
|
||||||
|
|
||||||
while (limit) {
|
while (limit) {
|
||||||
|
@ -65,7 +58,14 @@ export default abstract class Exporter {
|
||||||
|
|
||||||
const matrixEvents: MatrixEvent[] = res.chunk.map(eventMapper);
|
const matrixEvents: MatrixEvent[] = res.chunk.map(eventMapper);
|
||||||
|
|
||||||
matrixEvents.forEach(mxEv => events.push(mxEv));
|
for (const mxEv of matrixEvents) {
|
||||||
|
if (this.exportOptions.startDate && mxEv.getTs() < this.exportOptions.startDate) {
|
||||||
|
// Once the last message received is older than the start date, we break out of both the loops
|
||||||
|
limit = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.push(mxEv);
|
||||||
|
}
|
||||||
|
|
||||||
prevToken = res.end;
|
prevToken = res.end;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import exportCSS from "./exportCSS";
|
||||||
import exportJS from "./exportJS";
|
import exportJS from "./exportJS";
|
||||||
import exportIcons from "./exportIcons";
|
import exportIcons from "./exportIcons";
|
||||||
import { exportTypes } from "./exportUtils";
|
import { exportTypes } from "./exportUtils";
|
||||||
|
import { exportOptions } from "./exportUtils";
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import { MatrixClient } from "matrix-js-sdk";
|
import { MatrixClient } from "matrix-js-sdk";
|
||||||
|
|
||||||
|
@ -32,8 +33,8 @@ export default class HTMLExporter extends Exporter {
|
||||||
protected permalinkCreator: RoomPermalinkCreator;
|
protected permalinkCreator: RoomPermalinkCreator;
|
||||||
protected matrixClient: MatrixClient;
|
protected matrixClient: MatrixClient;
|
||||||
|
|
||||||
constructor(room: Room, exportType: exportTypes, numberOfEvents?: number) {
|
constructor(room: Room, exportType: exportTypes, exportOptions: exportOptions) {
|
||||||
super(room, exportType, numberOfEvents);
|
super(room, exportType, exportOptions);
|
||||||
this.zip = new JSZip();
|
this.zip = new JSZip();
|
||||||
this.avatars = new Map<string, boolean>();
|
this.avatars = new Map<string, boolean>();
|
||||||
this.matrixClient = MatrixClientPeg.get();
|
this.matrixClient = MatrixClientPeg.get();
|
||||||
|
@ -282,7 +283,7 @@ export default class HTMLExporter extends Exporter {
|
||||||
protected async getEventTile(mxEv: MatrixEvent, continuation: boolean, filePath?: string) {
|
protected async getEventTile(mxEv: MatrixEvent, continuation: boolean, filePath?: string) {
|
||||||
const hasAvatar = this.hasAvatar(mxEv);
|
const hasAvatar = this.hasAvatar(mxEv);
|
||||||
if (hasAvatar) await this.saveAvatarIfNeeded(mxEv);
|
if (hasAvatar) await this.saveAvatarIfNeeded(mxEv);
|
||||||
const eventTile = <li className="mx_Export_EventWrapper" id={mxEv.getId()}>
|
const eventTile = <div className="mx_Export_EventWrapper" id={mxEv.getId()}>
|
||||||
<MatrixClientContext.Provider value = {this.matrixClient}>
|
<MatrixClientContext.Provider value = {this.matrixClient}>
|
||||||
<EventTile
|
<EventTile
|
||||||
mxEvent={mxEv}
|
mxEvent={mxEv}
|
||||||
|
@ -307,11 +308,11 @@ export default class HTMLExporter extends Exporter {
|
||||||
showReadReceipts={false}
|
showReadReceipts={false}
|
||||||
/>
|
/>
|
||||||
</MatrixClientContext.Provider>
|
</MatrixClientContext.Provider>
|
||||||
</li>
|
</div>
|
||||||
let eventTileMarkup = renderToStaticMarkup(eventTile);
|
let eventTileMarkup = renderToStaticMarkup(eventTile);
|
||||||
if (filePath) eventTileMarkup = eventTileMarkup.replace(/(src=|href=)"forExport"/, `$1"${filePath}"`);
|
if (filePath) eventTileMarkup = eventTileMarkup.replace(/(src=|href=)"forExport"/g, `$1"${filePath}"`);
|
||||||
if (hasAvatar) {
|
if (hasAvatar) {
|
||||||
eventTileMarkup = eventTileMarkup.replace(/src="AvatarForExport"/, `src="users/${mxEv.sender.userId}"`);
|
eventTileMarkup = eventTileMarkup.replace(/src="AvatarForExport"/g, `src="users/${mxEv.sender.userId}"`);
|
||||||
}
|
}
|
||||||
return eventTileMarkup;
|
return eventTileMarkup;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19537,7 +19537,7 @@ a.mx_reply_anchor:hover{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
li.mx_Export_EventWrapper:target {
|
.mx_Export_EventWrapper:target {
|
||||||
background: white;
|
background: white;
|
||||||
animation: mx_event_highlight_animation 2s linear;
|
animation: mx_event_highlight_animation 2s linear;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,15 +14,20 @@ export enum exportTypes {
|
||||||
LAST_N_MESSAGES = "LAST_N_MESSAGES",
|
LAST_N_MESSAGES = "LAST_N_MESSAGES",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface exportOptions {
|
||||||
|
startDate?: number;
|
||||||
|
numberOfMessages?: number;
|
||||||
|
}
|
||||||
|
|
||||||
const exportConversationalHistory = async (
|
const exportConversationalHistory = async (
|
||||||
room: Room,
|
room: Room,
|
||||||
format: string,
|
format: string,
|
||||||
exportType: exportTypes,
|
exportType: exportTypes,
|
||||||
exportTypeMetadata?: number,
|
exportOptions?: exportOptions,
|
||||||
) => {
|
) => {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case exportFormats.HTML:
|
case exportFormats.HTML:
|
||||||
await new HTMLExporter(room, exportType, exportTypeMetadata).export();
|
await new HTMLExporter(room, exportType, exportOptions).export();
|
||||||
break;
|
break;
|
||||||
case exportFormats.JSON:
|
case exportFormats.JSON:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue