Skip to content

Commit

Permalink
Merge pull request #590 from nordeck/nic/feat/extend-the-widget-to-in…
Browse files Browse the repository at this point in the history
…clud-MSC-4039-upload-file

Extend the widgetApi with the new upload function in MSC 4039
  • Loading branch information
maheichyk authored Jan 17, 2024
2 parents 3a2ba2a + 3d5a79f commit 15f4522
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changeset/late-humans-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@matrix-widget-toolkit/testing': minor
'@matrix-widget-toolkit/api': minor
---

Implement upload files into media repository.
6 changes: 6 additions & 0 deletions packages/api/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
```ts

import { Capability } from 'matrix-widget-api';
import { IGetMediaConfigActionFromWidgetResponseData } from 'matrix-widget-api';
import { IModalWidgetCreateData } from 'matrix-widget-api';
import { IModalWidgetOpenRequestDataButton } from 'matrix-widget-api';
import { IModalWidgetReturnData } from 'matrix-widget-api';
import { IOpenIDCredentials } from 'matrix-widget-api';
import { IRoomEvent } from 'matrix-widget-api';
import { IUploadFileActionFromWidgetResponseData } from 'matrix-widget-api';
import { IWidget } from 'matrix-widget-api';
import { IWidgetApiRequest } from 'matrix-widget-api';
import { IWidgetApiRequestData } from 'matrix-widget-api';
Expand Down Expand Up @@ -267,6 +269,8 @@ export type WidgetApi = {
avatarUrl?: string;
}>;
}>;
getMediaConfig(): Promise<IGetMediaConfigActionFromWidgetResponseData>;
uploadFile(file: XMLHttpRequestBodyInit): Promise<IUploadFileActionFromWidgetResponseData>;
};

// @public
Expand All @@ -277,6 +281,7 @@ export class WidgetApiImpl implements WidgetApi {
widgetParameters: WidgetParameters, { capabilities, supportStandalone }?: WidgetApiOptions);
closeModal<T extends IModalWidgetReturnData>(data?: T): Promise<void>;
static create({ capabilities, supportStandalone, }?: WidgetApiOptions): Promise<WidgetApi>;
getMediaConfig(): Promise<IGetMediaConfigActionFromWidgetResponseData>;
getWidgetConfig<T extends IWidgetApiRequestData>(): Readonly<WidgetConfig<T> | undefined>;
hasCapabilities(capabilities: Array<WidgetEventCapability | Capability>): boolean;
hasInitialCapabilities(): boolean;
Expand Down Expand Up @@ -343,6 +348,7 @@ export class WidgetApiImpl implements WidgetApi {
};
}): Promise<void>;
setModalButtonEnabled(buttonId: ModalButtonID, isEnabled: boolean): Promise<void>;
uploadFile(file: XMLHttpRequestBodyInit): Promise<IUploadFileActionFromWidgetResponseData>;
readonly widgetId: string;
readonly widgetParameters: WidgetParameters;
}
Expand Down
47 changes: 47 additions & 0 deletions packages/api/src/api/WidgetApiImpl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ describe('WidgetApiImpl', () => {
getTurnServers: jest.fn(),
readEventRelations: jest.fn(),
searchUserDirectory: jest.fn(),
getMediaConfig: jest.fn(),
uploadFile: jest.fn(),
transport: {
reply: jest.fn(),
},
Expand Down Expand Up @@ -2181,6 +2183,51 @@ describe('WidgetApiImpl', () => {
);
});
});

describe('getMediaConfig', () => {
it('should get media config', async () => {
matrixWidgetApi.getMediaConfig.mockResolvedValue(
Promise.resolve({
'm.upload.size': 5444,
}),
);

await expect(widgetApi.getMediaConfig()).resolves.toEqual({
'm.upload.size': 5444,
});
expect(matrixWidgetApi.getMediaConfig).toBeCalledWith();
});
});

describe('uploadFile', () => {
it('should upload a file', async () => {
matrixWidgetApi.uploadFile.mockResolvedValue(
Promise.resolve({
content_uri: 'msx//:example',
}),
);

const file = new File(['file content'], 'test-image.png', {
type: 'image/png',
});

await expect(widgetApi.uploadFile(file)).resolves.toEqual({
content_uri: 'msx//:example',
});
expect(matrixWidgetApi.uploadFile).toBeCalled();
});

it('should throw error', async () => {
matrixWidgetApi.uploadFile.mockRejectedValue(
new Error('can not upload the file'),
);

await expect(widgetApi.uploadFile('file')).rejects.toThrowError(
'can not upload the file',
);
expect(matrixWidgetApi.uploadFile).toBeCalledWith('file');
});
});
});

function mockRoomEvent<T>({
Expand Down
14 changes: 14 additions & 0 deletions packages/api/src/api/WidgetApiImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

import {
Capability,
IGetMediaConfigActionFromWidgetResponseData,
IModalWidgetCreateData,
IModalWidgetOpenRequestDataButton,
IModalWidgetReturnData,
INotifyCapabilitiesActionRequest,
IOpenIDCredentials,
IRoomEvent,
IUploadFileActionFromWidgetResponseData,
IWidgetApiRequest,
IWidgetApiRequestData,
MatrixCapabilities,
Expand Down Expand Up @@ -784,4 +786,16 @@ export class WidgetApiImpl implements WidgetApi {
})),
};
}

/** {@inheritdoc WidgetApi.getMediaConfig} */
async getMediaConfig(): Promise<IGetMediaConfigActionFromWidgetResponseData> {
return await this.matrixWidgetApi.getMediaConfig();
}

/** {@inheritdoc WidgetApi.uploadFile} */
async uploadFile(
file: XMLHttpRequestBodyInit,
): Promise<IUploadFileActionFromWidgetResponseData> {
return await this.matrixWidgetApi.uploadFile(file);
}
}
18 changes: 18 additions & 0 deletions packages/api/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@

import {
Capability,
IGetMediaConfigActionFromWidgetResponseData,
IModalWidgetCreateData,
IModalWidgetOpenRequestDataButton,
IModalWidgetReturnData,
IOpenIDCredentials,
IRoomEvent,
IUploadFileActionFromWidgetResponseData,
IWidget,
IWidgetApiRequest,
IWidgetApiRequestData,
Expand Down Expand Up @@ -539,5 +541,21 @@ export type WidgetApi = {
}>;
}>;

/**
* Get the config for the media repository.
* @returns Promise which resolves with an object containing the config.
*/
getMediaConfig(): Promise<IGetMediaConfigActionFromWidgetResponseData>;

/**
* Upload a file to the media repository on the homeserver.
* @param file - The object to upload. Something that can be sent to
* XMLHttpRequest.send (typically a File).
* @returns Resolves to the location of the uploaded file.
*/
uploadFile(
file: XMLHttpRequestBodyInit,
): Promise<IUploadFileActionFromWidgetResponseData>;

// TODO: sendSticker, setAlwaysOnScreen
};
14 changes: 14 additions & 0 deletions packages/testing/src/api/mockWidgetApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -957,3 +957,17 @@ describe('searchUserDirectory', () => {
});
});
});

describe('getMediaConfig', () => {
it('should return empty media config', async () => {
await expect(widgetApi.getMediaConfig()).resolves.toEqual({});
});
});

describe('uploadFile', () => {
it('should return empty response', async () => {
await expect(widgetApi.uploadFile('data')).resolves.toEqual({
content_uri: 'mxc://...',
});
});
});
4 changes: 4 additions & 0 deletions packages/testing/src/api/mockWidgetApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ export function mockWidgetApi(opts?: {
),
),
searchUserDirectory: jest.fn().mockResolvedValue({ results: [] }),
getMediaConfig: jest.fn().mockResolvedValue({}),
uploadFile: jest.fn().mockResolvedValue({
content_uri: 'mxc://...',
}),
};

widgetApi.receiveRoomEvents.mockImplementation(async (type, options) => {
Expand Down

0 comments on commit 15f4522

Please sign in to comment.