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

Merge branch 'v4.2.0'

parents 7cd5f733 ba77e5ee
Branches
Tags
No related merge requests found
Pipeline #33492 canceled
Showing
with 467 additions and 203 deletions
...@@ -350,6 +350,6 @@ Sessionx.vim ...@@ -350,6 +350,6 @@ Sessionx.vim
.netrwhist .netrwhist
*~ *~
# Auto-generated tag files # Auto-generated tag files
tags # tags
# Persistent undo # Persistent undo
[._]*.un~ [._]*.un~
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
url = ../../shared/jetbrains_configuration.git url = ../../shared/jetbrains_configuration.git
[submodule "NodeApp/src/shared"] [submodule "NodeApp/src/shared"]
path = NodeApp/src/shared path = NodeApp/src/shared
url = ../../shared/nodesharedcode.git url = https://gitedu.hesge.ch/dojo_project/projects/shared/nodesharedcode
[submodule "NodeApp/src/sharedByClients"] [submodule "NodeApp/src/sharedByClients"]
path = NodeApp/src/sharedByClients path = NodeApp/src/sharedByClients
url = ../../shared/nodeclientsharedcode.git url = https://gitedu.hesge.ch/dojo_project/projects/shared/nodeclientsharedcode
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/dojocli.iml" filepath="$PROJECT_DIR$/.idea/dojocli.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
- No modifications / Keep major and minors versions in sync with all parts of the project - No modifications / Keep major and minors versions in sync with all parts of the project
--> -->
## 4.2.0 (Upcoming)
### ✨ Feature
- Add support for tags on assignments and exercises
## 4.1.1 (2024-05-28) ## 4.1.1 (2024-05-28)
...@@ -27,7 +32,7 @@ ...@@ -27,7 +32,7 @@
## 4.1.0 (2024-05-28) ## 4.1.0 (2024-05-28)
### ✨ Feature ### ✨ Feature
- Add features related to corrige (commentary, commit specific link / update, delete link) - Add features related to corrige (commentary, commit a specific link / update, delete link)
### 🎨 Interface ### 🎨 Interface
- Ask for confirmation before creating an exercise that already exists - Ask for confirmation before creating an exercise that already exists
......
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
sed -i -r "s/,[\ \n]*\}/\}/g" src/init.ts sed -i -r "s/,[\ \n]*\}/\}/g" src/init.ts
echo "DOTENV_KEY_PRODUCTION=\"${DOTENV_PROD_KEY}\"" > .env.keys echo "DOTENV_KEY_PRODUCTION=\"${DOTENV_PROD_KEY}\"" > .env.keys
npx @dotenvx/dotenvx decrypt npx @dotenvx/dotenvx@0.45.0 decrypt
mv .env.production .env mv .env.production .env
rm .env.keys rm .env.keys
fi fi
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="104e8585:19002424fea:-7ffe" />
</MTProjectMetadataState>
</option>
</component>
</project>
\ No newline at end of file
This diff is collapsed.
{ {
"name" : "dojo_cli", "name" : "dojo_cli",
"description" : "CLI of the Dojo project", "description" : "CLI of the Dojo project",
"version" : "4.1.1", "version" : "4.2.0",
"license" : "AGPLv3", "license" : "AGPLv3",
"author" : "Michaël Minelli <dojo@minelli.me>", "author" : "Michaël Minelli <dojo@mail.minelli.swiss>",
"main" : "dist/app.js", "main" : "dist/app.js",
"bin" : { "bin" : {
"dojo": "./dist/app.js" "dojo": "./dist/app.js"
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
"lint" : "npx eslint .", "lint" : "npx eslint .",
"genversion" : "npx genversion -s -e src/config/Version.ts", "genversion" : "npx genversion -s -e src/config/Version.ts",
"build" : "npm run genversion; npx tsc", "build" : "npm run genversion; npx tsc",
"start:dev" : "npm run genversion; npm run lint; tsc --noEmit && npx tsx src/app.ts", "start:dev" : "npm run genversion; npm run lint; tsc --noEmit && npx tsx --no-warnings src/app.ts",
"test" : "echo \"Error: no test specified\" && exit 1" "test" : "echo \"Error: no test specified\" && exit 1"
}, },
"dependencies" : { "dependencies" : {
"@dotenvx/dotenvx" : "^0.44.1", "@dotenvx/dotenvx" : "^0.45.0",
"@eslint/js" : "^9.3.0", "@eslint/js" : "^9.6.0",
"@gitbeaker/core" : "^40.0.3", "@gitbeaker/core" : "^40.0.3",
"@gitbeaker/requester-utils": "^40.0.3", "@gitbeaker/requester-utils": "^40.0.3",
"@gitbeaker/rest" : "^40.0.3", "@gitbeaker/rest" : "^40.0.3",
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
"axios" : "^1.7.2", "axios" : "^1.7.2",
"boxen" : "^5.1.2", "boxen" : "^5.1.2",
"chalk" : "^4.1.2", "chalk" : "^4.1.2",
"cli-table3" : "^0.6.5",
"commander" : "^12.1.0", "commander" : "^12.1.0",
"form-data" : "^4.0.0", "form-data" : "^4.0.0",
"fs-extra" : "^11.2.0", "fs-extra" : "^11.2.0",
...@@ -55,7 +56,7 @@ ...@@ -55,7 +56,7 @@
"tar-stream" : "^3.1.7", "tar-stream" : "^3.1.7",
"winston" : "^3.13.0", "winston" : "^3.13.0",
"winston-transport" : "^4.7.0", "winston-transport" : "^4.7.0",
"yaml" : "^2.4.2", "yaml" : "^2.4.5",
"zod" : "^3.23.8", "zod" : "^3.23.8",
"zod-validation-error" : "^3.3.0" "zod-validation-error" : "^3.3.0"
}, },
...@@ -63,18 +64,19 @@ ...@@ -63,18 +64,19 @@
"@types/fs-extra" : "^11.0.4", "@types/fs-extra" : "^11.0.4",
"@types/inquirer" : "^8.2.10", "@types/inquirer" : "^8.2.10",
"@types/jsonwebtoken" : "^8.5.9", "@types/jsonwebtoken" : "^8.5.9",
"@types/node" : "^18.19.33", "@types/node" : "^18.19.39",
"@types/semver" : "^7.5.8", "@types/semver" : "^7.5.8",
"@types/tar-stream" : "^3.1.3", "@types/tar-stream" : "^3.1.3",
"@typescript-eslint/eslint-plugin": "^7.11.0", "@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser" : "^7.11.0", "@typescript-eslint/parser" : "^7.15.0",
"dotenv-vault" : "^1.26.1", "dotenv-cli" : "^7.4.2",
"dotenv-vault" : "^1.26.2",
"eslint" : "^8.57.0", "eslint" : "^8.57.0",
"genversion" : "^3.2.0", "genversion" : "^3.2.0",
"pkg" : "^5.8.1", "pkg" : "^5.8.1",
"tiny-typed-emitter" : "^2.1.0", "tiny-typed-emitter" : "^2.1.0",
"tsx" : "^4.11.0", "tsx" : "^4.16.2",
"typescript" : "^5.4.5", "typescript" : "^5.5.3",
"typescript-eslint" : "^7.11.0" "typescript-eslint" : "^7.15.0"
} }
} }
...@@ -13,6 +13,7 @@ import AuthCommand from './auth/AuthCommand.js'; ...@@ -13,6 +13,7 @@ import AuthCommand from './auth/AuthCommand.js';
import SessionCommand from './auth/SessionCommand.js'; import SessionCommand from './auth/SessionCommand.js';
import UpgradeCommand from './UpgradeCommand.js'; import UpgradeCommand from './UpgradeCommand.js';
import TextStyle from '../types/TextStyle.js'; import TextStyle from '../types/TextStyle.js';
import TagCommand from './tag/TagCommand';
class CommanderApp { class CommanderApp {
...@@ -118,6 +119,7 @@ ${ TextStyle.CODE(' dojo upgrade ') }`, { ...@@ -118,6 +119,7 @@ ${ TextStyle.CODE(' dojo upgrade ') }`, {
SessionCommand.registerOnCommand(this.program); SessionCommand.registerOnCommand(this.program);
AssignmentCommand.registerOnCommand(this.program); AssignmentCommand.registerOnCommand(this.program);
ExerciseCommand.registerOnCommand(this.program); ExerciseCommand.registerOnCommand(this.program);
TagCommand.registerOnCommand(this.program);
CompletionCommand.registerOnCommand(this.program); CompletionCommand.registerOnCommand(this.program);
UpgradeCommand.registerOnCommand(this.program); UpgradeCommand.registerOnCommand(this.program);
} }
......
...@@ -33,9 +33,7 @@ class AssignmentCreateCommand extends CommanderCommand { ...@@ -33,9 +33,7 @@ class AssignmentCreateCommand extends CommanderCommand {
private async dataRetrieval(options: CommandOptions) { private async dataRetrieval(options: CommandOptions) {
console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...')); console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...'));
if ( !await AccessesHelper.checkTeachingStaff() ) { await AccessesHelper.checkTeachingStaff();
throw new Error();
}
this.members = await GitlabManager.fetchMembers(options); this.members = await GitlabManager.fetchMembers(options);
if ( !this.members ) { if ( !this.members ) {
......
...@@ -2,6 +2,7 @@ import CommanderCommand from '../CommanderCommand.js'; ...@@ -2,6 +2,7 @@ import CommanderCommand from '../CommanderCommand.js';
import ExerciseCreateCommand from './subcommands/ExerciseCreateCommand.js'; import ExerciseCreateCommand from './subcommands/ExerciseCreateCommand.js';
import ExerciseRunCommand from './subcommands/ExerciseRunCommand.js'; import ExerciseRunCommand from './subcommands/ExerciseRunCommand.js';
import ExerciseCorrectionCommand from './subcommands/ExerciseCorrectionCommand.js'; import ExerciseCorrectionCommand from './subcommands/ExerciseCorrectionCommand.js';
import ExerciseDeleteCommand from './subcommands/ExerciseDeleteCommand';
class ExerciseCommand extends CommanderCommand { class ExerciseCommand extends CommanderCommand {
...@@ -15,6 +16,7 @@ class ExerciseCommand extends CommanderCommand { ...@@ -15,6 +16,7 @@ class ExerciseCommand extends CommanderCommand {
protected defineSubCommands() { protected defineSubCommands() {
ExerciseCreateCommand.registerOnCommand(this.command); ExerciseCreateCommand.registerOnCommand(this.command);
ExerciseRunCommand.registerOnCommand(this.command); ExerciseRunCommand.registerOnCommand(this.command);
ExerciseDeleteCommand.registerOnCommand(this.command);
ExerciseCorrectionCommand.registerOnCommand(this.command); ExerciseCorrectionCommand.registerOnCommand(this.command);
} }
......
...@@ -17,8 +17,8 @@ class ExerciseCorrectionCommand extends CommanderCommand { ...@@ -17,8 +17,8 @@ class ExerciseCorrectionCommand extends CommanderCommand {
protected defineCommand() { protected defineCommand() {
this.command this.command
.description('link an exercise repo as a correction for an assignment') .description('list corrections of an assignment')
.requiredOption('-a, --assignment <string>', 'id or url of the assignment of the correction') .requiredOption('-a, --assignment <string>', 'id or url of the assignment')
.action(this.commandAction.bind(this)); .action(this.commandAction.bind(this));
} }
......
...@@ -33,9 +33,7 @@ class ExerciseCreateCommand extends CommanderCommand { ...@@ -33,9 +33,7 @@ class ExerciseCreateCommand extends CommanderCommand {
private async dataRetrieval(options: CommandOptions) { private async dataRetrieval(options: CommandOptions) {
console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...')); console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...'));
if ( !await AccessesHelper.checkStudent() ) { await AccessesHelper.checkStudent();
throw new Error();
}
this.members = await GitlabManager.fetchMembers(options); this.members = await GitlabManager.fetchMembers(options);
if ( !this.members ) { if ( !this.members ) {
......
import CommanderCommand from '../../CommanderCommand';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper from '../../../helpers/AccessesHelper';
import TextStyle from '../../../types/TextStyle';
class ExerciseDeleteCommand extends CommanderCommand {
protected commandName: string = 'delete';
protected defineCommand(): void {
this.command
.description('delete an exercise')
.argument('id or url', 'id or url of the exercise')
.action(this.commandAction.bind(this));
}
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...'));
await DojoBackendManager.deleteExercise(exerciseIdOrUrl);
}
protected async commandAction(exerciseIdOrUrl: string): Promise<void> {
try {
await this.dataRetrieval();
await this.deleteExercise(exerciseIdOrUrl);
} catch ( e ) { /* Do nothing */ }
}
}
export default new ExerciseDeleteCommand();
import CommanderCommand from '../CommanderCommand';
import TagCreateCommand from './subcommands/TagCreateCommand';
import TagDelete from './subcommands/TagDeleteCommand';
import TagProposalCommand from './subcommands/proposal/TagProposalCommand';
class TagCommand extends CommanderCommand {
protected commandName: string = 'tag';
protected defineCommand() {
this.command
.description('manage tags');
}
protected defineSubCommands() {
TagCreateCommand.registerOnCommand(this.command);
TagDelete.registerOnCommand(this.command);
TagProposalCommand.registerOnCommand(this.command);
}
protected async commandAction(): Promise<void> {
// No action
}
}
export default new TagCommand();
\ No newline at end of file
import CommanderCommand from '../../CommanderCommand';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import { Option } from 'commander';
import TextStyle from '../../../types/TextStyle';
import SessionManager from '../../../managers/SessionManager';
import ora from 'ora';
type CommandOptions = { name: string, type: 'Language' | 'Framework' | 'Theme' | 'UserDefined' }
class TagCreateCommand extends CommanderCommand {
protected commandName: string = 'create';
protected defineCommand() {
this.command
.description('create a new tag')
.requiredOption('-n, --name <name>', 'name of the tag')
.addOption(new Option('-t, --type <type>', 'type of the tag').choices([ 'Language', 'Framework', 'Theme', 'UserDefined' ]).makeOptionMandatory(true))
.action(this.commandAction.bind(this));
}
private async dataRetrieval(options: CommandOptions) {
console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...'));
const sessionResult = await SessionManager.testSession(true, [ 'admin' ]);
if ( !sessionResult ) {
throw new Error();
}
if ( options.type !== 'UserDefined' && !sessionResult.admin ) {
ora({
text : `Only admins can create non UserDefined tags`,
indent: 4
}).start().fail();
throw new Error();
}
}
private async createTag(options: CommandOptions) {
console.log(TextStyle.BLOCK('Please wait while we are creating the tag...'));
const tag = await DojoBackendManager.createTag(options.name, options.type);
if ( !tag ) {
throw new Error();
}
}
protected async commandAction(options: CommandOptions): Promise<void> {
try {
await this.dataRetrieval(options);
await this.createTag(options);
} catch ( e ) { /* Do nothing */ }
}
}
export default new TagCreateCommand();
\ No newline at end of file
import CommanderCommand from '../../CommanderCommand';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import TextStyle from '../../../types/TextStyle';
import AccessesHelper from '../../../helpers/AccessesHelper';
class TagDeleteCommand extends CommanderCommand {
protected commandName: string = 'delete';
protected defineCommand() {
this.command
.description('Delete a tag')
.argument('<name>', 'name of the tag')
.action(this.commandAction.bind(this));
}
private async dataRetrieval() {
console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...'));
await AccessesHelper.checkAdmin();
}
private async deleteTag(name: string) {
console.log(TextStyle.BLOCK('Please wait while we are deleting the tag...'));
if ( !await DojoBackendManager.deleteTag(name) ) {
throw new Error();
}
}
protected async commandAction(name: string): Promise<void> {
try {
await this.dataRetrieval();
await this.deleteTag(name);
} catch ( e ) { /* Do nothing */ }
}
}
export default new TagDeleteCommand();
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment