Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • Jw_sonar_backup
  • add_route_assignments
  • add_route_user
  • assignment_filter
  • bedran_exercise-list
  • exercise_list_filter
  • interactive-mode-preference
  • jw_sonar
  • main
  • move-to-esm-only
  • v6.0.0
  • 2.0.0
  • 2.1.0
  • 2.2.0
  • 3.0.0
  • 3.0.1
  • 3.1.0
  • 3.1.1
  • 3.1.2
  • 3.2.0
  • 3.2.2
  • 3.2.3
  • 3.3.0
  • 3.4.1
  • 3.4.2
  • 3.5.0
  • 4.0.0
  • 4.0.1
  • 4.1.0
  • 4.1.1
  • 4.2.0
  • 5.0.0
  • 6.0.0-dev
  • Latest
  • Pre-alpha
  • v1.0.1
36 results

Target

Select target project
No results found
Select Git revision
  • Jw_sonar_backup
  • add_route_assignments
  • add_route_user
  • assignment_filter
  • bedran_exercise-list
  • exercise_list_filter
  • interactive-mode-preference
  • jw_sonar
  • main
  • move-to-esm-only
  • v6.0.0
  • 2.0.0
  • 2.1.0
  • 2.2.0
  • 3.0.0
  • 3.0.1
  • 3.1.0
  • 3.1.1
  • 3.1.2
  • 3.2.0
  • 3.2.2
  • 3.2.3
  • 3.3.0
  • 3.4.1
  • 3.4.2
  • 3.5.0
  • 4.0.0
  • 4.0.1
  • 4.1.0
  • 4.1.1
  • 4.2.0
  • 5.0.0
  • 6.0.0-dev
  • Latest
  • Pre-alpha
  • v1.0.1
36 results
Show changes

Commits on Source 14

17 files
+ 623
130
Compare changes
  • Side-by-side
  • Inline

Files

+6 −0
Original line number Diff line number Diff line
@@ -18,6 +18,12 @@
-->


## 3.5.0 (???)

### ✨ Feature
- Link a commit of an exercise as a corrige of an assignment


## 3.4.2 (2024-01-23)

