From 34373cbd6d488661645502dcbe1fdf1d17bf6f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Minelli?= <git@minelli.swiss> Date: Tue, 25 Mar 2025 14:41:34 +0100 Subject: [PATCH] ExerciseHelper => Add some Exercises related function (interactive menu, displayDetails, clone, delete) --- NodeApp/src/helpers/Dojo/ExerciseHelper.ts | 140 +++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 NodeApp/src/helpers/Dojo/ExerciseHelper.ts diff --git a/NodeApp/src/helpers/Dojo/ExerciseHelper.ts b/NodeApp/src/helpers/Dojo/ExerciseHelper.ts new file mode 100644 index 0000000..9edd5a4 --- /dev/null +++ b/NodeApp/src/helpers/Dojo/ExerciseHelper.ts @@ -0,0 +1,140 @@ +import Exercise from '../../sharedByClients/models/Exercise'; +import ora from 'ora'; +import TextStyle from '../../types/TextStyle'; +import inquirer from 'inquirer'; +import Config from '../../config/Config'; +import DojoBackendManager from '../../managers/DojoBackendManager'; + + +class ExerciseHelper { + /** + * Clone the exercise repository + * @param exercise + * @param providedPath If a string is provided, the repository will be cloned in the specified directory. If true, the repository will be cloned in the current directory. If false, the repository will not be cloned, and if undefined, the user will be prompted for the path. + */ + async clone(exercise: Exercise, providedPath: string | boolean | undefined) { + if ( providedPath === false ) { + return; + } + + let path: string | boolean = './'; + if ( providedPath === undefined ) { + path = (await inquirer.prompt([ { + type : 'input', + name : 'path', + message: `Please enter the path (blank, '.' or './' for current directory):` + } ])).path; + } else { + path = providedPath; + } + + console.log(TextStyle.BLOCK('Please wait while we are cloning the repository...')); + + await Config.gitlabManager.cloneRepository(path === '' ? true : path, exercise.gitlabCreationInfo.ssh_url_to_repo, `DojoExercise_${ exercise.assignmentName }`, true, 0); + } + + async delete(exerciseIdOrUrl: string) { + console.log(TextStyle.BLOCK('Please wait while we are deleting the exercise...')); + + await DojoBackendManager.deleteExercise(exerciseIdOrUrl); + } + + async actionMenu(exercise: Exercise): Promise<void> { + // eslint-disable-next-line no-constant-condition + while ( true ) { + const action: string = (await inquirer.prompt([ { + type : 'list', + name : 'action', + message: 'What action do you want to do on the exercise ?', + choices: [ { + name : 'Display details of the exercise', + value: 'info' + }, new inquirer.Separator(), { + name : 'Clone (SSH required) in current directory (will create a subdirectory)', + value: 'cloneInCurrentDirectory' + }, { + name : 'Clone (SSH required) in the specified directory (will create a subdirectory)', + value: 'clone' + }, new inquirer.Separator(), { + name : 'Delete the exercise', + value: 'delete' + }, new inquirer.Separator(), { + name : 'Exit', + value: 'exit' + }, new inquirer.Separator() ] + } ])).action; + + switch ( action ) { + case 'info': + await this.displayDetails(exercise, false); + break; + case 'cloneInCurrentDirectory': + await this.clone(exercise, true); + break; + case 'clone': + await this.clone(exercise, undefined); + break; + case 'delete': + await this.delete(exercise.id); + return; + case 'exit': + return; + default: + ora().fail('Invalid option.'); + return; + } + } + } + + async displayDetails(exercise: Exercise, showActionMenu: boolean = false): Promise<void> { + ora().info(`Details of the exercise:`); + + const oraInfo = (message: string, indent: number = 4) => { + ora({ + text : message, + indent: indent + }).start().info(); + }; + + oraInfo(`${ TextStyle.LIST_ITEM_NAME('Id:') } ${ exercise.id }`); + oraInfo(`${ TextStyle.LIST_ITEM_NAME('Name:') } ${ exercise.name }`); + oraInfo(`${ TextStyle.LIST_ITEM_NAME('Assignment:') } ${ exercise.assignmentName }`); + + // Display exercise teachers + if ( exercise.assignment?.staff && exercise.assignment?.staff.length > 0 ) { + oraInfo(`${ TextStyle.LIST_ITEM_NAME('Teachers:') }`); + exercise.assignment?.staff.forEach(staff => { + console.log(` - ${ staff.gitlabUsername }`); + }); + } else { + ora({ + text : `${ TextStyle.LIST_ITEM_NAME('Teachers:') } No teachers found for this exercise.`, + indent: 4 + }).start().warn(); + } + + // Display exercise members + if ( exercise.members && exercise.members.length > 0 ) { + oraInfo(`${ TextStyle.LIST_ITEM_NAME('Members:') }`); + exercise.members.forEach(member => { + console.log(` - ${ member.gitlabUsername }`); + }); + } else { + ora({ + text : `${ TextStyle.LIST_ITEM_NAME('Members:') } No members found for this exercise.`, + indent: 4 + }).start().warn(); + } + + oraInfo(`${ TextStyle.LIST_ITEM_NAME('Gitlab URL:') } ${ exercise.gitlabCreationInfo.web_url }`); + oraInfo(`${ TextStyle.LIST_ITEM_NAME('HTTP Repo:') } ${ exercise.gitlabCreationInfo.http_url_to_repo }`); + oraInfo(`${ TextStyle.LIST_ITEM_NAME('SSH Repo:') } ${ exercise.gitlabCreationInfo.ssh_url_to_repo }`); + + if ( showActionMenu ) { + await this.actionMenu(exercise); + } + } +} + + +export default new ExerciseHelper(); \ No newline at end of file -- GitLab