diff --git a/AngularApp/angular.json b/AngularApp/angular.json index 605d3d4976c29e27e6611cf8507f271556b7b223..d4de230a00794833618ec2bc7853468ca7111860 100644 --- a/AngularApp/angular.json +++ b/AngularApp/angular.json @@ -1,183 +1,182 @@ { - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "material-dashboard-angular": { - "root": "", - "sourceRoot": "src", - "projectType": "application", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist", - "index": "src/index.html", - "main": "src/main.ts", - "tsConfig": "src/tsconfig.app.json", - "polyfills": "src/polyfills.ts", - "assets": [ - "src/assets", - "src/favicon.ico" - ], - "styles": [ - "node_modules/perfect-scrollbar/css/perfect-scrollbar.css", - "src/assets/scss/material-dashboard.scss", - "src/assets/css/demo.css" - ], - "scripts": [ - "node_modules/jquery/dist/jquery.js", - "node_modules/popper.js/dist/umd/popper.js", - "node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js", - "node_modules/arrive/src/arrive.js", - "node_modules/moment/moment.js", - "node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js", - "node_modules/bootstrap-notify/bootstrap-notify.js", - "node_modules/chartist/dist/chartist.js" - ], - "allowedCommonJsDependencies": [ - "rxjs/add/operator/filter", - "jquery", - "chartist" - ] - }, - "configurations": { - "production": { - "optimization": { - "scripts": true, - "styles": { - "minify": false, - "inlineCritical": false + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "material-dashboard-angular": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist", + "index": "src/index.html", + "main": "src/main.ts", + "tsConfig": "src/tsconfig.app.json", + "polyfills": "src/polyfills.ts", + "assets": [ + "src/assets", + "src/favicon.ico" + ], + "styles": [ + "node_modules/@fortawesome/fontawesome-free/css/all.min.css", + "node_modules/perfect-scrollbar/css/perfect-scrollbar.css", + "src/assets/scss/material-dashboard.scss", + "src/assets/css/demo.css" + ], + "scripts": [ + "node_modules/jquery/dist/jquery.js", + "node_modules/popper.js/dist/umd/popper.js", + "node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js", + "node_modules/arrive/src/arrive.js", + "node_modules/moment/moment.js", + "node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js", + "node_modules/bootstrap-notify/bootstrap-notify.js", + "node_modules/chartist/dist/chartist.js" + ], + "allowedCommonJsDependencies": [ + "rxjs/add/operator/filter", + "jquery", + "chartist" + ] + }, + "configurations": { + "production": { + "optimization": { + "scripts": true, + "styles": { + "minify": false, + "inlineCritical": false + }, + "fonts": true + }, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "fileReplacements": [{ + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + }] + }, + "development": { + "vendorChunk": true, + "extractLicenses": false, + "namedChunks": true, + "buildOptimizer": false, + "sourceMap": true, + "optimization": { + "scripts": true, + "styles": { + "minify": false, + "inlineCritical": true + }, + "fonts": true + }, + "outputHashing": "all" + } + } }, - "fonts": true - }, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ] - }, - "development": { - "vendorChunk": true, - "extractLicenses": false, - "namedChunks": true, - "buildOptimizer": false, - "sourceMap": true, - "optimization": { - "scripts": true, - "styles": { - "minify": false, - "inlineCritical": true + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "material-dashboard-angular:build" + }, + "configurations": { + "production": { + "browserTarget": "material-dashboard-angular:build:production" + }, + "development": { + "browserTarget": "material-dashboard-angular:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "material-dashboard-angular:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "karmaConfig": "./karma.conf.js", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "scripts": [ + "node_modules/jquery/dist/jquery.js", + "node_modules/popper.js/dist/umd/popper.js", + "node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js", + "node_modules/arrive/src/arrive.js", + "node_modules/moment/moment.js", + "node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js", + "node_modules/bootstrap-notify/bootstrap-notify.js", + "node_modules/chartist/dist/chartist.js" + ], + "styles": [ + "node_modules/perfect-scrollbar/css/perfect-scrollbar.css", + "src/assets/scss/material-dashboard.scss", + "src/assets/css/demo.css" + ], + "assets": [ + "src/assets", + "src/favicon.ico" + ] + } }, - "fonts": true - }, - "outputHashing": "all" + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [] + } + } } - } }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "options": { - "browserTarget": "material-dashboard-angular:build" - }, - "configurations": { - "production": { - "browserTarget": "material-dashboard-angular:build:production" - }, - "development": { - "browserTarget": "material-dashboard-angular:build:development" + "material-dashboard-angular-e2e": { + "root": "", + "sourceRoot": "", + "projectType": "application", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "./protractor.conf.js", + "devServerTarget": "material-dashboard-angular:serve" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "e2e/tsconfig.e2e.json" + ], + "exclude": [] + } + } } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "material-dashboard-angular:build" - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "src/test.ts", - "karmaConfig": "./karma.conf.js", - "polyfills": "src/polyfills.ts", - "tsConfig": "src/tsconfig.spec.json", - "scripts": [ - "node_modules/jquery/dist/jquery.js", - "node_modules/popper.js/dist/umd/popper.js", - "node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js", - "node_modules/arrive/src/arrive.js", - "node_modules/moment/moment.js", - "node_modules/perfect-scrollbar/dist/perfect-scrollbar.min.js", - "node_modules/bootstrap-notify/bootstrap-notify.js", - "node_modules/chartist/dist/chartist.js" - ], - "styles": [ - "node_modules/perfect-scrollbar/css/perfect-scrollbar.css", - "src/assets/scss/material-dashboard.scss", - "src/assets/css/demo.css" - ], - "assets": [ - "src/assets", - "src/favicon.ico" - ] - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "src/tsconfig.app.json", - "src/tsconfig.spec.json" - ], - "exclude": [] - } } - } }, - "material-dashboard-angular-e2e": { - "root": "", - "sourceRoot": "", - "projectType": "application", - "architect": { - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "./protractor.conf.js", - "devServerTarget": "material-dashboard-angular:serve" - } + "defaultProject": "material-dashboard-angular", + "schematics": { + "@schematics/angular:component": { + "prefix": "app", + "style": "scss" }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": [ - "e2e/tsconfig.e2e.json" - ], - "exclude": [] - } + "@schematics/angular:directive": { + "prefix": "app" } - } - } - }, - "defaultProject": "material-dashboard-angular", - "schematics": { - "@schematics/angular:component": { - "prefix": "app", - "style": "scss" }, - "@schematics/angular:directive": { - "prefix": "app" + "cli": { + "analytics": false } - }, - "cli": { - "analytics": false - } } \ No newline at end of file diff --git a/AngularApp/package-lock.json b/AngularApp/package-lock.json index be1c76789341ef10f3c39ca3377e43dcb73d7f2e..e23ea78c4b76c9799a038b984bed43d88af284bf 100644 --- a/AngularApp/package-lock.json +++ b/AngularApp/package-lock.json @@ -21,6 +21,7 @@ "@angular/platform-browser": "^14.2.0", "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.3.0", + "@fortawesome/fontawesome-free": "^6.5.1", "ajv": "8.11.0", "arrive": "2.4.1", "bootstrap": "4.6.1", @@ -2986,6 +2987,15 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.1.tgz", + "integrity": "sha512-CNy5vSwN3fsUStPRLX7fUYojyuzoEMSXPl7zSLJ8TgtRfjv24LOnOWKT2zYwaHZCJGkdyRnTmstR0P+Ah503Gw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", diff --git a/AngularApp/package.json b/AngularApp/package.json index 312bcd5c883012b1c147fbc386b826ef077547c2..b36b5772496975c1d3f0896fd0d0c32b732eb49b 100644 --- a/AngularApp/package.json +++ b/AngularApp/package.json @@ -29,6 +29,7 @@ "@angular/platform-browser": "^14.2.0", "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.3.0", + "@fortawesome/fontawesome-free": "^6.5.1", "ajv": "8.11.0", "arrive": "2.4.1", "bootstrap": "4.6.1", diff --git a/AngularApp/src/app/assignment.service.ts b/AngularApp/src/app/assignment.service.ts deleted file mode 100644 index f57ec41c3eb53c92c082f7ebf284a89fc1e844c0..0000000000000000000000000000000000000000 --- a/AngularApp/src/app/assignment.service.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { Assignment } from './model/assignment'; - - - -@Injectable({ - providedIn: 'root' -}) -export class AssignmentService { - private baseUrl = 'http://localhost:3000'; - - constructor(private http: HttpClient) {} - - getAssignment(): Observable<Assignment[]> { - return this.http.get<Assignment[]>(`${this.baseUrl}/assignments`); - } - getAssignmentTitles(): Observable<string[]> { - return this.http.get<string[]>(`${this.baseUrl}/assignments/name`); - } -} diff --git a/AngularApp/src/app/components/navbar/navbar.component.ts b/AngularApp/src/app/components/navbar/navbar.component.ts index 7824a5c10f6b4b6879bf65bb79ffc3f93eed48ed..9057e99dea4baed5da1ba03e4bd439d4fd456012 100644 --- a/AngularApp/src/app/components/navbar/navbar.component.ts +++ b/AngularApp/src/app/components/navbar/navbar.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, ElementRef } from '@angular/core'; import { ROUTES } from '../sidebar/sidebar.component'; import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common'; import { Router } from '@angular/router'; -import { AuthService} from "../../auth_service"; +import { AuthService} from "../../../services/auth_service"; @Component({ selector: 'app-navbar', diff --git a/AngularApp/src/app/create-exercise/create-exercise.component.ts b/AngularApp/src/app/create-exercise/create-exercise.component.ts index ba4a3d676539d5eb0ffbebd47284637df0a92b00..2ebcd4e4aac027c4911834bb841572459e8f7729 100644 --- a/AngularApp/src/app/create-exercise/create-exercise.component.ts +++ b/AngularApp/src/app/create-exercise/create-exercise.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; -import { AssignmentService } from 'app/assignment.service'; +import { AssignmentService } from 'services/assignment.service'; import { Assignment } from '../model/assignment'; -import { ExerciseService } from 'app/exercise.service'; +import { ExerciseService } from 'services/exercise.service'; import { Exercise } from 'app/model/exercise'; @@ -20,7 +20,7 @@ export class CreateExerciseComponent implements OnInit { ngOnInit(): void { // Récupérer la liste des assignments lors de l'initialisation du composant - this.assignmentService.getAssignment().subscribe(assignments => { + this.assignmentService.getAssignments().subscribe(assignments => { this.assignments = assignments; }); } diff --git a/AngularApp/src/app/exercise-details/exercise-details.component.html b/AngularApp/src/app/exercise-details/exercise-details.component.html index 2eeb03cf17a868c32bb27f908452ab650f03452b..d2ed56fc52fd728c49b8ab241bfb8ea5a4088884 100644 --- a/AngularApp/src/app/exercise-details/exercise-details.component.html +++ b/AngularApp/src/app/exercise-details/exercise-details.component.html @@ -34,6 +34,38 @@ <label for="gitlabLink">Lien GitLab :</label> <input type="text" id="gitlabLink" name="gitlabLink" [(ngModel)]="exercise.gitlabLink" class="form-control" readonly> </div> + + <div *ngIf="results && results.length > 0" class="form-group"> + <h5>Résultats de l'exercice :</h5> + <ul> + <li *ngFor="let result of results"> + <p>Date et heure : {{ result.dateTime | date: 'medium' }}</p> + <p>Résultats :</p> + <ul> + <li>Tests réussis : {{ result.results.successfulTests }}</li> + <li>Tests échoués : {{ result.results.failedTests }}</li> + <li>Liste des tests réussis : + <ul> + <li *ngFor="let test of result.results.successfulTestsList"> + {{ test }} <i class="fas fa-check-circle text-success"></i> + </li> + </ul> + </li> + <li>Liste des tests échoués : + <ul> + <li *ngFor="let test of result.results.failedTestsList"> + {{ test }} <i class="fas fa-times-circle text-danger"></i> + </li> + </ul> + </li> + </ul> + <hr> + </li> + </ul> + </div> + <div *ngIf="!results || results.length === 0" class="form-group"> + <p>Aucun résultat disponible pour cet exercice.</p> + </div> </form> </div> diff --git a/AngularApp/src/app/exercise-details/exercise-details.component.ts b/AngularApp/src/app/exercise-details/exercise-details.component.ts index 2f3e2c330dfbab1bc5ce6e1d24097a5a4399ffe2..20d9c9ada36b4a37c5f3668894c8685a2e5bcf2d 100644 --- a/AngularApp/src/app/exercise-details/exercise-details.component.ts +++ b/AngularApp/src/app/exercise-details/exercise-details.component.ts @@ -2,8 +2,9 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { ExerciseService } from 'app/exercise.service'; +import { ExerciseService } from 'services/exercise.service'; import { Exercise } from 'app/model/exercise'; +import { Result } from 'app/model/result'; @Component({ selector: 'app-exercise-details', @@ -13,6 +14,8 @@ import { Exercise } from 'app/model/exercise'; export class ExerciseDetailsComponent implements OnInit { exerciseId: string; exercise: Exercise; + results: Result[]; + res: []; constructor(private route: ActivatedRoute, private exerciseService: ExerciseService) { } @@ -31,5 +34,28 @@ export class ExerciseDetailsComponent implements OnInit { } ); } + this.loadResults(); + + } + loadResults(): void { + this.exerciseService.getResults().subscribe( + data => { + this.results = data.map(result => { + // Convertir les champs JSON encodés en objets JavaScript + result.results = JSON.parse(result.results); + return result; + }); + + // Afficher les résultats + if (this.results && this.results.length > 0) { + this.results.forEach(result => { + console.log('Results :', result.results); + }); + } + }, + error => { + console.error('Erreur lors de la récupération des résultats :', error); + } + ); } } diff --git a/AngularApp/src/app/exercise.service.ts b/AngularApp/src/app/exercise.service.ts deleted file mode 100644 index 9e0acdef0bf99af1ca03fda0d26b18cca6771144..0000000000000000000000000000000000000000 --- a/AngularApp/src/app/exercise.service.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { Exercise } from './model/exercise'; -import { Assignment } from './model/assignment'; - -@Injectable({ - providedIn: 'root' -}) -export class ExerciseService { - private baseUrl = 'http://localhost:3000'; - - constructor(private http: HttpClient) {} - - getExercises(): Observable<Exercise[]> { - return this.http.get<Exercise[]>(`${this.baseUrl}/exercises`); - } - - - getAssignments(): Observable<Assignment[]> { - return this.http.get<Assignment[]>(`${this.baseUrl}/assignments`); - } - - getExercisesByAssignmentName(assignmentName: string): Observable<Exercise[]> { - return this.http.get<Exercise[]>(`${this.baseUrl}/exercises?assignmentName=${assignmentName}`); - } - - getExerciseById(id: string): Observable<Exercise> { - console.log('ID de l\'exercice demandé :', id); - - return this.http.get<Exercise>(`${this.baseUrl}/exercises/${id}`); -} - - getExercisesByName(name: string): Observable<Exercise[]> { - // Utilisez HttpParams pour ajouter le paramètre de filtrage par nom - const params = new HttpParams().set('name', name); - - // Utilisez les paramètres dans la requête HTTP - return this.http.get<Exercise[]>(`${this.baseUrl}/exercises`, { params }); - } - // Méthode pour créer un nouvel exercice - createExercise(exercise: Exercise): Observable<any> { - return this.http.post(`${this.baseUrl}/exercises`, exercise); - } -} diff --git a/AngularApp/src/app/exercise/exercise.component.ts b/AngularApp/src/app/exercise/exercise.component.ts index 08eddf248c364a4d6f9cce00f0491ac6bf12e7e1..8cd6ce2ee7c413e5205be8e2136854d1fcbd54e6 100644 --- a/AngularApp/src/app/exercise/exercise.component.ts +++ b/AngularApp/src/app/exercise/exercise.component.ts @@ -1,7 +1,7 @@ // exercises.component.ts import { Component, OnInit } from '@angular/core'; -import {ExerciseService} from "../exercise.service"; +import {ExerciseService} from "../../services/exercise.service"; @Component({ selector: 'app-exercises', diff --git a/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.css b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.html b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.html new file mode 100644 index 0000000000000000000000000000000000000000..08092ab3ba54b025dea99cff14041a9b8533310f --- /dev/null +++ b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.html @@ -0,0 +1,38 @@ +<div class="main-content"> + <div class="container-fluid"> + <div class="row"> + <div class="col-md-12"> + <div class="card"> + <div class="card-header card-header-danger"> + <h4 class="card-title">Liste des exercices pour {{ assignmentName }}</h4> + </div> + <div class="card-body"> + <div class="table-responsive"> + <table class="table"> + <thead class="text-primary"> + <tr> + <th>Nom de l'Exercice</th> + <th>Lien Gitlab</th> + <th>Détails</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let exercise of exercises"> + <td>{{ exercise.name }}</td> + <td>{{ exercise.gitlabLink }}</td> + <td> + <a [routerLink]="['/exercise-details', exercise.id]"> + <i class="fa fa-eye"></i> + </a> + </td> + + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.spec.ts b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d0ae3e3d170a043e760929f27e861cdbba1a9e9 --- /dev/null +++ b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ExerciseFromAssign } from './exercise_from_assign.component'; + +describe('DetailExerciseComponent', () => { + let component: ExerciseFromAssign; + let fixture: ComponentFixture<ExerciseFromAssign>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ExerciseFromAssign ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ExerciseFromAssign); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.ts b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..19b4238ab0075ce6415a19054704e0eda7a42b0e --- /dev/null +++ b/AngularApp/src/app/exercise_from_assign/exercise_from_assign.component.ts @@ -0,0 +1,31 @@ +// exercise.component.ts +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Exercise } from 'app/model/exercise'; +import { ExerciseService } from 'services/exercise.service'; + + +@Component({ + selector: 'app-exercise-from-assign', + templateUrl: './exercise_from_assign.component.html', + styleUrls: ['./exercise_from_assign.component.css'] +}) +export class ExerciseFromAssign implements OnInit { + assignmentName: string; + exercises: Exercise[]; + + constructor(private route: ActivatedRoute, private exerciseService: ExerciseService) { } + + ngOnInit(): void { + this.route.paramMap.subscribe(params => { + this.assignmentName = params.get('assignmentName'); + this.getExercisesByAssignmentName(this.assignmentName); + }); + } + + getExercisesByAssignmentName(assignmentName: string): void { + this.exerciseService.getExercisesByAssignmentName(assignmentName).subscribe(exercises => { + this.exercises = exercises; + }); + } +} \ No newline at end of file diff --git a/AngularApp/src/app/layouts/admin-layout/admin-layout.routing.ts b/AngularApp/src/app/layouts/admin-layout/admin-layout.routing.ts index 8d6cade52392e9061c507f5140a64fec51a043df..80ac8e990cd436c2adc4c15312415ffbb93038ad 100644 --- a/AngularApp/src/app/layouts/admin-layout/admin-layout.routing.ts +++ b/AngularApp/src/app/layouts/admin-layout/admin-layout.routing.ts @@ -13,6 +13,8 @@ import {LoginComponent} from "../../login/login.component"; import { ExerciseComponent } from 'app/exercise/exercise.component'; import { ListExerciseComponent } from 'app/list-exercise/list-exercise.component'; import { CreateExerciseComponent } from 'app/create-exercise/create-exercise.component'; +import { ExerciseFromAssign } from 'app/exercise_from_assign/exercise_from_assign.component'; +import { ExerciseDetailsComponent } from 'app/exercise-details/exercise-details.component'; export const AdminLayoutRoutes: Routes = [ { path: 'dashboard', component: DashboardComponent }, @@ -24,8 +26,10 @@ export const AdminLayoutRoutes: Routes = [ { path: 'maps', component: MapsComponent }, { path: 'notifications', component: NotificationsComponent }, { path: 'exercise-page', component: ExercisePageComponent }, + { path :'exercise_from_assign/:assignmentName', component : ExerciseFromAssign}, { path: 'upgrade', component: UpgradeComponent }, { path: 'exercise', component: ExerciseComponent }, + { path : 'exercise-details/:id', component:ExerciseDetailsComponent } diff --git a/AngularApp/src/app/list-exercise/list-exercise.component.ts b/AngularApp/src/app/list-exercise/list-exercise.component.ts index 0df7bfd2a75c2e86dcfe9e58fda5ef2564a2153a..eb8b5093e67ae0445ed17e7af2ab9aefa58b5365 100644 --- a/AngularApp/src/app/list-exercise/list-exercise.component.ts +++ b/AngularApp/src/app/list-exercise/list-exercise.component.ts @@ -1,10 +1,10 @@ // exercise.component.ts import { Component, OnInit } from '@angular/core'; -import { ExerciseService } from 'app/exercise.service'; +import { ExerciseService } from 'services/exercise.service'; import { Exercise } from 'app/model/exercise'; import { Assignment } from 'app/model/assignment'; -import { AssignmentService } from 'app/assignment.service'; +import { AssignmentService } from 'services/assignment.service'; @@ -22,18 +22,18 @@ export class ListExerciseComponent implements OnInit { constructor( private exerciseService: ExerciseService, - private assignmentService: AssignmentService // Injectez le service d'assignation + private assignmentService: AssignmentService ) {} ngOnInit(): void { - // Récupérer la liste des exercices lors de l'initialisation du composant + this.exerciseService.getExercises().subscribe(exercises => { this.exercises = exercises; this.filteredExercises = this.exercises; }); // Récupérer la liste des noms d'assignation lors de l'initialisation du composant - this.assignmentService.getAssignment().subscribe(assignments => { + this.assignmentService.getAssignments().subscribe(assignments => { this.assignmentNames = assignments.map(assignment => assignment.name); }); } diff --git a/AngularApp/src/app/login/login.component.ts b/AngularApp/src/app/login/login.component.ts index bf549286e4d51bcbef25d572939646d1951c12e7..d2943cdd22abc451ba8b61d43df502ccf1cce05c 100644 --- a/AngularApp/src/app/login/login.component.ts +++ b/AngularApp/src/app/login/login.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { AuthService } from "../auth_service"; +import { AuthService } from "../../services/auth_service"; import { ActivatedRoute } from '@angular/router'; @Component({ @@ -20,7 +20,9 @@ export class LoginComponent implements OnInit { console.log('Code d\'autorisation récupéré :', code); this.authService.exchangeCodeForToken(code); const accessToken = this.authService.getAccessToken(); + const refresh_token = this.authService.getRefreshToken(); console.log('Access token dans LoginComponent :', accessToken); + console.log('Refresh token dans LoginComponent :', refresh_token); } else { console.log('Aucun code d\'autorisation trouvé dans les queryParams.'); } diff --git a/AngularApp/src/app/model/assignment.ts b/AngularApp/src/app/model/assignment.ts index 399e1a66fe73c5dd318c03e201f5b196c1b8bf1f..e401fff5f447b0b7fa016672d43b949570c416b0 100644 --- a/AngularApp/src/app/model/assignment.ts +++ b/AngularApp/src/app/model/assignment.ts @@ -1,5 +1,8 @@ export interface Assignment { name : string, - description : string, - language : string -} + gitLabId: string, + gitlabCreationInfo : string, + gitlabLastInfo : string, + gitlabLink : string, + gitlabLastInfoDate : string, +} \ No newline at end of file diff --git a/AngularApp/src/app/model/result.ts b/AngularApp/src/app/model/result.ts new file mode 100644 index 0000000000000000000000000000000000000000..b35cf2ab505e38fe9b2cdec420f7c32de940cd9a --- /dev/null +++ b/AngularApp/src/app/model/result.ts @@ -0,0 +1,9 @@ +export interface Result { + exerciseId: string; + dateTime: string; + commit: any; + exitCode: number; + files: any; + results: any; + success: boolean; +} diff --git a/AngularApp/src/app/table-list/table-list.component.html b/AngularApp/src/app/table-list/table-list.component.html index f0cef1a341cadd0b4a69926472b46c17f6755d5b..f3f5ef705d790e8c60391ae8b8c48f63fa22c8d6 100644 --- a/AngularApp/src/app/table-list/table-list.component.html +++ b/AngularApp/src/app/table-list/table-list.component.html @@ -5,28 +5,44 @@ <div class="card"> <div class="card-header card-header-danger"> <h4 class="card-title ">Assignments</h4> - <p class="card-category"> Here is a subtitle for this table</p> </div> <div class="card-body"> <div class="table-responsive"> <table class="table"> <thead class=" text-primary"> - <th *ngFor="let h of headers"> - {{h}} - </th> + <tr> + <th *ngFor="let h of headers"> + {{h}} + </th> + + </tr> </thead> <tbody> - <tr *ngFor="let row of rows"> - <td *ngFor="let h of headers"> - <a ng-href="#/{{row['link']}}">{{row[h]}}</a> - </td> - </tr> + <tr *ngFor="let assignment of assignments"> + <td> + <a *ngIf="assignment.published === 1" [routerLink]="['/exercise_from_assign', assignment.name]"> + <i class="fa fa-eye"></i> + </a> + <ng-container *ngIf="assignment.published !== 1"> + <i class="fa fa-eye" (click)="showUnpublishedPopup()"></i> + </ng-container> + </td> + <td>{{assignment.name}}</td> + <td>{{assignment.gitlabCreationInfo.description}}</td> + <td>{{assignment.gitlabCreationInfo.created_at | date:"dd MMM yyyy 'at' hh:mm"}}</td> + <td>{{assignment.gitlabLink}}</td> + <td>{{assignment.published === 1 ? 'Published' : 'Unpublished'}}</td> + <td> + <button class="btn btn-outline-danger" (click)="delAssignment(assignment.gitlabId)">Delete</button> + </td> + </tr> </tbody> </table> + <h1>{{ delStatus }}</h1> </div> </div> </div> </div> </div> </div> -</div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/table-list/table-list.component.ts b/AngularApp/src/app/table-list/table-list.component.ts index 699fb9f4fe97851fb1a98801489785391f685545..420d9570656c025a93a2ef7c843dda3a460d3e7e 100644 --- a/AngularApp/src/app/table-list/table-list.component.ts +++ b/AngularApp/src/app/table-list/table-list.component.ts @@ -1,4 +1,8 @@ import { Component, OnInit } from '@angular/core'; +import { Assignment } from 'app/model/assignment'; +import { AssignmentService } from 'services/assignment.service'; +import { DatePipe } from '@angular/common'; + @Component({ selector: 'app-table-list', @@ -6,35 +10,40 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./table-list.component.css'] }) export class TableListComponent implements OnInit { + assignments : Assignment[] = [] + data : [] = [] + formattedDate : string + delStatus : string; + headers : string[] = ['Exercise Created', 'Name', 'Description', 'Creation date', 'gitlabLink', 'Status','Options']; + + constructor(private service : AssignmentService) { } + - constructor() { } - - headers : string[] = ['Assignment', 'Description', 'Number of success', 'Exercises created']; - rows = [ - { - 'Assignment' : 'TCP', - 'Description' : 'Technique de compilation', - 'Number of success' : '2', - 'Exercises created' : '4', - 'Link' : 'exercise-page' - }, - { - 'Assignment' : 'Optimisation', - 'Description' : 'Do some optimisation', - 'Number of success' : '2', - 'Exercises created' : '4', - 'Link' : '' - }, - { - 'Assignment' : 'Advanced Programmation', - 'Description' : 'Some programmation', - 'Number of success' : '0', - 'Exercises created' : '10', - 'Link' : '' - }, - ]; + delAssignment(id: number) { + console.log(id); + this.service.delAssignments(id).subscribe( + () => { + this.delStatus = 'Delete successful'; + }, + (error) => { + console.error('Error deleting assignment:', error); + this.delStatus = 'Delete failed'; + } + ); + } ngOnInit() { + this.service.getAssignments().subscribe((assignment) => { + this.assignments = assignment + for (let i = 0; i < this.assignments.length; i++) { + this.assignments[i].gitlabCreationInfo = JSON.parse(assignment[i].gitlabCreationInfo) + this.assignments[i].gitlabLastInfo = JSON.parse(assignment[i].gitlabLastInfo) + } + console.log(this.assignments[0].gitlabCreationInfo) + }) } + showUnpublishedPopup() { + alert('Aucun Exercice utilise cet énoncé car il n\'est pas publié.'); +} } diff --git a/AngularApp/src/services/api.service.spec.ts b/AngularApp/src/services/api.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0310ae68257073a88a5d5d84c69a673a6864b32 --- /dev/null +++ b/AngularApp/src/services/api.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ApiService } from './api.service'; + +describe('ApiService', () => { + let service: ApiService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ApiService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/services/api.service.ts b/AngularApp/src/services/api.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..94404c205e559e45473f0708323a55b0b380f103 --- /dev/null +++ b/AngularApp/src/services/api.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { AuthService } from './auth_service'; + +@Injectable({ + providedIn: 'root' +}) +export class ApiService { + + constructor(private http: HttpClient, private authService: AuthService) { } + + fetchData(): void { + const accessToken = this.authService.getAccessToken(); + if (accessToken) { + const headers = new HttpHeaders({ + 'Authorization': `Bearer ${accessToken}` + }); + this.http.get<any>('http://0.0.0.0:30993', { headers }).subscribe( + response => { + console.log('Données récupérées avec succès :', response); + }, + error => { + console.error('Erreur lors de la récupération des données :', error); + } + ); + } else { + console.error('Access token non disponible.'); + } + } +} \ No newline at end of file diff --git a/AngularApp/src/app/assignment.service.spec.ts b/AngularApp/src/services/assignment.service.spec.ts similarity index 100% rename from AngularApp/src/app/assignment.service.spec.ts rename to AngularApp/src/services/assignment.service.spec.ts diff --git a/AngularApp/src/services/assignment.service.ts b/AngularApp/src/services/assignment.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..39a3b45d896f63e892a1efb496741a8c68c8f25f --- /dev/null +++ b/AngularApp/src/services/assignment.service.ts @@ -0,0 +1,50 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Assignment } from 'app/model/assignment'; +import { Observable } from 'rxjs'; +import { AuthService } from './auth_service'; + +@Injectable({ + providedIn: 'root' +}) + +export class AssignmentService { + private baseUrl = 'http://localhost:3000'; + + constructor(private http: HttpClient) {} + + getAssignments(): Observable<Assignment[]> { + return this.http.get<Assignment[]>(`${this.baseUrl}/assignments`); + } + + delAssignments(id: number): Observable<any> { + const url = `${this.baseUrl}/assignments/${id}`; + return this.http.delete(url); + } +} + + + + + +/* export class AssignmentService { + private baseUrl = 'http://0.0.0.0:30993'; + + constructor(private http: HttpClient, private authService: AuthService) {} + + setAccessToken(token: string): void { + this.authService.setAccessToken(token); + } + + getAssignments(): Observable<Assignment[]> { + const token = this.authService.getAccessToken(); + const headers = { Authorization: `Bearer ${token}` }; + return this.http.get<Assignment[]>(`${this.baseUrl}/assignments`, { headers }); + } + + delAssignments(id: number): Observable<any> { + const url = `${this.baseUrl}/assignments/${id}`; + return this.http.delete(url); + } +} +*/ \ No newline at end of file diff --git a/AngularApp/src/app/auth_service.ts b/AngularApp/src/services/auth_service.ts similarity index 72% rename from AngularApp/src/app/auth_service.ts rename to AngularApp/src/services/auth_service.ts index 5356675d1951bd6c6ec6a03d397ac8559dbad339..52cedf1be4fc73df78df73527f753397d9fd2542 100644 --- a/AngularApp/src/app/auth_service.ts +++ b/AngularApp/src/services/auth_service.ts @@ -8,15 +8,16 @@ import { takeUntil } from 'rxjs/operators'; providedIn: 'root' }) export class AuthService { - private gitLabClientId = 'aa238db2a5ca6d9eda4214dc563c0ae49224d1dad2b1364cfe68f8a653c4bd9f'; + private gitLabClientId = '83846733ac6ca3d32903198198887641b4b4ff1d773d525e3e5a3d1a4be82aa5'; private gitLabRedirectUri = 'http://localhost:4200/login'; private gitLabAuthUrl = 'https://gitedu.hesge.ch/oauth/authorize'; private gitLabTokenUrl = 'https://gitedu.hesge.ch/oauth/token'; private gitLabScope = 'api+create_runner+read_repository+write_repository'; - private GITLAB_SECRET = 'gloas-4b3615b522437402e34617e1ce2bccaf690caf8225c664fee4cd14f38300521a' + private GITLAB_SECRET = 'gloas-1e7ffc76fdc0a8a60031d847dd0729e9c345516f8230056c776895bb93a1481e' private accessTokenSubject: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null); + private refreshTokenSubject: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null); // Propriété pour stocker le nom d'utilisateur private usernameSubject: BehaviorSubject<string> = new BehaviorSubject<string>(''); @@ -42,9 +43,9 @@ export class AuthService { this.http.post<any>(this.gitLabTokenUrl, body, { headers }).subscribe( response => { const accessToken = response.access_token; - console.log('AccessToken récupéré :', accessToken); + const refreshToken = response.refresh_token; this.setAccessToken(accessToken); - // Stockez le jeton d'accès dans localStorage ou dans un service approprié + this.setRefreshToken(refreshToken); }, error => { console.error('Erreur lors de l\'échange du code d\'autorisation contre un jeton d\'accès :', error); @@ -57,16 +58,34 @@ export class AuthService { console.log('Access token stocké dans localStorage :', accessToken); } + setRefreshToken(refreshToken: string): void { + localStorage.setItem('refreshToken', refreshToken); + this.refreshTokenSubject.next(refreshToken); + console.log('Refresh token stocké dans localStorage :', refreshToken); + } + getAccessToken(): string | null { const accessToken = localStorage.getItem('accessToken'); console.log('Access token récupéré depuis localStorage :', accessToken); return accessToken; } + getRefreshToken(): string | null { + const refreshToken = localStorage.getItem('refreshToken'); + console.log('Refresh token récupéré depuis localStorage :', refreshToken); + return refreshToken; + + } + clearAccessToken(): void { localStorage.removeItem('accessToken'); this.accessTokenSubject.next(null); console.log('Access token supprimé de localStorage.'); } + clearRefreshToken(): void { + localStorage.removeItem('refreshToken'); + this.refreshTokenSubject.next(null); + console.log('Refresh token supprimé de localStorage.'); + } } \ No newline at end of file diff --git a/AngularApp/src/app/exercise.service.spec.ts b/AngularApp/src/services/exercise.service.spec.ts similarity index 100% rename from AngularApp/src/app/exercise.service.spec.ts rename to AngularApp/src/services/exercise.service.spec.ts diff --git a/AngularApp/src/services/exercise.service.ts b/AngularApp/src/services/exercise.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..a70de6b5531c08a58fba565a2b007f95ab598740 --- /dev/null +++ b/AngularApp/src/services/exercise.service.ts @@ -0,0 +1,105 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';; +import { Observable } from 'rxjs'; +import { Exercise } from '../app/model/exercise'; +import { Assignment } from '../app/model/assignment'; +import { AuthService } from './auth_service'; +import { Result } from 'app/model/result'; + +@Injectable({ + providedIn: 'root' +}) + +export class ExerciseService { + private baseUrl = 'http://localhost:3000'; + + constructor(private http: HttpClient) {} + + getExercises(): Observable<Exercise[]> { + return this.http.get<Exercise[]>(`${this.baseUrl}/exercises`); + } + + + getAssignments(): Observable<Assignment[]> { + return this.http.get<Assignment[]>(`${this.baseUrl}/assignments`); + } + + getExercisesByAssignmentName(assignmentName: string): Observable<Exercise[]> { + return this.http.get<Exercise[]>(`${this.baseUrl}/exercises?assignmentName=${assignmentName}`); + } + + getResults(): Observable<Result[]> { + return this.http.get<Result[]>(`${this.baseUrl}/results`); + } + + getExerciseById(id: string): Observable<Exercise> { + console.log('ID de l\'exercice demandé :', id); + + return this.http.get<Exercise>(`${this.baseUrl}/exercises/${id}`); + } + + getExercisesByName(name: string): Observable<Exercise[]> { + // Utilisez HttpParams pour ajouter le paramètre de filtrage par nom + const params = new HttpParams().set('name', name); + + // Utilisez les paramètres dans la requête HTTP + return this.http.get<Exercise[]>(`${this.baseUrl}/exercises`, { params }); + } + // Méthode pour créer un nouvel exercice + createExercise(exercise: Exercise): Observable<any> { + return this.http.post(`${this.baseUrl}/exercises`, exercise); + } +} + +// export class ExerciseService { +// private baseUrl = 'http://localhost:30993'; + +// constructor(private http: HttpClient, private authService: AuthService) {} + +// setAccessToken(token: string): void { +// this.authService.setAccessToken(token); +// } + + +// getExercises(): Observable<Exercise[]> { +// return this.http.get<Exercise[]>(`${this.baseUrl}/exercises`, { +// headers: this.getHeadersWithToken() +// }); +// } + +// getAssignments(): Observable<Assignment[]> { +// return this.http.get<Assignment[]>(`${this.baseUrl}/assignments`, { +// headers: this.getHeadersWithToken() +// }); +// } + +// getExercisesByAssignmentName(assignmentName: string): Observable<Exercise[]> { +// return this.http.get<Exercise[]>(`${this.baseUrl}/exercises?assignmentName=${assignmentName}`, { +// headers: this.getHeadersWithToken() +// }); +// } +// getExerciseById(id: string): Observable<Exercise> { +// console.log('ID de l\'exercice demandé :', id); + +// return this.http.get<Exercise>(`${this.baseUrl}/exercises/${id}`); +// } + +// getExercisesByName(name: string): Observable<Exercise[]> { +// // Utilisez HttpParams pour ajouter le paramètre de filtrage par nom +// const params = new HttpParams().set('name', name); + +// // Utilisez les paramètres dans la requête HTTP +// return this.http.get<Exercise[]>(`${this.baseUrl}/exercises`, { params }); +// } +// // Méthode pour créer un nouvel exercice +// createExercise(exercise: Exercise): Observable<any> { +// return this.http.post(`${this.baseUrl}/exercises`, exercise); +// } + +// private getHeadersWithToken(): HttpHeaders { +// const token = this.authService.getAccessToken(); +// return new HttpHeaders({ +// 'Authorization': `Bearer ${token}` +// }); +// } +// } diff --git a/AngularApp/src/app/user.service.spec.ts b/AngularApp/src/services/user.service.spec.ts similarity index 100% rename from AngularApp/src/app/user.service.spec.ts rename to AngularApp/src/services/user.service.spec.ts diff --git a/AngularApp/src/app/user.service.ts b/AngularApp/src/services/user.service.ts similarity index 100% rename from AngularApp/src/app/user.service.ts rename to AngularApp/src/services/user.service.ts