Fix media upload

This commit is contained in:
marcin mikołajczak
2024-05-12 19:29:04 +02:00
parent cb7976bd3d
commit d6ee14cb99
12 changed files with 56 additions and 79 deletions

View File

@@ -32,37 +32,18 @@ const updateMedia = (mediaId: string, params: Record<string, any>) =>
});
};
const uploadMediaV1 = (body: FormData, onUploadProgress = noOp) =>
(dispatch: any, getState: () => RootState) =>
api(getState)('/api/v1/media', {
method: 'POST',
body,
headers: { 'Content-Type': '' },
// }, {
// onUploadProgress: onUploadProgress,
});
const uploadMediaV2 = (body: FormData, onUploadProgress = noOp) =>
(dispatch: any, getState: () => RootState) =>
api(getState)('/api/v2/media', {
method: 'POST',
body,
headers: { 'Content-Type': '' },
// }, {
// onUploadProgress: onUploadProgress,
});
const uploadMedia = (data: FormData, onUploadProgress = noOp) =>
const uploadMedia = (body: FormData, onUploadProgress: (e: ProgressEvent) => void = noOp) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const instance = state.instance;
const features = getFeatures(instance);
if (features.mediaV2) {
return dispatch(uploadMediaV2(data, onUploadProgress));
} else {
return dispatch(uploadMediaV1(data, onUploadProgress));
}
return api(getState)(features.mediaV2 ? '/api/v2/media' : '/api/v1/media', {
method: 'POST',
body,
headers: { 'Content-Type': '' },
onUploadProgress,
});
};
const uploadFile = (
@@ -70,7 +51,7 @@ const uploadFile = (
intl: IntlShape,
onSuccess: (data: APIEntity) => void = () => {},
onFail: (error: unknown) => void = () => {},
onProgress: (loaded: number) => void = () => {},
onProgress: (e: ProgressEvent) => void = () => {},
changeTotal: (value: number) => void = () => {},
) =>
async (dispatch: AppDispatch, getState: () => RootState) => {
@@ -135,8 +116,6 @@ const uploadFile = (
export {
fetchMedia,
updateMedia,
uploadMediaV1,
uploadMediaV2,
uploadMedia,
uploadFile,
};

View File

@@ -1,11 +1,11 @@
import MockAdapter from 'axios-mock-adapter';
// import MockAdapter from 'axios-mock-adapter';
import LinkHeader from 'http-link-header';
import { vi } from 'vitest';
const api = await vi.importActual('../index') as Record<string, Function>;
let mocks: Array<Function> = [];
export const __stub = (func: (mock: MockAdapter) => void) => mocks.push(func);
export const __stub = (func: (mock: any) => void) => mocks.push(func);
export const __clear = (): Function[] => mocks = [];
// const setupMock = (axios: AxiosInstance) => {

View File

@@ -41,7 +41,10 @@ const getAuthBaseURL = createSelector([
});
export const getFetch = (accessToken?: string | null, baseURL: string = '') =>
<T = any>(input: URL | RequestInfo, init?: RequestInit & { params?: Record<string, any>} | undefined) => {
<T = any>(
input: URL | RequestInfo,
init?: RequestInit & { params?: Record<string, any>; onUploadProgress?: (e: ProgressEvent) => void } | undefined,
) => {
const fullPath = buildFullPath(input.toString(), isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : baseURL, init?.params);
const headers = new Headers(init?.headers);
@@ -56,18 +59,47 @@ export const getFetch = (accessToken?: string | null, baseURL: string = '') =>
headers.set('Content-Type', headers.get('Content-Type') || 'application/json');
}
// Fetch API doesn't report upload progress, use XHR
if (init?.onUploadProgress) {
return new Promise<Response & { data: string; json: T }>((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener('progress', init.onUploadProgress!);
xhr.addEventListener('loadend', () => {
const data = xhr.response;
let json: T = undefined!;
try {
json = JSON.parse(data);
} catch (e) {
//
}
if (xhr.status >= 400) reject({ response: { status: xhr.status, data, json } });
resolve({ status: xhr.status, data, json } as any);
});
xhr.open(init?.method || 'GET', fullPath, true);
headers.forEach((value, key) => xhr.setRequestHeader(key, value));
xhr.responseType = 'text';
xhr.send(init.body as FormData);
});
}
return fetch(fullPath, {
...init,
headers,
}).then(async (response) => {
if (!response.ok) throw { response };
const data = await response.text();
let json: T = undefined!;
try {
json = JSON.parse(data);
} catch (e) {
//
}
if (!response.ok) throw { response: { ...response, data, json } };
return { ...response, data, json };
});
};

View File

@@ -24,7 +24,7 @@ function useCreateEntity<TEntity extends Entity = Entity, Data = unknown>(
const [isSubmitting, setPromise] = useLoading();
const { entityType, listKey } = parseEntitiesPath(expandedPath);
async function createEntity(data: Data, callbacks: EntityCallbacks<TEntity> = {}): Promise<void> {
async function createEntity(data: Data, callbacks: EntityCallbacks<TEntity, { response?: Response & { json: any } }> = {}): Promise<void> {
const result = await setPromise(entityFn(data));
const schema = opts.schema || z.custom<TEntity>();
const entity = schema.parse(result.json);

View File

@@ -50,7 +50,7 @@ export interface IEmojiPickerDropdown {
}
const perLine = 8;
const lines = 2;
const lines = 2;
const DEFAULTS = [
'+1',

View File

@@ -50,7 +50,7 @@ const GroupActionButton = ({ group }: IGroupActionButton) => {
);
},
onError(error) {
const message = (error.response?.data as any).error;
const message = error.response?.json?.error;
if (message) {
toast.error(message);
}

View File

@@ -62,7 +62,7 @@ const EditGroup: React.FC<IEditGroup> = ({ params: { groupId } }) => {
toast.success(intl.formatMessage(messages.groupSaved));
},
onError(error) {
const message = (error.response?.data as any)?.error;
const message = error.response?.json?.error;
if (error.response?.status === 422 && typeof message !== 'undefined') {
toast.error(message);

View File

@@ -57,37 +57,37 @@ const NotificationFilterBar = () => {
name: 'mention',
});
if (features.accountNotifies || features.accountSubscriptions) items.push({
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/bell-ringing.svg')} />,
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/bell-ringing.svg')} />,
title: intl.formatMessage(messages.statuses),
action: onClick('status'),
name: 'status',
});
items.push({
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/heart.svg')} />,
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/heart.svg')} />,
title: intl.formatMessage(messages.favourites),
action: onClick('favourite'),
name: 'favourite',
});
items.push({
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/repeat.svg')} />,
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/repeat.svg')} />,
title: intl.formatMessage(messages.boosts),
action: onClick('reblog'),
name: 'reblog',
});
if (features.polls) items.push({
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/chart-bar.svg')} />,
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/chart-bar.svg')} />,
title: intl.formatMessage(messages.polls),
action: onClick('poll'),
name: 'poll',
});
if (features.events) items.push({
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/calendar.svg')} />,
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/calendar.svg')} />,
title: intl.formatMessage(messages.events),
action: onClick('events'),
name: 'events',
});
items.push({
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/user-plus.svg')} />,
text: <Icon className='h-4 w-4' src={require('@tabler/icons/outline/user-plus.svg')} />,
title: intl.formatMessage(messages.follows),
action: onClick('follow'),
name: 'follow',

View File

@@ -117,7 +117,7 @@ describe('auth reducer', () => {
};
const expected = ImmutableMap({
'https://gleasonator.com/users/alex': AuthUserRecord({ id: '1234', access_token: 'ABCDEFG', url: 'https://gleasonator.com/users/alex' }),
'https://gleasonator.com/users/alex': AuthUserRecord({ id: '1234', access_token: 'ABCDEFG', url: 'https://gleasonator.com/users/alex' }),
});
const result = reducer(undefined, action);

View File

@@ -154,7 +154,7 @@ const processImage = (
name?: string;
},
) => new Promise<File>((resolve, reject) => {
const canvas = document.createElement('canvas');
const canvas = document.createElement('canvas');
if (4 < orientation && orientation < 9) {
canvas.width = height;