Fixed the exercise submission front-end again.

This commit is contained in:
Andrew Lalis 2023-04-07 12:17:40 +02:00
parent 2881dc5376
commit 4a6d33ffa4
3 changed files with 63 additions and 79 deletions

View File

@ -8,6 +8,7 @@ const api = axios.create({
});
export enum VideoProcessingStatus {
NOT_STARTED = 'NOT_STARTED',
WAITING = 'WAITING',
IN_PROGRESS = 'IN_PROGRESS',
COMPLETED = 'COMPLETED',
@ -18,24 +19,21 @@ export interface FileMetadata {
filename: string;
mimeType: string;
size: number;
uploadedAt: string;
availableForDownload: boolean;
createdAt: string;
}
export async function uploadVideoToCDN(file: File): Promise<string> {
export async function uploadVideoToCDN(file: File): Promise<number> {
const response = await api.post('/uploads/video', file, {
headers: {
'Content-Type': file.type,
},
});
return response.data.id;
return response.data.taskId;
}
export async function getVideoProcessingStatus(
id: string
): Promise<VideoProcessingStatus | null> {
export async function getVideoProcessingStatus(taskId: number): Promise<VideoProcessingStatus | null> {
try {
const response = await api.get(`/uploads/video/${id}/status`);
const response = await api.get(`/uploads/video/${taskId}/status`);
return response.data.status;
} catch (error: any) {
if (error.response && error.response.status === 404) {
@ -45,16 +43,14 @@ export async function getVideoProcessingStatus(
}
}
export async function waitUntilVideoProcessingComplete(
id: string
): Promise<VideoProcessingStatus> {
export async function waitUntilVideoProcessingComplete(taskId: number): Promise<VideoProcessingStatus> {
let failureCount = 0;
let attemptCount = 0;
while (failureCount < 5 && attemptCount < 60) {
await sleep(1000);
attemptCount++;
try {
const status = await getVideoProcessingStatus(id);
const status = await getVideoProcessingStatus(taskId);
failureCount = 0;
if (
status === VideoProcessingStatus.COMPLETED ||

View File

@ -51,8 +51,8 @@ export default {
upload: 'Video File to Upload',
submit: 'Submit',
submitUploading: 'Uploading video...',
submitUploadFailed: 'Video upload failed.',
submitCreatingSubmission: 'Creating submission...',
submitVideoProcessing: 'Processing...',
submitComplete: 'Submission complete!',
submitFailed: 'Submission processing failed. Please try again later.',
},

View File

@ -48,7 +48,7 @@ A high-level overview of the submission process is as follows:
</div>
<div class="row">
<q-input
v-model="submissionModel.date"
v-model="submissionModel.performedAt"
type="date"
:label="$t('gymPage.submitPage.date')"
class="col-12"
@ -98,21 +98,15 @@ import api from 'src/api/main';
import {Gym} from 'src/api/main/gyms';
import {Exercise} from 'src/api/main/exercises';
import {useRoute, useRouter} from 'vue-router';
import { showApiErrorToast, sleep } from 'src/utils';
import {
uploadVideoToCDN,
VideoProcessingStatus,
waitUntilVideoProcessingComplete,
} from 'src/api/cdn';
import {showApiErrorToast, showWarningToast, sleep} from 'src/utils';
import {uploadVideoToCDN,} from 'src/api/cdn';
import {useAuthStore} from 'stores/auth-store';
import {useI18n} from 'vue-i18n';
import { useQuasar } from 'quasar';
const authStore = useAuthStore();
const router = useRouter();
const route = useRoute();
const i18n = useI18n();
const quasar = useQuasar();
interface Option {
value: string;
@ -127,8 +121,8 @@ let submissionModel = ref({
weight: 100,
weightUnit: 'Kg',
reps: 1,
videoFileId: '',
date: new Date().toLocaleDateString('en-CA'),
performedAt: new Date().toLocaleDateString('en-CA'),
taskId: -1
});
const selectedVideoFile: Ref<File | undefined> = ref<File>();
const weightUnits = ['KG', 'LBS'];
@ -169,59 +163,53 @@ async function onSubmitted() {
if (!selectedVideoFile.value || !gym.value) return;
submitting.value = true;
if (await uploadVideo()) {
await createSubmission();
}
submitting.value = false;
}
/**
* Uploads the selected video and returns true if successful.
*/
async function uploadVideo(): Promise<boolean> {
if (!selectedVideoFile.value) return false;
try {
// 1. Upload the video to the CDN.
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitUploading');
await sleep(1000);
submissionModel.value.videoFileId = await uploadVideoToCDN(
selectedVideoFile.value
);
// 2. Wait for the video to be processed.
submitButtonLabel.value = i18n.t(
'gymPage.submitPage.submitVideoProcessing'
);
const processingStatus = await waitUntilVideoProcessingComplete(
submissionModel.value.videoFileId
);
// 3. If successful upload, create the submission.
if (processingStatus === VideoProcessingStatus.COMPLETED) {
try {
submitButtonLabel.value = i18n.t(
'gymPage.submitPage.submitCreatingSubmission'
);
submissionModel.value.taskId = await uploadVideoToCDN(selectedVideoFile.value);
return true;
} catch (error) {
showApiErrorToast(error);
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitUploadFailed');
await sleep(1000);
const submission = await api.gyms.submissions.createSubmission(
gym.value,
submissionModel.value,
authStore
);
selectedVideoFile.value = undefined;
submitButtonLabel.value = i18n.t('gymPage.submitPage.submit');
return false;
}
}
/**
* Tries to create a new submission, and if successful, redirects the user to it.
*/
async function createSubmission() {
if (!gym.value) return;
try {
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitCreatingSubmission');
await sleep(1000);
const submission = await api.gyms.submissions.createSubmission(gym.value, submissionModel.value, authStore);
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitComplete');
await sleep(2000);
await router.push(`/submissions/${submission.id}`);
} catch (error: any) {
if (error.response && error.response.status === 400) {
quasar.notify({
message: error.response.data.message,
type: 'warning',
position: 'top',
});
showWarningToast(error.response.data.message);
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitFailed');
await sleep(3000);
} else {
showApiErrorToast(error);
}
}
// Otherwise, report the failed submission and give up.
} else {
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitFailed');
await sleep(3000);
}
} catch (error: any) {
showApiErrorToast(error);
} finally {
submitting.value = false;
submitButtonLabel.value = i18n.t('gymPage.submitPage.submit');
}
}