Fix media upload
This commit is contained in:
parent
cb7976bd3d
commit
d6ee14cb99
12 changed files with 56 additions and 79 deletions
|
@ -98,8 +98,6 @@
|
|||
"@vitejs/plugin-react": "^4.0.4",
|
||||
"@webbtc/webln-types": "^3.0.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"axios": "^1.2.2",
|
||||
"axios-mock-adapter": "^1.22.0",
|
||||
"babel-plugin-formatjs": "^10.5.6",
|
||||
"babel-plugin-preval": "^5.1.0",
|
||||
"blurhash": "^2.0.0",
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 };
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -50,7 +50,7 @@ export interface IEmojiPickerDropdown {
|
|||
}
|
||||
|
||||
const perLine = 8;
|
||||
const lines = 2;
|
||||
const lines = 2;
|
||||
|
||||
const DEFAULTS = [
|
||||
'+1',
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
32
yarn.lock
32
yarn.lock
|
@ -3267,23 +3267,6 @@ axe-core@^4.6.2:
|
|||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.1.tgz#6948854183ee7e7eae336b9877c5bafa027998ea"
|
||||
integrity sha512-9l850jDDPnKq48nbad8SiEelCv4OrUWrKab/cPj0GScVg6cb6NbCCt/Ulk26QEq5jP9NnGr04Bit1BHyV6r5CQ==
|
||||
|
||||
axios-mock-adapter@^1.22.0:
|
||||
version "1.22.0"
|
||||
resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.22.0.tgz#0f3e6be0fc9b55baab06f2d49c0b71157e7c053d"
|
||||
integrity sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
is-buffer "^2.0.5"
|
||||
|
||||
axios@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.2.tgz#72681724c6e6a43a9fea860fc558127dbe32f9f1"
|
||||
integrity sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
axobject-query@^3.1.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a"
|
||||
|
@ -4891,11 +4874,6 @@ flatted@^3.2.9:
|
|||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
|
||||
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
|
||||
|
||||
follow-redirects@^1.15.0:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
|
||||
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
|
||||
|
||||
for-each@^0.3.3:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
|
||||
|
@ -5560,11 +5538,6 @@ is-boolean-object@^1.1.0:
|
|||
call-bind "^1.0.2"
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-buffer@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
|
||||
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
|
||||
|
||||
is-builtin-module@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
|
||||
|
@ -7264,11 +7237,6 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0,
|
|||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
pseudomap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
|
|
Loading…
Reference in a new issue