Skip to content
Snippets Groups Projects
Commit fb9ee36a authored by michael.minelli's avatar michael.minelli
Browse files

ExerciseDeletion => Code integration

parent 5be27bb6
No related branches found
No related tags found
No related merge requests found
Pipeline #33468 failed
......@@ -2,11 +2,7 @@ import CommanderCommand from '../CommanderCommand.js';
import ExerciseCreateCommand from './subcommands/ExerciseCreateCommand.js';
import ExerciseRunCommand from './subcommands/ExerciseRunCommand.js';
import ExerciseCorrectionCommand from './subcommands/ExerciseCorrectionCommand.js';
import ExerciseListCommand from './subcommands/ExerciseListCommand';
import ExerciseDetailCommand from './subcommands/ExerciseDetailCommand';
import ExerciseDeleteCommand from './subcommands/ExerciseDeleteCommand';
import ExerciseMemberCommand from './subcommands/ExerciseMemberCommand';
import ExerciseResultCommand from './subcommands/ExerciseResultCommand';
class ExerciseCommand extends CommanderCommand {
......@@ -20,11 +16,7 @@ class ExerciseCommand extends CommanderCommand {
protected defineSubCommands() {
ExerciseCreateCommand.registerOnCommand(this.command);
ExerciseRunCommand.registerOnCommand(this.command);
ExerciseListCommand.registerOnCommand(this.command);
ExerciseDetailCommand.registerOnCommand(this.command);
ExerciseDeleteCommand.registerOnCommand(this.command);
ExerciseMemberCommand.registerOnCommand(this.command);
ExerciseResultCommand.registerOnCommand(this.command);
ExerciseCorrectionCommand.registerOnCommand(this.command);
}
......
......@@ -17,8 +17,8 @@ class ExerciseCorrectionCommand extends CommanderCommand {
protected defineCommand() {
this.command
.description('link an exercise repo as a correction for an assignment')
.requiredOption('-a, --assignment <string>', 'id or url of the assignment of the correction')
.description('list corrections of an assignment')
.requiredOption('-a, --assignment <string>', 'id or url of the assignment')
.action(this.commandAction.bind(this));
}
......
import CommanderCommand from '../../CommanderCommand';
import chalk from 'chalk';
import ora from 'ora';
import CommanderCommand from '../../CommanderCommand';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper from '../../../helpers/AccessesHelper';
import AccessesHelper from '../../../helpers/AccessesHelper';
import TextStyle from '../../../types/TextStyle';
class ExerciseDeleteCommand extends CommanderCommand {
protected commandName: string = 'delete';
......@@ -10,24 +10,29 @@ class ExerciseDeleteCommand extends CommanderCommand {
protected defineCommand(): void {
this.command
.description('delete an exercise')
.argument('[exerciseId]', 'ID of the exercise to delete')
.argument('id or url', 'id or url of the exercise')
.action(this.commandAction.bind(this));
}
protected async commandAction(exerciseId: string): Promise<void> {
console.log(chalk.cyan('Please wait while we delete your exercise...'));
private async dataRetrieval() {
console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...'));
await AccessesHelper.checkStudent();
}
private async deleteExercise(exerciseIdOrUrl: string) {
console.log(TextStyle.BLOCK('Please wait while we are deleting the exercise...'));
if (!await AccessesHelper.checkStudent()) {
return;
}
await DojoBackendManager.deleteExercise(exerciseIdOrUrl);
}
protected async commandAction(exerciseIdOrUrl: string): Promise<void> {
try {
const spinner = ora(`Deleting exercise ${exerciseId}`).start();
await DojoBackendManager.deleteExercise(exerciseId);
spinner.succeed(`Exercise with ID ${exerciseId} has been successfully deleted.`);
} catch (error) {
ora().fail(`Failed to delete exercise with ID ${exerciseId}`);
}
await this.dataRetrieval();
await this.deleteExercise(exerciseIdOrUrl);
} catch ( e ) { /* Do nothing */ }
}
}
export default new ExerciseDeleteCommand();
// ExerciseListCommand.ts
import CommanderCommand from '../../CommanderCommand';
import chalk from 'chalk';
import ora from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper from '../../../helpers/AccessesHelper';
import Exercise from '../../../sharedByClients/models/Exercise';
//import Result from '../../../sharedByClients/models/Result';
import Table from 'cli-table3';
class ExerciseListCommand extends CommanderCommand {
protected commandName: string = 'info';
protected defineCommand(): void {
this.command
.description('detail of an exercise')
.argument('[exerciseId]', 'display detail of a specific exercise by id')
.action(this.commandAction.bind(this));
}
protected async commandAction(exerciseId?: string): Promise<void> {
console.log(chalk.cyan('Please wait while we retrieve your exercise...'));
// Check access
if (!await AccessesHelper.checkStudent()) {
return;
}
const userExercises: Exercise[] | undefined = await DojoBackendManager.getUserExercises();
if (!userExercises || userExercises.length === 0) {
ora().info('You have no exercise yet.');
return;
}
//console.log(userExercises);
if (exerciseId) {
const exercise = userExercises.find(exercise => exercise.id === exerciseId);
if (!exercise) {
ora().info(`No exercise found with ID : ${exerciseId}.`);
return;
}
ora().info(`Detail of Exercise with ID : ${exerciseId}:`);
console.log(chalk.magenta(' - Exercise Name:'), exercise.name);
console.log(chalk.magenta(' - Assignment Name:'), exercise.assignmentName);
console.log(chalk.magenta(' - GitLab ID:'), exercise.gitlabId);
console.log(chalk.magenta(' - GitLab Link:'), chalk.blue.underline(exercise.gitlabLink));
console.log(chalk.magenta(' - GitLab Last Info Date:'), exercise.gitlabLastInfoDate);
return;
} else {
ora().info('No exercise with this ID.');
}
// Display list of all exercises
//this.displayExerciseList(userExercises);
}
private displayExerciseList(exercises: Exercise[]): void {
const table = new Table({
head: ['#', 'Exercise Name']
});
exercises.forEach((exercise, index) => {
// Add 1 to index to convert zero-based index to one-based index for display
table.push([index + 1, exercise.name]);
});
ora().info('Your exercises:');
console.log(table.toString());
}
}
export default new ExerciseListCommand();
// // Display test results
// if (results && results.length > 0) {
// console.log(chalk.magenta(' - Test Results:'));
// const successfulTests = results.filter(result => result.status === 'success').length;
// const failedTests = results.filter(result => result.status === 'failure').length;
// console.log(chalk.magenta(' Successful Tests:'), successfulTests);
// console.log(chalk.magenta(' Failed Tests:'), failedTests);
// console.log(chalk.magenta(' Successful Tests List:'));
// results.filter(result => result.status === 'success').forEach(result => {
// console.log(chalk.magenta(` - ${result.testName}`));
// });
// console.log(chalk.magenta(' Failed Tests List:'));
// results.filter(result => result.status === 'failure').forEach(result => {
// console.log(chalk.magenta(` - ${result.testName}`));
// });
// } else {
// console.log(chalk.yellow(' - No test results found.'));
// }
\ No newline at end of file
// ExerciseListCommand.ts
import CommanderCommand from '../../CommanderCommand';
import chalk from 'chalk';
import ora from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper from '../../../helpers/AccessesHelper';
import Exercise from '../../../sharedByClients/models/Exercise';
import inquirer from 'inquirer';
import Table from 'cli-table3';
import Fuse from 'fuse.js';
import User from '../../../sharedByClients/models/User';
class ExerciseListCommand extends CommanderCommand {
protected commandName: string = 'list';
protected defineCommand(): void {
this.command
.description('list your exercises')
.action(this.commandAction.bind(this));
}
protected async commandAction(): Promise<void> {
console.log(chalk.cyan('Please wait while we retrieve your exercises...'));
// Check access
if (!await AccessesHelper.checkStudent()) {
return;
}
// Fetch user's exercises
const userExercises: Exercise[] | undefined = await DojoBackendManager.getUserExercises();
if (!userExercises || userExercises.length === 0) {
ora().info('You have no exercises yet.');
return;
}
// Display the list of exercises
this.displayExerciseList(userExercises);
// Ask the user for further actions
await this.askUserForActions(userExercises);
}
private async askUserForActions(exercises: Exercise[]): Promise<void> {
const { action } = await inquirer.prompt([
{
type: 'list',
name: 'action',
message: 'Que souhaitez-vous faire ?',
choices: [
{ name: 'Voir les détails d\'exercice', value: 'details'},
{ name: 'Filter les exercises', value: 'filter' },
{ name: 'Exit', value: 'exit' },
],
},
]);
if (action === 'details') {
await this.selectExerciseForDetails(exercises);
} else if (action === 'filter') {
await this.filterExercises(exercises);
} else {
ora().info('No further actions selected.');
}
}
private async selectExerciseForDetails(exercises: Exercise[]): Promise<void> {
const { selectedExercise } = await inquirer.prompt([{
type: 'list',
name: 'selectedExercise',
message: 'Selectionner un exercice :',
choices: [
...exercises.map(exercise => ({
name: exercise.name,
value: exercise.id,
})),
{ name: 'Exit', value: 'exit' },
],
}]);
if (selectedExercise === 'exit') {
ora().info('Pas de détails requis: détails dispo avec la commande `dojo exercise info <id>`.');
return;
}
const selected = exercises.find(ex => ex.id === selectedExercise);
if (selected) {
await this.displayExerciseDetails(selected);
} else {
ora().info('Invalid selection. No exercise details to show.');
}
}
private async filterExercises(exercises: Exercise[]): Promise<void> {
const { filterType } = await inquirer.prompt([
{
type: 'list',
name: 'filterType',
message: 'Comment souhaitez-vous filtrer les exercices ?',
choices: [
{ name: 'Par saisie texte', value: 'fuzzy' },
{ name: 'Par professeurs', value: 'professor' },
{ name: 'Exit', value: 'exit' },
],
},
]);
if (filterType === 'fuzzy') {
await this.fuzzySearchExercises(exercises);
} else if (filterType === 'professor') {
await this.filterByProfessor(exercises);
} else {
ora().info('No filtering selected.');
}
}
private async fuzzySearchExercises(exercises: Exercise[]): Promise<void> {
const { searchQuery } = await inquirer.prompt([
{
type: 'input',
name: 'searchQuery',
message: 'Entrez le nom de l\'exercice (laisser vide pour la liste complète) :',
},
]);
if (!searchQuery) {
this.displayExerciseList(exercises);
return;
}
const fuse = new Fuse(exercises, {
keys: ['name'],
threshold: 0.5,
distance: 150,
});
const filteredExercises = fuse.search(searchQuery).map(result => result.item);
if (filteredExercises.length === 0) {
ora().info('Aucun exercice trouvé correspondant à votre recherche.');
return;
}
this.displayExerciseList(filteredExercises);
// Affichage des détails de chaque exercice trouvé
for (const exercise of filteredExercises) {
await this.displayExerciseDetails(exercise);
}
}
private async filterByProfessor(exercises: Exercise[]): Promise<void> {
const professors: User[] | undefined = await DojoBackendManager.getProfessors();
if (!professors || professors.length === 0) {
ora().info('No professors found.');
return;
}
const professorChoices = professors.map(professor => ({
name: `${professor.gitlabUsername}`,
value: professor // Use the professor object as the value
}));
const { selectedProfessor } = await inquirer.prompt([
{
type: 'list',
name: 'selectedProfessor',
message: 'Selectionnez un professeur:',
choices: professorChoices
}
]);
console.log(`Selected professor: ${selectedProfessor.gitlabUsername}`);
ora().info('Filter by professor is not yet implemented.');
}
private displayExerciseList(exercises: Exercise[]): void {
const headers = ['Exercise Name', 'GitLab Link'];
// Calculate the maximum width for each column
const maxWidths = headers.map(header => header.length);
exercises.forEach(exercise => {
maxWidths[0] = Math.max(maxWidths[0], exercise.name.length);
maxWidths[1] = Math.max(maxWidths[1], exercise.gitlabLink.length);
});
const table = new Table({
head: headers,
});
exercises.forEach((exercise) => {
table.push([
exercise.name,
exercise.gitlabLink,
]);
});
ora().info('Your exercises:');
console.log(table.toString());
}
private async displayExerciseDetails(exercise: Exercise): Promise<void> {
ora().info(`Detail of Exercise with ID: ${exercise.id}`);
console.log(chalk.magenta(' - Exercise Name:'), exercise.name);
console.log(chalk.magenta(' - Assignment Name:'), exercise.assignmentName);
console.log(chalk.magenta(' - GitLab ID:'), exercise.gitlabId);
console.log(chalk.magenta(' - GitLab Link:'), chalk.blue.underline(exercise.gitlabLink));
console.log(chalk.magenta(' - GitLab Last Info Date:'), exercise.gitlabLastInfoDate);
// Fetch exercise members
const exerciseMembers = await DojoBackendManager.getExerciseMembers(exercise.id);
if (exerciseMembers && exerciseMembers.length > 0) {
ora().info('Exercise Members:');
exerciseMembers.forEach(member => {
console.log(chalk.magenta(` - ${member.id} ${member.name}`));
});
} else {
ora().info('No members found for this exercise.');
}
}
}
export default new ExerciseListCommand();
\ No newline at end of file
import CommanderCommand from '../../CommanderCommand';
import chalk from 'chalk';
import ora from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper from '../../../helpers/AccessesHelper';
class ExerciseMembersCommand extends CommanderCommand {
protected commandName: string = 'members';
protected defineCommand(): void {
this.command
.description('detail of an exercise')
.argument('[exerciseId]', 'display detail of a specific exercise by id')
.action(this.commandAction.bind(this));
}
protected async commandAction(exerciseId: string): Promise<void> {
console.log(chalk.cyan('Please wait while we fetch the members of the exercise...'));
if (!await AccessesHelper.checkStudent()) {
return;
}
try {
const spinner = ora(`Fetching members for exercise ${exerciseId}`).start();
const members = await DojoBackendManager.getExerciseMembers(exerciseId);
spinner.succeed(`Members of exercise with ID ${exerciseId}:`);
members.forEach(member => {
console.log(`ID: ${member.id}, Name: ${member.name}`);
});
} catch (error) {
ora().fail(`Failed to fetch members for exercise with ID ${exerciseId}`);
}
}
}
export default new ExerciseMembersCommand();
import CommanderCommand from '../../CommanderCommand';
import chalk from 'chalk';
import ora from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import Result from '../../../sharedByClients/models/Result';
class ExerciseResultCommand extends CommanderCommand {
protected commandName: string = 'result';
protected defineCommand(): void {
this.command
.description('results of an exercise')
.argument('[idOrLink]', 'display results of a specific exercise by id')
.action(this.commandAction.bind(this));
}
protected async commandAction(idOrLink: string): Promise<void> {
const spinner = ora('Fetching exercise results...').start();
try {
const exerciseId = this.extractExerciseId(idOrLink);
//console.log('Exercise ID:', exerciseId);
spinner.info(`Fetching results for exercise with ID: ${exerciseId}`);
const results = await DojoBackendManager.getExerciseResults(exerciseId);
if (!results) {
spinner.info('No results found for this exercise.');
spinner.succeed('Exercise results fetched successfully.');
return;
}
if (results.length === 0) {
spinner.info('No results found for this exercise.');
} else {
this.displayResults(results);
spinner.succeed('Exercise results fetched successfully.');
}
} catch (error) {
spinner.fail('Error fetching exercise results.');
console.error(error);
}
}
private extractExerciseId(idOrLink: string): string {
if (idOrLink.length <= 36) {
return idOrLink;
} else {
const lastUnderscoreIndex = idOrLink.lastIndexOf('_');
//console.log('Last underscore index:', lastUnderscoreIndex);
if (lastUnderscoreIndex !== -1) { // -1 = pas de underscore trouvé
return idOrLink.substring(lastUnderscoreIndex + 1); // Extrait la sous-chaîne après le dernier underscore dans idOrLink
} else {
return '';
}
}
}
private displayResults(results: Result[]): void {
if (!results || results.length === 0) {
console.log('No results to display.');
return;
}
results.forEach(result => {
console.log(chalk.magenta('Résultats de l`exercice :'));
console.log(` - Date et heure : ${result.dateTime}`);
console.log(` - Succès : ${result.success ? chalk.green('Oui') : chalk.red('Non')}`);
console.log(' - Détails des résultats :');
console.log(` - Tests réussis : ${result.results.successfulTests}`);
console.log(` - Tests échoués : ${result.results.failedTests}`);
console.log(' - Liste des tests réussis :');
if (Array.isArray(result.results.successfulTestsList)) {
result.results.successfulTestsList.forEach((test: string) => {
console.log(` - ${test} ${chalk.green('\u2713')}`);
});
}
console.log(' - Liste des tests échoués :');
if (Array.isArray(result.results.failedTestsList)) {
result.results.failedTestsList.forEach((test: string) => {
console.log(` - ${test} ${chalk.red('\u2717')}`);
});
}
console.log('-----------------------------------');
});
}
}
export default new ExerciseResultCommand();
\ No newline at end of file
......@@ -366,9 +366,9 @@ class DojoBackendManager {
}
}
public async getUserExercises(): Promise<Exercise[] | undefined> {
public async getUserExercises(): Promise<Array<Exercise> | undefined> {
try {
const response = await axios.get<DojoBackendResponse<Exercise[]>>(this.getApiUrl(ApiRoute.EXERCISE_LIST));
const response = await axios.get<DojoBackendResponse<Array<Exercise>>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_LIST));
return response.data.data;
} catch ( error ) {
console.error('Error fetching user exercises:', error);
......@@ -376,10 +376,12 @@ class DojoBackendManager {
}
}
public async getExerciseDetail(exerciseId: string): Promise<Exercise | undefined> {
public async getExerciseDetails(exerciseIdOrUrl: string): Promise<Exercise | undefined> {
try {
const response = await axios.get<Exercise>(this.getApiUrl(ApiRoute.EXERCISE_DETAIL).replace('{{exerciseId}}', String(exerciseId)));
const response = await axios.get<Exercise>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_DETAILS_GET, {
exerciseIdOrUrl: exerciseIdOrUrl
}));
return response.data;
} catch ( error ) {
console.error('Error fetching exercise details:', error);
......@@ -387,37 +389,61 @@ class DojoBackendManager {
}
}
public async deleteExercise(exerciseIdOrUrl: string, verbose: boolean = true): Promise<void> {
const spinner: ora.Ora = ora('Deleting exercise...');
public async deleteExercise(exerciseId: string): Promise<Exercise> {
return (await axios.patch<DojoBackendResponse<Exercise>>(this.getApiUrl(ApiRoute.EXERCISE_DELETE).replace('{{exerciseId}}', exerciseId))).data.data;
}
if ( verbose ) {
spinner.start();
}
public async getExerciseMembers(exerciseId: string): Promise<Array<User>> {
return (await axios.get<DojoBackendResponse<Array<User>>>(this.getApiUrl(ApiRoute.EXERCISE_MEMBER).replace('{{exerciseId}}', exerciseId))).data.data;
try {
await axios.delete<DojoBackendResponse<Exercise>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_GET_DELETE, {
exerciseIdOrUrl: exerciseIdOrUrl
}));
if ( verbose ) {
spinner.succeed(`Exercise deleted with success`);
}
} catch ( error ) {
this.handleApiError(error, spinner, verbose, `Exercise deleting error: ${ error }`);
throw error;
}
}
public async getExerciseMembers(exerciseIdOrUrl: string): Promise<Array<User>> {
return (await axios.get<DojoBackendResponse<Array<User>>>(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_MEMBERS_GET, {
exerciseIdOrUrl: exerciseIdOrUrl
}))).data.data;
}
public async getExerciseResults(exerciseId: string): Promise<Result[]> {
public async getExerciseResults(exerciseIdOrUrl: string): Promise<Array<Result>> {
try {
const response = await axios.get(this.getApiUrl(ApiRoute.EXERCISE_RESULTS).replace('{{idOrLink}}', exerciseId));
//console.log('response.data:', response.data);
return response.data as Result[];
const response = await axios.get(DojoBackendHelper.getApiUrl(ApiRoute.EXERCISE_RESULTS, {
exerciseIdOrUrl: exerciseIdOrUrl
}));
return response.data as Array<Result>;
} catch ( error ) {
console.error('Error fetching exercise results:', error);
return [];
}
}
public async getProfessors(): Promise<User[] | undefined> {
public async getUsers(roleFilter?: string): Promise<Array<User> | undefined> {
try {
const response = await axios.get<DojoBackendResponse<User[]>>(this.getApiUrl(ApiRoute.TEACHERS));
const users = response.data.data;
return users;
const response = await axios.get<DojoBackendResponse<Array<User>>>(DojoBackendHelper.getApiUrl(ApiRoute.USER_LIST), { params: roleFilter ? { roleFilter: roleFilter } : {} });
return response.data.data;
} catch ( error ) {
console.error('Error fetching professors:', error);
return undefined;
}
}
public async getTeachers(): Promise<Array<User> | undefined> {
return this.getUsers('teacher');
}
}
......
Subproject commit 86707310b276fd641f794e8c9f410c42bdb58206
Subproject commit 6e46ceeabffc5ba6fdd27ca89b9b5f82c68f82de
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment