Skip to content

Commit

Permalink
Merge pull request #1152 from ral-facilities/api-refresh-logic-uppy-#…
Browse files Browse the repository at this point in the history
…1147

Uppy refresh token logic
  • Loading branch information
joshuadkitenge authored Jan 14, 2025
2 parents b44c3d8 + 2de9a9e commit d03524a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 9 deletions.
45 changes: 44 additions & 1 deletion src/api/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const createAuthenticatedClient = (props: {
return new Promise((resolve, reject) => {
failedAuthRequestQueue.push((shouldReject?: boolean) => {
if (shouldReject) reject(error);
else resolve(imsApi(originalRequest));
else resolve(apiClient(originalRequest));
});
});
}
Expand All @@ -91,6 +91,49 @@ const createAuthenticatedClient = (props: {
return apiClient;
};

export function uppyOnAfterResponse(xhr: XMLHttpRequest) {
if (xhr.status >= 400 && xhr.status < 600) {
const errorMessage: string = (
JSON.parse(xhr.responseText) as APIError
).detail.toLocaleLowerCase();

// Check if the token is invalid and needs refreshing
if (
xhr.status === 403 &&
errorMessage.includes('expired token') &&
localStorage.getItem('scigateway:token')
) {
// Prevent other requests from also attempting to refresh while waiting for
// SciGateway to refresh the token

if (!isFetchingAccessToken) {
isFetchingAccessToken = true;

// Request SciGateway to refresh the token
document.dispatchEvent(
new CustomEvent(MicroFrontendId, {
detail: {
type: InvalidateTokenType,
},
})
);
}

// Create a new promise to wait for the token to be refreshed
return new Promise<void>((resolve, reject) => {
failedAuthRequestQueue.push((shouldReject?: boolean) => {
if (shouldReject) reject(xhr);
else resolve();
});
});
}
}
}

export function uppyOnBeforeRequest(xhr: XMLHttpRequest) {
xhr.setRequestHeader('Authorization', `Bearer ${readSciGatewayToken()}`);
}

export const imsApi = createAuthenticatedClient({
getURL: (settings) => settings.imsApiUrl,
});
Expand Down
19 changes: 11 additions & 8 deletions src/common/images/uploadImagesDialog.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ProgressBar from '@uppy/progress-bar'; // Import the ProgressBar plugin
import { DashboardModal } from '@uppy/react';
import XHR from '@uppy/xhr-upload';
import React from 'react';
import { uppyOnAfterResponse, uppyOnBeforeRequest } from '../../api/api';
import { settings } from '../../settings';
import { getNonEmptyTrimmedString } from '../../utils';

Expand Down Expand Up @@ -47,6 +48,16 @@ const UploadImagesDialog = (props: UploadImagesDialogProps) => {
endpoint: `${url}/images`,
method: 'POST',
fieldName: 'upload_file',
limit: 1, // Limit uploads to one file at a time
// Reason 1: To avoid overloading the memory of the object-store API.
// Reason 2: To prevent multiple simultaneous uploads from triggering
// the token refresh process multiple times, which could lead to race conditions.
async onBeforeRequest(xhr) {
uppyOnBeforeRequest(xhr);
},
async onAfterResponse(xhr) {
await uppyOnAfterResponse(xhr);
},
});
});

Expand Down Expand Up @@ -86,14 +97,6 @@ const UploadImagesDialog = (props: UploadImagesDialogProps) => {
}
});

uppy.on('upload-error', (_file, _error, response) => {
if (response?.body?.id) {
// TODO: Implement logic to delete metadata using id
// If metadata exists for the given id, remove it from the api
// If not, do nothing and exit the function
}
});

return (
<DashboardModal
open={open}
Expand Down

0 comments on commit d03524a

Please sign in to comment.