### 🐛 Bugfix
Original line number Diff line number Diff line
{
    "name"           : "dojo_cli",
    "description"    : "CLI of the Dojo project",
    "version"        : "3.4.2",
    "version"        : "3.5.0",
    "license"        : "AGPLv3",
    "author"         : "Michaël Minelli <dojo@minelli.me>",
    "main"           : "dist/app.js",
@@ -33,6 +33,7 @@
        "test"        : "echo \"Error: no test specified\" && exit 1"
    },
    "dependencies"   : {
        "@gitbeaker/rest"     : "^39.34.3",
        "appdata-path"        : "^1.0.0",
        "axios"               : "^1.6.5",
        "boxen"               : "^5.1.2",
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ class CommanderApp {
                           sortSubcommands  : true
                       })
        .option('-H, --host <string>', 'override the Dojo API endpoint', ClientsSharedConfig.apiURL)
        .option('-I, --interactive', 'show interactive interface when available', Config.interactiveMode)
        .addOption(new Option('--debug').hideHelp())
        .hook('preAction', () => {
            this.warnDevelopmentVersion();
@@ -37,6 +38,10 @@ class CommanderApp {
            ClientsSharedConfig.apiURL = this.program.opts().host;
        });

        this.program.on('option:interactive', () => {
            Config.interactiveMode = this.program.opts().interactive;
        });

        this.program.on('option:debug', () => {
            SharedConfig.debug = true;
        });
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import AssignmentPublishCommand from './subcommands/AssignmentPublishCommand';
import AssignmentUnpublishCommand  from './subcommands/AssignmentUnpublishCommand';
import AssignmentCheckCommand      from './subcommands/AssignmentCheckCommand';
import AssignmentRunCommand        from './subcommands/AssignmentRunCommand';
import AssignmentCorrectionCommand from './subcommands/correction/AssignmentCorrectionCommand';


class AssignmentCommand extends CommanderCommand {
@@ -20,6 +21,7 @@ class AssignmentCommand extends CommanderCommand {
        AssignmentRunCommand.registerOnCommand(this.command);
        AssignmentPublishCommand.registerOnCommand(this.command);
        AssignmentUnpublishCommand.registerOnCommand(this.command);
        AssignmentCorrectionCommand.registerOnCommand(this.command);
    }

    protected async commandAction(): Promise<void> { }
Original line number Diff line number Diff line
import CommanderCommand                  from '../../../CommanderCommand';
import AssignmentCorrectionLinkCommand   from './subcommands/AssignmentCorrectionLinkCommand';
import AssignmentCorrectionUpdateCommand from './subcommands/AssignmentCorrectionUpdateCommand';


class AssignmentCorrectionCommand extends CommanderCommand {
    protected commandName: string = 'correction';

    protected defineCommand() {
        this.command
        .description('manage corrections of an assignment');
    }

    protected defineSubCommands() {
        AssignmentCorrectionLinkCommand.registerOnCommand(this.command);
        AssignmentCorrectionUpdateCommand.registerOnCommand(this.command);
    }

    protected async commandAction(): Promise<void> { }
}


export default new AssignmentCorrectionCommand();
 No newline at end of file
Original line number Diff line number Diff line
import AssignmentCorrectionLinkUpdateCommand from './AssignmentCorrectionLinkUpdateCommand';


class AssignmentCorrectionLinkCommand extends AssignmentCorrectionLinkUpdateCommand {
    protected commandName: string = 'link';
    protected isUpdate: boolean = false;
}


export default new AssignmentCorrectionLinkCommand();
 No newline at end of file
Original line number Diff line number Diff line
import CommanderCommand   from '../../../../CommanderCommand';
import chalk              from 'chalk';
import ora                from 'ora';
import DojoBackendManager from '../../../../../managers/DojoBackendManager';
import SessionManager     from '../../../../../managers/SessionManager';
import Assignment         from '../../../../../sharedByClients/models/Assignment';


abstract class AssignmentCorrectionLinkUpdateCommand extends CommanderCommand {
    protected abstract isUpdate: boolean;

    protected defineCommand() {
        this.command
        .description(this.isUpdate ? 'update a correction of an assignment' : 'link an exercise repo as a correction for an assignment')
        .argument('<string>', 'id or url of the exercise that is the correction')
        .requiredOption('-a, --assignment <string>', 'id or url of the assignment of the correction')
        .action(this.commandAction.bind(this));
    }

    protected async commandAction(exerciseIdOrUrl: string, options: { assignment: string }): Promise<void> {
        let assignment!: Assignment | undefined;

        // Check access
        {
            console.log(chalk.cyan('Please wait while we check access...'));

            const assignmentGetSpinner: ora.Ora = ora('Checking if assignment exists').start();
            assignment = await DojoBackendManager.getAssignment(options.assignment);
            if ( !assignment ) {
                assignmentGetSpinner.fail(`The assignment doesn't exists`);
                return;
            }
            assignmentGetSpinner.succeed(`The assignment exists`);


            const assignmentAccessSpinner: ora.Ora = ora('Checking assignment access').start();
            if ( assignment.staff.find(staff => staff.id === SessionManager.profile?.id) === undefined ) {
                assignmentAccessSpinner.fail(`You are not in the staff of the assignment`);
                return;
            }
            assignmentAccessSpinner.succeed(`You are in the staff of the assignment`);


            const assignmentPublishedSpinner: ora.Ora = ora('Checking assignment').start();
            if ( !assignment.published ) {
                assignmentPublishedSpinner.fail(`Assignment is not published`);
                return;
            }
            assignmentPublishedSpinner.succeed(`Assignment is published`);
        }

        // Link the exercise
        {
            console.log(chalk.cyan('Please wait while we link the exercise...'));

            await DojoBackendManager.linkUpdateCorrection(exerciseIdOrUrl, assignment, this.isUpdate);
        }
    }
}


export default AssignmentCorrectionLinkUpdateCommand;
 No newline at end of file
Original line number Diff line number Diff line
import AssignmentCorrectionLinkUpdateCommand from './AssignmentCorrectionLinkUpdateCommand';


class AssignmentCorrectionUpdateCommand extends AssignmentCorrectionLinkUpdateCommand {
    protected commandName: string = 'update';
    protected isUpdate: boolean = true;
}


export default new AssignmentCorrectionUpdateCommand();
 No newline at end of file
Original line number Diff line number Diff line
import CommanderCommand          from '../CommanderCommand';
import ExerciseCreateCommand     from './subcommands/ExerciseCreateCommand';
import ExerciseRunCommand        from './subcommands/ExerciseRunCommand';
import ExerciseCorrectionCommand from './subcommands/ExerciseCorrectionCommand';


class ExerciseCommand extends CommanderCommand {
@@ -14,6 +15,7 @@ class ExerciseCommand extends CommanderCommand {
    protected defineSubCommands() {
        ExerciseCreateCommand.registerOnCommand(this.command);
        ExerciseRunCommand.registerOnCommand(this.command);
        ExerciseCorrectionCommand.registerOnCommand(this.command);
    }

    protected async commandAction(): Promise<void> { }
Original line number Diff line number Diff line
import CommanderCommand   from '../../CommanderCommand';
import ora                from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import Config             from '../../../config/Config';
import Assignment         from '../../../sharedByClients/models/Assignment';
import inquirer           from 'inquirer';
import open               from 'open';
import chalk              from 'chalk';


type CorrectionResume = { name: string, value: string }


class ExerciseCorrectionCommand extends CommanderCommand {
    protected commandName: string = 'correction';

    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')
        .action(this.commandAction.bind(this));
    }

    protected async commandAction(options: { assignment: string }): Promise<void> {
        const assignmentGetSpinner: ora.Ora = ora('Fetching assignment data').start();
        const assignment = await DojoBackendManager.getAssignment(options.assignment);
        if ( !assignment ) {
            assignmentGetSpinner.fail(`The assignment doesn't exists`);
            return;
        }

        if ( assignment.corrections && assignment.corrections.length > 0 ) {
            Config.interactiveMode ? await this.showCorrectionsInteractive(assignment, assignmentGetSpinner) : this.showCorrections(assignment, assignmentGetSpinner);
        } else {
            assignmentGetSpinner.fail(`The assignment doesn't have any corrections yet`);
            return;
        }
    }

    private getCorrections(assignment: Assignment): Array<CorrectionResume> {
        return assignment.corrections.map(correction => {
            return {
                name : correction.name.replace(correction.assignmentName, '').split('-')[2].trim(),
                value: correction.correctionCommit!.web_url?.replace('/commit/', '/tree/') ?? ''
            };
        });
    }

    private showCorrections(assignment: Assignment, spinner: ora.Ora) {
        spinner.succeed(`Here are corrections of the assignment '${ assignment.name }':`);

        this.getCorrections(assignment).forEach(correction => {
            console.log(chalk.green(`- ${ correction.name }`));
            console.log(`  ${ correction.value }`);
        });
    }

    private async showCorrectionsInteractive(assignment: Assignment, spinner: ora.Ora) {
        spinner.stop();

        const correctionUrl: string = (await inquirer.prompt({
                                                                 name   : 'correctionUrl',
                                                                 message: 'Which correction do you want to consult? (use arrow keys then enter)',
                                                                 type   : 'list',
                                                                 choices: this.getCorrections(assignment),
                                                                 default: false
                                                             })).correctionUrl;

        console.log(chalk.green(correctionUrl));

        open(correctionUrl).then();
    }
}


export default new ExerciseCorrectionCommand();
 No newline at end of file
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ class Config {
        neededFiles: Array<string>
    };

    public interactiveMode: boolean;

    constructor() {
        this.localConfig = {
            folder     : getAppDataPath('DojoCLI'),
@@ -62,6 +64,8 @@ class Config {
        this.exercise = {
            neededFiles: JSON.parse(process.env.EXERCISE_NEEDED_FILES || '[]')
        };

        this.interactiveMode = process.env.INTERACTIVE_MODE === 'true';
    }
}

Original line number Diff line number Diff line
@@ -3,25 +3,34 @@ import GitlabManager from '../managers/GitlabManager';


class AccessesHelper {
    async checkStudent(): Promise<boolean> {
    async checkStudent(testGitlab: boolean = false): Promise<boolean> {
        const sessionResult = await SessionManager.testSession(true, [ 'student' ]);

        if ( !sessionResult ) {
            return false;
        }

        if ( testGitlab ) {
            return (await GitlabManager.testToken(true)).every(result => result);
        } else {
            return true;
        }
    }

    async checkTeachingStaff(): Promise<boolean> {
    async checkTeachingStaff(testGitlab: boolean = false): Promise<boolean> {
        const sessionResult = await SessionManager.testSession(true, [ 'teachingStaff' ]);

        if ( !sessionResult || !sessionResult.teachingStaff ) {
            return false;
        }

        if ( testGitlab ) {
            return (await GitlabManager.testToken(true)).every(result => result);
        } else {
            return true;
        }
    }
}


export default new AccessesHelper();
 No newline at end of file
Original line number Diff line number Diff line
@@ -192,6 +192,49 @@ class DojoBackendManager {
            throw error;
        }
    }

    public async linkUpdateCorrection(exerciseIdOrUrl: string, assignment: Assignment, isUpdate: boolean, verbose: boolean = true): Promise<boolean> {
        const spinner: ora.Ora = ora(`${ isUpdate ? 'Updating' : 'Linking' } correction`);

        if ( verbose ) {
            spinner.start();
        }

        try {
            const axiosFunction = isUpdate ? axios.patch : axios.post;
            const route = isUpdate ? ApiRoute.ASSIGNMENT_CORRECTION_UPDATE : ApiRoute.ASSIGNMENT_CORRECTION_LINK;

            await axiosFunction(this.getApiUrl(route).replace('{{assignmentNameOrUrl}}', encodeURIComponent(assignment.name)).replace('{{exerciseIdOrUrl}}', encodeURIComponent(exerciseIdOrUrl)), {
                exerciseIdOrUrl: exerciseIdOrUrl
            });

            if ( verbose ) {
                spinner.succeed(`Correction ${ isUpdate ? 'updated' : 'linked' }`);
            }

            return true;
        } catch ( error ) {
            if ( verbose ) {
                if ( error instanceof AxiosError ) {
                    if ( error.response?.data ) {
                        if ( error.response.data.code === DojoStatusCode.ASSIGNMENT_EXERCISE_NOT_RELATED ) {
                            spinner.fail(`The exercise does not belong to the assignment.`);
                        } else if ( error.response.data.code === DojoStatusCode.EXERCISE_CORRECTION_ALREADY_EXIST ) {
                            spinner.fail(`This exercise is already labelled as a correction. If you want to update it, please use the update command.`);
                        } else if ( error.response.data.code === DojoStatusCode.EXERCISE_CORRECTION_NOT_EXIST ) {
                            spinner.fail(`The exercise is not labelled as a correction so it's not possible to update it.`);
                        }
                    } else {
                        spinner.fail(`Correction ${ isUpdate ? 'update' : 'link' } error: ${ error.response?.statusText }`);
                    }
                } else {
                    spinner.fail(`Correction ${ isUpdate ? 'update' : 'link' } error: ${ error }`);
                }
            }

            return false;
        }
    }
}


Original line number Diff line number Diff line
@@ -38,11 +38,11 @@ class LoginServer {
            if ( req.url?.match(Config.login.server.route) ) {
                const urlParts = req.url.split('=');
                if ( urlParts.length > 0 ) {
                    this.events.emit('code', urlParts[1]);

                    res.writeHead(HttpStatusCode.Ok, { 'Content-Type': 'text/html' });
                    res.write(`<html lang="en"><body><h1 style="color: green">DojoCLI login successful</h1><h3>You can close this window.</h3></body></html>`);
                    res.end();
                    
                    this.events.emit('code', urlParts[1]);
                    return;
                }

@@ -66,6 +66,7 @@ class LoginServer {
    stop() {
        try {
            this.server.close();
            this.server.closeAllConnections();
            this.events.emit('stopped');
        } catch ( error ) {
            this.events.emit('error', error);