From 677d512e70c5d9131ae5998d3d6c7598f588e969 Mon Sep 17 00:00:00 2001
From: Joel von der Weid <joel.von-der-weid@hesge.ch>
Date: Tue, 25 Jun 2024 14:41:49 +0200
Subject: [PATCH] Add users to sonar projects and show url

---
 .../subcommands/AssignmentCreateCommand.ts    |  6 ++++-
 .../subcommands/ExerciseCreateCommand.ts      |  8 +++----
 NodeApp/src/helpers/Dojo/ExerciseHelper.ts    |  5 ++++
 NodeApp/src/managers/DojoBackendManager.ts    | 24 ++++++++++---------
 4 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts b/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts
index 3d664d0..44f9e7a 100644
--- a/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts
+++ b/NodeApp/src/commander/assignment/subcommands/AssignmentCreateCommand.ts
@@ -37,7 +37,8 @@ class AssignmentCreateCommand extends CommanderCommand {
             .action(this.commandAction.bind(this));
 
         if ( SharedConfig.sonar.enabled ) {
-            this.command.requiredOption('-s, --sonar', 'add sonar to the code checking process for exercises derived from the assignment')
+            this.command.requiredOption('-s, --sonar', 'add sonar to the code checking process for assignment and exercises')
+                .requiredOption('-d, --no-sonar', 'disable sonar for the code checking process for assignment and exercises')
                 .addOption(new Option('-g, --gate <gate>', 'quality gate for sonar').implies({ sonar: true }))
                 .addOption(new Option('-p, --profile <profile...>', 'quality profiles for sonar').default([]).implies({ sonar: true }));
         }
@@ -138,6 +139,9 @@ class AssignmentCreateCommand extends CommanderCommand {
         oraInfo(`${ TextStyle.LIST_ITEM_NAME('Web URL:') } ${ this.assignment.gitlabCreationInfo.web_url }`);
         oraInfo(`${ TextStyle.LIST_ITEM_NAME('HTTP Repo:') } ${ this.assignment.gitlabCreationInfo.http_url_to_repo }`);
         oraInfo(`${ TextStyle.LIST_ITEM_NAME('SSH Repo:') } ${ this.assignment.gitlabCreationInfo.ssh_url_to_repo }`);
+        if ( this.assignment.useSonar ) {
+            oraInfo(`${ TextStyle.LIST_ITEM_NAME('Sonar project:') } ${ SharedConfig.sonar.url }/dashboard?id=${ this.assignment.sonarKey }`);
+        }
     }
 
     private async cloneRepository(options: CommandOptions) {
diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts
index c354b01..d841e26 100644
--- a/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts
+++ b/NodeApp/src/commander/exercise/subcommands/ExerciseCreateCommand.ts
@@ -80,11 +80,9 @@ class ExerciseCreateCommand extends CommanderCommand {
             const presets: Array<{ name: string, value: CreationChoice } | inquirer.Separator> = [];
 
             for ( const exercise of this.assignment.myExercises ) {
-                oraInfo(`${ TextStyle.LIST_ITEM_NAME('Exercice Id:') } ${ exercise.id }`, 8);
-                oraInfo(`${ TextStyle.LIST_ITEM_NAME('Name:') } ${ exercise.name }`);
-                oraInfo(`${ TextStyle.LIST_ITEM_NAME('Creation date:') } ${ exercise.gitlabCreationInfo.created_at }`);
-                oraInfo(`${ TextStyle.LIST_ITEM_NAME('Repository:') } ${ exercise.gitlabCreationInfo.web_url }`);
-                oraInfo(`${ TextStyle.LIST_ITEM_NAME('Members:') } ${ exercise.members?.map(member => member.gitlabUsername).join(', ') ?? 'There is only you' }`);
+                exercise.assignment = this.assignment;
+
+                await ExerciseHelper.displayDetails(exercise, false);
 
                 presets.push({
                                  name : `Delete "${ exercise.name }" and create a new one.`,
diff --git a/NodeApp/src/helpers/Dojo/ExerciseHelper.ts b/NodeApp/src/helpers/Dojo/ExerciseHelper.ts
index 9edd5a4..5871b47 100644
--- a/NodeApp/src/helpers/Dojo/ExerciseHelper.ts
+++ b/NodeApp/src/helpers/Dojo/ExerciseHelper.ts
@@ -4,6 +4,7 @@ import TextStyle          from '../../types/TextStyle';
 import inquirer           from 'inquirer';
 import Config             from '../../config/Config';
 import DojoBackendManager from '../../managers/DojoBackendManager';
+import SharedConfig       from '../../shared/config/SharedConfig';
 
 
 class ExerciseHelper {
@@ -126,6 +127,10 @@ class ExerciseHelper {
                 }).start().warn();
         }
 
+        if ( exercise.assignment?.useSonar ) {
+            oraInfo(`${ TextStyle.LIST_ITEM_NAME('Sonar project:') } ${ SharedConfig.sonar.url }/dashboard?id=${ exercise.sonarKey }`);
+        }
+
         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 }`);
diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts
index 939e684..4250f67 100644
--- a/NodeApp/src/managers/DojoBackendManager.ts
+++ b/NodeApp/src/managers/DojoBackendManager.ts
@@ -153,6 +153,9 @@ class DojoBackendManager {
                     case DojoStatusCode.ASSIGNMENT_NAME_CONFLICT:
                         spinner.fail(`Assignment creation error: The assignment name already exists. Please choose another name.`);
                         break;
+                    case DojoStatusCode.ASSIGNMENT_CREATION_SONAR_MEMBER:
+                        spinner.fail(`All members of the project must connect at least one time to SonarQube with their Gitlab Id.\nURL: ${ SharedConfig.sonar.url }/`);
+                        break;
                     case DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR:
                         spinner.fail(`Assignment creation error: An unknown error occurred while creating the assignment on GitLab (internal error message: ${ error.response?.data?.description ?? unknownErrorMessage }). Please try again later or contact an administrator.`);
                         break;
@@ -256,12 +259,12 @@ class DojoBackendManager {
 
         try {
             const response = await axios.post<DojoBackendResponse<Assignment>>(DojoBackendHelper.getApiUrl(ApiRoute.ASSIGNMENT_CREATE), Object.assign({
-                                                                                                                                                          name    : name,
-                                                                                                                                                          language: language,
-                                                                                                                                                          members : JSON.stringify(members),
-                                                                                                                                                          useSonar: String(sonar),
-                                                                                                                                                          sonarGate: sonarGate ?? '',
-                                                                                                                                                          sonarProfiles : JSON.stringify(sonarProfiles),
+                                                                                                                                                          name         : name,
+                                                                                                                                                          language     : language,
+                                                                                                                                                          members      : JSON.stringify(members),
+                                                                                                                                                          useSonar     : String(sonar),
+                                                                                                                                                          sonarGate    : sonarGate ?? '',
+                                                                                                                                                          sonarProfiles: JSON.stringify(sonarProfiles)
                                                                                                                                                       }, templateIdOrNamespace ? { template: templateIdOrNamespace } : {}));
 
             if ( verbose ) {
@@ -394,11 +397,10 @@ class DojoBackendManager {
     }
 
     public async testSonarQualities(gate: string, profiles: string[]) {
-        const resp = await axios.post<DojoBackendResponse<{ valid: boolean, badProfiles: string[], badGate: string | undefined }>>(
-            this.getApiUrl(ApiRoute.SONAR_QUALITIES), {
-                gate: gate,
-                profiles: profiles,
-            });
+        const resp = await axios.post<DojoBackendResponse<{ valid: boolean, badProfiles: string[], badGate: string | undefined }>>(DojoBackendHelper.getApiUrl(ApiRoute.SONAR_QUALITIES), {
+            gate    : gate,
+            profiles: profiles
+        });
         return resp.data.data;
     }
 
-- 
GitLab