Expose user avatar URL field in the UI (#27)

* wip

* some fixes

* update readme

* update readme

* Add option to change/erase any user's avatar

* Fix README

* Remove mutationMode from Edit

* remove log

* update readme
This commit is contained in:
Aine
2024-09-17 23:06:12 +03:00
committed by GitHub
parent d5113aad72
commit 24cf0a60bf
13 changed files with 138 additions and 78 deletions

View File

@@ -1,16 +1,26 @@
import { stringify } from "query-string";
import { DataProvider, DeleteParams, HttpError, Identifier, Options, RaRecord, fetchUtils } from "react-admin";
import {
DataProvider,
DeleteParams,
HttpError,
Identifier,
Options,
RaRecord,
UpdateParams,
fetchUtils,
withLifecycleCallbacks,
} from "react-admin";
import storage from "../storage";
import { returnMXID } from "./synapse.ts"
import { returnMXID } from "./synapse";
import { MatrixError, displayError } from "../components/error";
// Adds the access token to all requests
const jsonClient = async (url: string, options: Options = {}) => {
const token = storage.getItem("access_token");
console.log("httpClient " + url);
if (token != null) {
if (token !== null) {
options.user = {
authenticated: true,
token: `Bearer ${token}`,
@@ -23,7 +33,9 @@ const jsonClient = async (url: string, options: Options = {}) => {
const error = err as HttpError;
const errorStatus = error.status;
const errorBody = error.body as MatrixError;
const errMsg = !!errorBody?.errcode ? displayError(errorBody.errcode, errorStatus, errorBody.error) : displayError("M_INVALID", errorStatus, error.message);
const errMsg = !!errorBody?.errcode
? displayError(errorBody.errcode, errorStatus, errorBody.error)
: displayError("M_INVALID", errorStatus, error.message);
return Promise.reject(new HttpError(errMsg, errorStatus, errorBody));
}
@@ -226,8 +238,19 @@ export interface DeleteMediaResult {
total: number;
}
export interface UploadMediaParams {
file: File;
filename: string;
content_type: string;
}
export interface UploadMediaResult {
content_uri: string;
}
export interface SynapseDataProvider extends DataProvider {
deleteMedia: (params: DeleteMediaParams) => Promise<DeleteMediaResult>;
uploadMedia: (params: UploadMediaParams) => Promise<UploadMediaResult>;
}
const resourceMap = {
@@ -500,7 +523,7 @@ function getSearchOrder(order: "ASC" | "DESC") {
}
}
const dataProvider: SynapseDataProvider = {
const baseDataProvider: SynapseDataProvider = {
getList: async (resource, params) => {
console.log("getList " + resource);
const { user_id, name, guests, deactivated, locked, search_term, destination, valid } = params.filter;
@@ -742,6 +765,46 @@ const dataProvider: SynapseDataProvider = {
const { json } = await jsonClient(endpoint_url, { method: "POST" });
return json as DeleteMediaResult;
},
uploadMedia: async ({ file, filename, content_type }: UploadMediaParams) => {
const base_url = storage.getItem("base_url");
const uploadMediaURL = `${base_url}/_matrix/media/v3/upload`;
const { json } = await jsonClient(`${uploadMediaURL}?filename=${filename}`, {
method: "POST",
body: file,
headers: new Headers({
Accept: "application/json",
"Content-Type": content_type,
}) as Headers,
});
return json as UploadMediaResult;
},
};
const dataProvider = withLifecycleCallbacks(baseDataProvider, [
{
resource: "users",
beforeUpdate: async (params: UpdateParams<any>, dataProvider: DataProvider) => {
const avatarFile = params.data.avatar_file?.rawFile;
const avatarErase = params.data.avatar_erase;
if (avatarErase) {
params.data.avatar_url = "";
return params;
}
if (avatarFile instanceof File) {
const reponse = await dataProvider.uploadMedia({
file: avatarFile,
filename: params.data.avatar_file.title,
content_type: params.data.avatar_file.rawFile.type,
});
params.data.avatar_url = reponse.content_uri;
}
return params;
},
},
]);
export default dataProvider;