From 15feb4b93a112ed0423acbf03542361621c61f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Tainon?= Date: Mon, 3 Jun 2024 18:22:06 +0200 Subject: [PATCH 1/2] Evaluate correct solutions --- frontend/common/options.ts | 4 +-- frontend/submission/submission.ts | 4 ++- frontend/task/index.ts | 4 +-- .../task/libs/quickalgo_library_factory.ts | 8 +++-- frontend/task/platform/platform.ts | 35 ++++++++++++++++++- frontend/task/utils.ts | 2 +- frontend/utils/api.ts | 21 +++++++++++ package.json | 3 +- 8 files changed, 71 insertions(+), 10 deletions(-) diff --git a/frontend/common/options.ts b/frontend/common/options.ts index de37837f..dab1bad5 100644 --- a/frontend/common/options.ts +++ b/frontend/common/options.ts @@ -231,8 +231,8 @@ export default function(bundle: Bundle) { if (false !== reloadTask) { yield* put({type: StepperActionTypes.StepperExit}); - if (!state.options.tabsEnabled) { - const activeBufferName = state.buffers.activeBufferName; + const activeBufferName = state.buffers.activeBufferName; + if (!state.options.tabsEnabled && null !== activeBufferName) { yield* put(bufferChangePlatform(activeBufferName, newPlatform)); } } diff --git a/frontend/submission/submission.ts b/frontend/submission/submission.ts index 8d0dc584..8d33ddf2 100644 --- a/frontend/submission/submission.ts +++ b/frontend/submission/submission.ts @@ -241,7 +241,9 @@ export default function (bundle: Bundle) { // Refresh test visualization const currentTestId = yield* appSelect(state => state.task.currentTestId); - yield* put(updateCurrentTestId({testId: currentTestId, record: false})); + if (null !== currentTestId) { + yield* put(updateCurrentTestId({testId: currentTestId, record: false})); + } }); yield* takeEvery(submissionChangeDisplayedError, function* ({payload}) { diff --git a/frontend/task/index.ts b/frontend/task/index.ts index 45df1c20..f8d4c057 100644 --- a/frontend/task/index.ts +++ b/frontend/task/index.ts @@ -982,10 +982,10 @@ export default function (bundle: Bundle) { yield* takeEvery(platformAnswerLoaded, function*({payload: {answer}}) { log.getLogger('task').debug('Platform answer loaded', answer); const state = yield* appSelect(); + const currentBuffer = state.buffers.activeBufferName; if (state.options.tabsEnabled || !state.buffers.activeBufferName) { yield* call(createSourceBufferFromDocument, answer.document, answer.platform); - } else { - const currentBuffer = state.buffers.activeBufferName; + } else if (null !== currentBuffer) { if (state.buffers.buffers[currentBuffer].platform !== answer.platform) { yield* put(bufferChangePlatform(currentBuffer, answer.platform, answer.document)); } else { diff --git a/frontend/task/libs/quickalgo_library_factory.ts b/frontend/task/libs/quickalgo_library_factory.ts index a4366614..078356d5 100644 --- a/frontend/task/libs/quickalgo_library_factory.ts +++ b/frontend/task/libs/quickalgo_library_factory.ts @@ -31,7 +31,7 @@ import {selectActiveBufferPlatform} from '../../buffers/buffer_selectors'; import {selectAvailableExecutionModes} from '../../submission/submission_selectors'; import {submissionChangeExecutionMode} from '../../submission/submission_slice'; -export function* createQuickalgoLibrary() { +export function* createQuickalgoLibrary(platformAlreadyChanged: boolean = false) { let state = yield* appSelect(); let oldContext = quickAlgoLibraries.getContext(null, state.environment); log.getLogger('libraries').debug('Create a context', state.environment); @@ -124,9 +124,13 @@ export function* createQuickalgoLibrary() { availablePlatforms = availablePlatforms.filter(platform => -1 !== taskAvailablePlatforms.indexOf(platform)); } if (-1 === availablePlatforms.indexOf(state.options.platform) && availablePlatforms.length) { + if (platformAlreadyChanged) { + throw new Error("Platform has already changed once, cannot converge to a valid platform"); + } + yield* put({type: CommonActionTypes.PlatformChanged, payload: {platform: availablePlatforms[0], reloadTask: true}}); - return false; + return yield* call(createQuickalgoLibrary, true); } yield* put(taskSetAvailablePlatforms(availablePlatforms)); diff --git a/frontend/task/platform/platform.ts b/frontend/task/platform/platform.ts index 521f327d..fecaa216 100644 --- a/frontend/task/platform/platform.ts +++ b/frontend/task/platform/platform.ts @@ -49,7 +49,7 @@ import {Codecast} from '../../app_types'; import {Document} from '../../buffers/buffer_types'; import {quickAlgoLibraries} from '../libs/quick_algo_libraries_model'; import {ActionTypes} from '../../common/actionTypes'; -import {TaskAnswer} from '../task_types'; +import {isServerTask, TaskAnswer} from '../task_types'; import {RECORDING_FORMAT_VERSION} from '../../version'; import {BlockBufferHandler, uncompressIntoDocument} from '../../buffers/document'; import {CodecastPlatform} from '../../stepper/codecast_platform'; @@ -57,6 +57,7 @@ import {hasBlockPlatform} from '../../stepper/platforms'; import {callPlatformValidate} from '../../submission/submission_actions'; import {loadOptionsFromQuery} from '../../common/options'; import {CodecastOptions} from '../../store'; +import {asyncGetFile} from '../../utils/api'; let getTaskAnswer: () => Generator; let getTaskState: () => Generator; @@ -365,6 +366,31 @@ function* taskGetStateEventSaga ({payload: {success}}: ReturnType state.task.currentTask); + if (isServerTask(task)) { + const taskSettings = yield* call(asyncGetFile, 'taskSettings.json'); + if (!taskSettings) { + return; + } + taskSettingsParsed = JSON.parse(taskSettings); + } + + if (!taskSettingsParsed?.correctSolutions) { + return; + } + + const {correctSolutions} = taskSettingsParsed; + resources.correct_solutions = []; + for (let correctSolution of correctSolutions) { + const {path, language, grade} = correctSolution; + const correctedPath = path.replace(/\$TASK_PATH\/?/, ''); + const solution = yield* call(asyncGetFile, correctedPath); + resources.correct_solutions.push({type: 'solution', solution, id: path, language, grade}); + } +} + function* taskGetResourcesPostSaga ({payload: {resources, callback}}: ReturnType) { const options = yield* appSelect(state => state.options); let optionsToPreload = {}; @@ -388,6 +414,13 @@ function* taskGetResourcesPostSaga ({payload: {resources, callback}}: ReturnType } }); + try { + yield* call(taskGetResourcesImportCorrectSolutions, resources); + } catch (e) { + // Avoid blocking errors here + console.error(e); + } + // For Castor platform, we need to add custom scripts that will be added to the assets during the generation of the task const castorScriptInject = `window.codecastPreload = JSON.parse('${JSON.stringify(optionsToPreload)}'); document.body.setAttribute('id', 'app'); diff --git a/frontend/task/utils.ts b/frontend/task/utils.ts index bb28d336..ca3a1e30 100644 --- a/frontend/task/utils.ts +++ b/frontend/task/utils.ts @@ -154,7 +154,7 @@ export function checkCompilingCode(answer: TaskAnswer|null, state: AppStore, dis export function getBlocksUsage(answer: TaskAnswer|null) { const context = quickAlgoLibraries.getContext(null, 'main'); - if (!context) { + if (!context || !answer) { return null; } diff --git a/frontend/utils/api.ts b/frontend/utils/api.ts index 1e293590..fe328fd1 100644 --- a/frontend/utils/api.ts +++ b/frontend/utils/api.ts @@ -51,3 +51,24 @@ export const asyncGetJson = function (path, withToken: boolean = false) { return promise; }; + +export const asyncGetFile = function(path) { + let req; + const promise = new Promise(function(resolve, reject) { + req = request.get(path); + + req.end(function(err, res) { + if (err || !res.ok) { + return reject({err, res}); + } + + resolve(res.text); + }); + }); + + promise[CANCEL] = () => { + req.abort(); + }; + + return promise; +}; diff --git a/package.json b/package.json index 99044f75..cadf5613 100644 --- a/package.json +++ b/package.json @@ -159,5 +159,6 @@ "webpack-dev-middleware": "^6.1.1", "webpack-hot-middleware": "^2.25.4", "worker-loader": "^3.0.8" - } + }, + "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610" } From 54837c59de31e6952050fda625caf98d988e04e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Tainon?= Date: Wed, 5 Jun 2024 11:53:08 +0200 Subject: [PATCH 2/2] [Fix] Fork saga to allow continuing task loading --- frontend/task/index.ts | 2 +- frontend/task/task_types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/task/index.ts b/frontend/task/index.ts index f8d4c057..76241ca2 100644 --- a/frontend/task/index.ts +++ b/frontend/task/index.ts @@ -274,7 +274,7 @@ function* taskLoadSaga(app: App, action) { const currentTask = yield* appSelect(state => state.task.currentTask); if (!isServerTask(currentTask)) { - yield* call(subscribePlatformHelper); + yield* fork(subscribePlatformHelper); } if (currentTask) { diff --git a/frontend/task/task_types.ts b/frontend/task/task_types.ts index bcdbf068..00d66639 100644 --- a/frontend/task/task_types.ts +++ b/frontend/task/task_types.ts @@ -223,7 +223,7 @@ export interface TaskServer extends TaskNormalized { export type Task = QuickalgoTask & Partial; export function isServerTask(object: Task|null): boolean { - return (object && null !== object.id && undefined !== object.id) || window.PEMTaskMetaData; + return !!((object && null !== object.id && undefined !== object.id) || window.PEMTaskMetaData); } export function isServerTest(object: TaskTest): boolean {