diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b58b603fea78041071d125a30db58d79b3d49217 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/dojoweb.iml b/.idea/dojoweb.iml new file mode 100644 index 0000000000000000000000000000000000000000..24643cc37449b4bde54411a80b8ed61258225e34 --- /dev/null +++ b/.idea/dojoweb.iml @@ -0,0 +1,12 @@ +<?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 diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000000000000000000000000000000..03d9549ea8e4ada36fb3ecbc30fef08175b7d728 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ +<component name="InspectionProjectProfileManager"> + <profile version="1.0"> + <option name="myName" value="Project Default" /> + <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" /> + </profile> +</component> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..58ccc1ccf50d8021beac17064844135d6109aac3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/dojoweb.iml" filepath="$PROJECT_DIR$/.idea/dojoweb.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?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 diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml new file mode 100644 index 0000000000000000000000000000000000000000..fb0d65a4bb2218d117c4dd18bf823081dd7fcba1 --- /dev/null +++ b/.idea/watcherTasks.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectTasksOptions" suppressed-tasks="SCSS" /> +</project> \ No newline at end of file diff --git a/AngularApp/package-lock.json b/AngularApp/package-lock.json index c9a45c266ed368603e3ce4ed980b876c2060087d..be1c76789341ef10f3c39ca3377e43dcb73d7f2e 100644 --- a/AngularApp/package-lock.json +++ b/AngularApp/package-lock.json @@ -11,16 +11,16 @@ "dependencies": { "@angular/animations": "^14.2.0", "@angular/cdk": "^14.2.0", - "@angular/common": "^14.2.0", + "@angular/common": "^14.3.0", "@angular/compiler": "^14.2.0", "@angular/core": "^14.2.0", "@angular/elements": "^14.2.0", - "@angular/forms": "^14.2.0", + "@angular/forms": "^14.3.0", "@angular/localize": "^14.2.0", "@angular/material": "^14.2.0", "@angular/platform-browser": "^14.2.0", "@angular/platform-browser-dynamic": "^14.2.0", - "@angular/router": "^14.2.0", + "@angular/router": "^14.3.0", "ajv": "8.11.0", "arrive": "2.4.1", "bootstrap": "4.6.1", @@ -46,12 +46,12 @@ "@angular/cli": "~14.2.7", "@angular/compiler-cli": "^14.2.0", "@angular/language-service": "14.2.0", - "@types/bootstrap": "4.5.0", + "@types/bootstrap": "^4.5.0", "@types/chartist": "0.11.1", "@types/google.maps": "3.47.4", "@types/jasmine": "~4.0.0", "@types/jasminewd2": "~2.0.10", - "@types/jquery": "3.5.6", + "@types/jquery": "^3.5.6", "@types/node": "^17.0.21", "codelyzer": "6.0.2", "jasmine-core": "~4.4.0", diff --git a/AngularApp/package.json b/AngularApp/package.json index 121600e0377521a0004ad2e34dea84291a6f14a0..312bcd5c883012b1c147fbc386b826ef077547c2 100644 --- a/AngularApp/package.json +++ b/AngularApp/package.json @@ -19,16 +19,16 @@ "dependencies": { "@angular/animations": "^14.2.0", "@angular/cdk": "^14.2.0", - "@angular/common": "^14.2.0", + "@angular/common": "^14.3.0", "@angular/compiler": "^14.2.0", "@angular/core": "^14.2.0", "@angular/elements": "^14.2.0", - "@angular/forms": "^14.2.0", + "@angular/forms": "^14.3.0", "@angular/localize": "^14.2.0", "@angular/material": "^14.2.0", "@angular/platform-browser": "^14.2.0", "@angular/platform-browser-dynamic": "^14.2.0", - "@angular/router": "^14.2.0", + "@angular/router": "^14.3.0", "ajv": "8.11.0", "arrive": "2.4.1", "bootstrap": "4.6.1", @@ -46,22 +46,21 @@ "popper.js": "1.16.1", "rxjs": "~7.5.0", "tslib": "^2.3.0", - "zone.js": "~0.11.4", - "web-animations-js": "2.3.2" + "web-animations-js": "2.3.2", + "zone.js": "~0.11.4" }, "devDependencies": { "@angular-devkit/build-angular": "^14.2.7", "@angular/cli": "~14.2.7", "@angular/compiler-cli": "^14.2.0", "@angular/language-service": "14.2.0", + "@types/bootstrap": "^4.5.0", + "@types/chartist": "0.11.1", + "@types/google.maps": "3.47.4", "@types/jasmine": "~4.0.0", "@types/jasminewd2": "~2.0.10", + "@types/jquery": "^3.5.6", "@types/node": "^17.0.21", - "@types/bootstrap": "4.5.0", - "@types/chartist": "0.11.1", - "@types/google.maps": "3.47.4", - "@types/jquery": "3.5.6", - "sass": "1.32.13", "codelyzer": "6.0.2", "jasmine-core": "~4.4.0", "jasmine-spec-reporter": "~7.0.0", @@ -72,6 +71,7 @@ "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.0.0", "protractor": "7.0.0", + "sass": "1.32.13", "ts-node": "~10.9.1", "typescript": "~4.7.2" } diff --git a/AngularApp/src/app/app.module.ts b/AngularApp/src/app/app.module.ts index 03932ba451693c3f0911bad4cc4f36f7553cbf02..fabae395fcdffa979782f280dc53d0f6c21d177f 100644 --- a/AngularApp/src/app/app.module.ts +++ b/AngularApp/src/app/app.module.ts @@ -2,13 +2,22 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; -import { RouterModule } from '@angular/router'; +import { RouterModule, Routes} from '@angular/router'; import { AppRoutingModule } from './app.routing'; import { ComponentsModule } from './components/components.module'; import { AppComponent } from './app.component'; import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.component'; +import { CreateExerciseComponent } from './create-exercise/create-exercise.component'; +import { ListExerciseComponent } from './list-exercise/list-exercise.component'; +import { ExerciseDetailsComponent } from './exercise-details/exercise-details.component'; +import * as bootstrap from "bootstrap"; +import * as $ from "jquery"; // import { ExercisePageComponent } from './exercise-page/exercise-page.component'; +const routes: Routes = [ + // Add other routes as needed +]; + @NgModule({ imports: [ BrowserAnimationsModule, @@ -16,12 +25,15 @@ import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.compon ReactiveFormsModule, HttpClientModule, ComponentsModule, - RouterModule, + RouterModule.forRoot(routes), AppRoutingModule, ], declarations: [ AppComponent, AdminLayoutComponent, + CreateExerciseComponent, + ListExerciseComponent, + ExerciseDetailsComponent, ], providers: [], bootstrap: [AppComponent] diff --git a/AngularApp/src/app/app.routing.ts b/AngularApp/src/app/app.routing.ts index f2f01ac74e29c6a1b22faf4de3621b3b193753a1..e56d5c6f2a4ac4ad6c759922a929758c5de959e2 100644 --- a/AngularApp/src/app/app.routing.ts +++ b/AngularApp/src/app/app.routing.ts @@ -4,6 +4,9 @@ import { BrowserModule } from '@angular/platform-browser'; import { Routes, RouterModule } from '@angular/router'; import { AdminLayoutComponent } from './layouts/admin-layout/admin-layout.component'; +import { CreateExerciseComponent } from './create-exercise/create-exercise.component'; +import { ListExerciseComponent } from './list-exercise/list-exercise.component'; +import { ExerciseDetailsComponent } from './exercise-details/exercise-details.component'; const routes: Routes =[ { @@ -17,7 +20,10 @@ const routes: Routes =[ path: '', loadChildren: () => import('./layouts/admin-layout/admin-layout.module').then(m => m.AdminLayoutModule) }] - } + }, + { path: 'list_exercice', component: ListExerciseComponent }, + { path: 'create_exercise', component: CreateExerciseComponent }, + { path: 'exercise-details/:id', component: ExerciseDetailsComponent } ]; @NgModule({ diff --git a/AngularApp/src/app/assignment.service.spec.ts b/AngularApp/src/app/assignment.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c8e2c6aa780b70c9dc84092182cb8e86bd0d9bb --- /dev/null +++ b/AngularApp/src/app/assignment.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AssignmentService } from './assignment.service'; + +describe('AssignmentService', () => { + let service: AssignmentService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AssignmentService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/assignment.service.ts b/AngularApp/src/app/assignment.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..f57ec41c3eb53c92c082f7ebf284a89fc1e844c0 --- /dev/null +++ b/AngularApp/src/app/assignment.service.ts @@ -0,0 +1,22 @@ +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/auth_service.ts b/AngularApp/src/app/auth_service.ts new file mode 100644 index 0000000000000000000000000000000000000000..260aaa20f15ed4d10b53a7b9cda0070d0afe84e0 --- /dev/null +++ b/AngularApp/src/app/auth_service.ts @@ -0,0 +1,96 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Router } from '@angular/router'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService implements OnDestroy { + private gitLabClientId = 'aa238db2a5ca6d9eda4214dc563c0ae49224d1dad2b1364cfe68f8a653c4bd9f'; + private gitLabRedirectUri = 'http://localhost:4200/login'; + private gitLabAuthUrl = 'https://githepia.hesge.ch/oauth/authorize'; + private gitLabTokenUrl = 'https://githepia.hesge.ch/oauth/token'; + private GITLAB_SECRET = 'gloas-4b3615b522437402e34617e1ce2bccaf690caf8225c664fee4cd14f38300521a' + + private destroy$ = new Subject<void>(); + + // Propriété pour stocker le nom d'utilisateur + private usernameSubject: BehaviorSubject<string> = new BehaviorSubject<string>(''); + + // Propriété observable pour permettre à d'autres parties de l'application d'accéder au nom d'utilisateur + username$ = this.usernameSubject.asObservable(); + + constructor(private http: HttpClient, private router: Router) {} + + authenticateWithGitLab(): void { + const redirectUri = encodeURIComponent(this.gitLabRedirectUri); + const authUrl = `${this.gitLabAuthUrl}?client_id=${this.gitLabClientId}&redirect_uri=${redirectUri}&response_type=code&scope=api+create_runner+read_repository+write_repository`; + + window.location.href = authUrl; + + console.log("test"); + } + + getUserInfo(accessToken: string): void { + const headers = new HttpHeaders({ + Authorization: `Bearer ${accessToken}` + }); + + // Faire une requête à l'API GitLab pour obtenir les détails de l'utilisateur + this.http.get('https://githepia.hesge.ch/api/v4/user', { headers }) + .pipe(takeUntil(this.destroy$)) + .subscribe( + (user: any) => { + // Récupérer le nom du compte de l'utilisateur + const accountName = user.username; + this.usernameSubject.next(accountName); + + console.log(`Nom du compte: ${accountName}`); + }, + (error) => { + console.error(error); + } + ); + } + + exchangeCodeForToken(code: string): void { + const redirectUri = encodeURIComponent(this.gitLabRedirectUri); + const body = `client_id=${this.gitLabClientId}&client_secret=${this.GITLAB_SECRET}&code=${code}&grant_type=authorization_code&redirect_uri=${redirectUri}`; + + this.http.post(this.gitLabTokenUrl, body) + .pipe(takeUntil(this.destroy$)) + .subscribe( + (response: any) => { + // Récupérer le jeton d'accès depuis la réponse + const accessToken = response.access_token; + + // Ajouter une déclaration de débogage pour vérifier l'accessToken + console.log('AccessToken récupéré :', accessToken); + + // Utiliser le jeton pour récupérer les informations de l'utilisateur + this.getUserInfo(accessToken); + + localStorage.setItem('authorizationCode', code); + localStorage.setItem('accessToken', response.access_token); + }, + (error) => { + console.error(error); + } + ); + } + + isAuthorizationCodeStored(): boolean { + return localStorage.getItem('authorizationCode') !== null; + } + + isAccessTokenStored(): boolean { + return localStorage.getItem('accessToken') !== null; + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/AngularApp/src/app/components/navbar/navbar.component.css b/AngularApp/src/app/components/navbar/navbar.component.css index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..94b1ba2ac348c89c5ea7add4ce69c1c1d9258789 100644 --- a/AngularApp/src/app/components/navbar/navbar.component.css +++ b/AngularApp/src/app/components/navbar/navbar.component.css @@ -0,0 +1,16 @@ +/* navbar.component.css */ +.dropdown-content { + position: absolute; + display: block; + background-color: #f9f9f9; + min-width: 160px; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); + z-index: 1; +} + +.dropdown-content p { + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; +} \ No newline at end of file diff --git a/AngularApp/src/app/components/navbar/navbar.component.html b/AngularApp/src/app/components/navbar/navbar.component.html index a38a6c7255dc04a70309d81678d5a2b9c21cdf1d..597b814277ca4e3cede5d632f2df9a4aa89d3c29 100644 --- a/AngularApp/src/app/components/navbar/navbar.component.html +++ b/AngularApp/src/app/components/navbar/navbar.component.html @@ -20,14 +20,6 @@ </div> </form> <ul class="navbar-nav"> - <li class="nav-item"> - <a class="nav-link" href="javascript:void(0)"> - <i class="material-icons">dashboard</i> - <p> - <span class="d-lg-none d-md-block">Stats</span> - </p> - </a> - </li> <li class="nav-item dropdown"> <a class="nav-link" href="javascript:void(0)" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="material-icons">notifications</i> @@ -45,12 +37,17 @@ </div> </li> <li class="nav-item"> - <a class="nav-link" href="javascript:void(0)"> + <a class="nav-link" href="javascript:void(0)" (click)="toggleDropdown()"> <i class="material-icons">person</i> <p> <span class="d-lg-none d-md-block">Account</span> </p> </a> + <div *ngIf="dropdownVisible" class="dropdown-content"> + <p>Contact</p> + <p>Déconnexion</p> + <p>{{ username }}</p> + </div> </li> </ul> </div> diff --git a/AngularApp/src/app/components/navbar/navbar.component.ts b/AngularApp/src/app/components/navbar/navbar.component.ts index bccc8852cfd40e7b069ca8d903972e7905324283..7824a5c10f6b4b6879bf65bb79ffc3f93eed48ed 100644 --- a/AngularApp/src/app/components/navbar/navbar.component.ts +++ b/AngularApp/src/app/components/navbar/navbar.component.ts @@ -2,6 +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"; @Component({ selector: 'app-navbar', @@ -9,18 +10,28 @@ import { Router } from '@angular/router'; styleUrls: ['./navbar.component.css'] }) export class NavbarComponent implements OnInit { + username: string = ''; + accountName: string = 'Nom du compte par défaut'; // Initialisez avec une valeur par défaut + dropdownVisible: boolean = false; + + toggleDropdown() { + this.dropdownVisible = !this.dropdownVisible; + } private listTitles: any[]; location: Location; mobile_menu_visible: any = 0; private toggleButton: any; private sidebarVisible: boolean; - constructor(location: Location, private element: ElementRef, private router: Router) { + constructor(location: Location, private element: ElementRef, private router: Router,private authService:AuthService) { this.location = location; this.sidebarVisible = false; } ngOnInit(){ + this.authService.username$.subscribe(username => { + this.username = username; + }); this.listTitles = ROUTES.filter(listTitle => listTitle); const navbar: HTMLElement = this.element.nativeElement; this.toggleButton = navbar.getElementsByClassName('navbar-toggler')[0]; diff --git a/AngularApp/src/app/components/sidebar/sidebar.component.html b/AngularApp/src/app/components/sidebar/sidebar.component.html index efeea8b517a883b5214d6379aa5f5e3c4ee2663b..4df23bba4ded3d50a9a2587a51c73f1f25ffcc76 100644 --- a/AngularApp/src/app/components/sidebar/sidebar.component.html +++ b/AngularApp/src/app/components/sidebar/sidebar.component.html @@ -1,9 +1,9 @@ <div class="logo"> - <a href="https://www.creative-tim.com" class="simple-text"> + <a href="" class="simple-text"> <div class="logo-img"> <img src="/assets/img/angular2-logo-red.png"/> </div> - Creative Tim + DOJO </a> </div> <div class="sidebar-wrapper"> diff --git a/AngularApp/src/app/components/sidebar/sidebar.component.ts b/AngularApp/src/app/components/sidebar/sidebar.component.ts index d5df9ccdda1a13929478e0d90a3e03dcfa9853b8..bc7ec8379070d7aa5c6985206307d001191e7242 100644 --- a/AngularApp/src/app/components/sidebar/sidebar.component.ts +++ b/AngularApp/src/app/components/sidebar/sidebar.component.ts @@ -9,10 +9,13 @@ declare interface RouteInfo { } export const ROUTES: RouteInfo[] = [ { path: '/dashboard', title: 'Dashboard', icon: 'dashboard', class: '' }, + { path: '/login', title: 'Login', icon:'login', class: '' }, { path: '/user-profile', title: 'Create assignment', icon:'assignment_add', class: '' }, { path: '/table-list', title: 'Assignment', icon:'content_paste', class: '' }, { path: '/exercise-page', title: 'Exercise Page', icon:'description', class: '' }, { path: '/typography', title: 'Typography', icon:'library_books', class: '' }, + { path: '/exercise', title: 'Exercices', icon:'exercises', class: '' }, + // { path: '/icons', title: 'Icons', icon:'bubble_chart', class: '' }, // { path: '/maps', title: 'Maps', icon:'location_on', class: '' }, { path: '/notifications', title: 'Notifications', icon:'notifications', class: '' }, diff --git a/AngularApp/src/app/create-exercise/create-exercise.component.css b/AngularApp/src/app/create-exercise/create-exercise.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/AngularApp/src/app/create-exercise/create-exercise.component.html b/AngularApp/src/app/create-exercise/create-exercise.component.html new file mode 100644 index 0000000000000000000000000000000000000000..9adb87ae22b614f63fa3bb1be5a9f12575e7f1d9 --- /dev/null +++ b/AngularApp/src/app/create-exercise/create-exercise.component.html @@ -0,0 +1,38 @@ +<!-- create-exercise.component.html --> + +<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">Créer un exercice</h4> + </div> + <div class="card-body"> + <div class="table-responsive"> + <table class="table"> + <tbody> + <tr> + <td>Nom de l'exercice:</td> + <td> + <input type="text" name="exerciseName" [(ngModel)]="exerciseName" class="form-control" required> + </td> + </tr> + <tr> + <td>Énoncé de l'exercice:</td> + <td> + <select name="selectedAssignment" [(ngModel)]="selectedAssignment" class="form-control" required> + <option *ngFor="let assignment of assignments" [ngValue]="assignment">{{ assignment.name }}</option> + </select> + </td> + </tr> + </tbody> + </table> + <button (click)="createExercise()" class="btn btn-primary">Créer l'exercice</button> + </div> + </div> + </div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/create-exercise/create-exercise.component.spec.ts b/AngularApp/src/app/create-exercise/create-exercise.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac4e396ee5037602c535f58ec5ab4ba7b832d804 --- /dev/null +++ b/AngularApp/src/app/create-exercise/create-exercise.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateExerciseComponent } from './create-exercise.component'; + +describe('CreateExerciseComponent', () => { + let component: CreateExerciseComponent; + let fixture: ComponentFixture<CreateExerciseComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ CreateExerciseComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CreateExerciseComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/create-exercise/create-exercise.component.ts b/AngularApp/src/app/create-exercise/create-exercise.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba4a3d676539d5eb0ffbebd47284637df0a92b00 --- /dev/null +++ b/AngularApp/src/app/create-exercise/create-exercise.component.ts @@ -0,0 +1,61 @@ +import { Component, OnInit } from '@angular/core'; +import { AssignmentService } from 'app/assignment.service'; +import { Assignment } from '../model/assignment'; +import { ExerciseService } from 'app/exercise.service'; +import { Exercise } from 'app/model/exercise'; + + + +@Component({ + selector: 'app-create-exercise', + templateUrl: './create-exercise.component.html', + styleUrls: ['./create-exercise.component.css'] +}) +export class CreateExerciseComponent implements OnInit { + assignments: Assignment[] = []; + selectedAssignment: Assignment | undefined; // Ajout de la variable pour stocker l'assignment sélectionné + exerciseName: string = ''; // Ajout de la variable pour stocker le nom de l'exercice + + constructor(private assignmentService: AssignmentService, private exerciseService: ExerciseService) { } + + ngOnInit(): void { + // Récupérer la liste des assignments lors de l'initialisation du composant + this.assignmentService.getAssignment().subscribe(assignments => { + this.assignments = assignments; + }); + } + + // Méthode appelée lorsque le formulaire est soumis + createExercise(): void { + if (this.selectedAssignment && this.exerciseName) { + // Créer un nouvel exercice avec les informations nécessaires + const newExercise: Exercise = { + id : '', + assignmentName: this.selectedAssignment.name, + name: this.exerciseName, + gitlabId: 0, // Ajoutez des valeurs par défaut si nécessaire + gitlabLink: '', + gitlabCreationInfo: "{\"id\":14232,\"description\":\"Dojo exercise repository based on the the assignment: Technique de compilation - TP\}", + gitlabLastInfo: '', + gitlabLastInfoDate: this.formatDateForMySQL(new Date()), + secret: '' // Ajoutez des valeurs par défaut si nécessaire + }; + + // Appelez le service pour créer l'exercice + this.exerciseService.createExercise(newExercise).subscribe(response => { + // Gérez la réponse de création si nécessaire + console.log('Exercice créé avec succès :', response); + }); + } + } + private formatDateForMySQL(date: Date): string { + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + const seconds = date.getSeconds().toString().padStart(2, '0'); + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; + } +} diff --git a/AngularApp/src/app/exercise-details/exercise-details.component.css b/AngularApp/src/app/exercise-details/exercise-details.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/AngularApp/src/app/exercise-details/exercise-details.component.html b/AngularApp/src/app/exercise-details/exercise-details.component.html new file mode 100644 index 0000000000000000000000000000000000000000..2eeb03cf17a868c32bb27f908452ab650f03452b --- /dev/null +++ b/AngularApp/src/app/exercise-details/exercise-details.component.html @@ -0,0 +1,44 @@ +<!-- exercise-details.component.html --> + +<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">Détails de l'exercice</h4> + </div> + <div class="card-body"> + <form> + <div class="form-group"> + <label for="exerciseName">Nom de l'exercice :</label> + <input type="text" id="exerciseName" name="exerciseName" [(ngModel)]="exercise.name" class="form-control" readonly> + </div> + + <div class="form-group"> + <label for="assignmentName">Nom de l'assignment :</label> + <input type="text" id="assignmentName" name="assignmentName" [(ngModel)]="exercise.assignmentName" class="form-control" readonly> + </div> + + <div class="form-group"> + <label for="gitlabId">ID GitLab :</label> + <input type="text" id="gitlabId" name="gitlabId" [(ngModel)]="exercise.gitlabId" class="form-control" readonly> + </div> + + <div class="form-group"> + <label for="gitlabLastInfoDate">Date de dernière information GitLab :</label> + <input type="text" id="gitlabLastInfoDate" name="gitlabLastInfoDate" [(ngModel)]="exercise.gitlabLastInfoDate" class="form-control" readonly> + </div> + + <div class="form-group"> + <label for="gitlabLink">Lien GitLab :</label> + <input type="text" id="gitlabLink" name="gitlabLink" [(ngModel)]="exercise.gitlabLink" class="form-control" readonly> + </div> + </form> + + </div> + </div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/exercise-details/exercise-details.component.spec.ts b/AngularApp/src/app/exercise-details/exercise-details.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..79ec6c2cead7dfb6d212b9aca83716e0ec772e26 --- /dev/null +++ b/AngularApp/src/app/exercise-details/exercise-details.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ExerciseDetailsComponent } from './exercise-details.component'; + +describe('ExerciseDetailsComponent', () => { + let component: ExerciseDetailsComponent; + let fixture: ComponentFixture<ExerciseDetailsComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ExerciseDetailsComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ExerciseDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/exercise-details/exercise-details.component.ts b/AngularApp/src/app/exercise-details/exercise-details.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f3e2c330dfbab1bc5ce6e1d24097a5a4399ffe2 --- /dev/null +++ b/AngularApp/src/app/exercise-details/exercise-details.component.ts @@ -0,0 +1,35 @@ +// exercise-details.component.ts + +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ExerciseService } from 'app/exercise.service'; +import { Exercise } from 'app/model/exercise'; + +@Component({ + selector: 'app-exercise-details', + templateUrl: './exercise-details.component.html', + styleUrls: ['./exercise-details.component.css'] +}) +export class ExerciseDetailsComponent implements OnInit { + exerciseId: string; + exercise: Exercise; + + constructor(private route: ActivatedRoute, private exerciseService: ExerciseService) { } + + ngOnInit(): void { + const exerciseId = this.route.snapshot.paramMap.get('id'); + console.log('ID de l\'exercice dans le composant :', exerciseId); + + if (exerciseId) { + this.exerciseService.getExerciseById(exerciseId).subscribe( + (exercise: Exercise) => { + console.log('Exercice récupéré avec succès :', exercise); + this.exercise = exercise; + }, + (error) => { + console.error('Erreur lors de la récupération de l\'exercice :', error); + } + ); + } +} +} diff --git a/AngularApp/src/app/exercise.service.spec.ts b/AngularApp/src/app/exercise.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..00a9195be600c464808fe006fc23e93865debb31 --- /dev/null +++ b/AngularApp/src/app/exercise.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ExerciseService } from './exercise.service'; + +describe('ExerciseService', () => { + let service: ExerciseService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ExerciseService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/exercise.service.ts b/AngularApp/src/app/exercise.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e0acdef0bf99af1ca03fda0d26b18cca6771144 --- /dev/null +++ b/AngularApp/src/app/exercise.service.ts @@ -0,0 +1,45 @@ +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.css b/AngularApp/src/app/exercise/exercise.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/AngularApp/src/app/exercise/exercise.component.html b/AngularApp/src/app/exercise/exercise.component.html new file mode 100644 index 0000000000000000000000000000000000000000..315a2fa41a2a777efe21ad83f960c3ee29cf92ea --- /dev/null +++ b/AngularApp/src/app/exercise/exercise.component.html @@ -0,0 +1,27 @@ +<!-- exercises.component.html --> + +<!-- login.component.html --> +<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 ">Exercices</h4> + </div> + <div class="card-body"> + <div class="table-responsive"> + <div class="exercise-container"> + <!-- Bouton pour Voir mes exercices --> + <a routerLink="/list_exercice" class="btn btn-primary">Voir mes exercices</a> + + <!-- Bouton pour Créer un exercice --> + <a routerLink="/create_exercise" class="btn btn-success">Créer un exercice</a> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/exercise/exercise.component.spec.ts b/AngularApp/src/app/exercise/exercise.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..98fa87e684daf95089c3c103cd8e68a654956827 --- /dev/null +++ b/AngularApp/src/app/exercise/exercise.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ExerciseComponent } from './exercise.component'; + +describe('ExerciseComponent', () => { + let component: ExerciseComponent; + let fixture: ComponentFixture<ExerciseComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ExerciseComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ExerciseComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/exercise/exercise.component.ts b/AngularApp/src/app/exercise/exercise.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..08eddf248c364a4d6f9cce00f0491ac6bf12e7e1 --- /dev/null +++ b/AngularApp/src/app/exercise/exercise.component.ts @@ -0,0 +1,30 @@ +// exercises.component.ts + +import { Component, OnInit } from '@angular/core'; +import {ExerciseService} from "../exercise.service"; + +@Component({ + selector: 'app-exercises', + templateUrl: './exercise.component.html', + styleUrls: ['./exercise.component.css'] +}) +export class ExerciseComponent implements OnInit { + exercises: any[] = []; + + constructor(private exerciseService: ExerciseService) { } + + ngOnInit(): void { + this.loadExercises(); + } + + private loadExercises(): void { + this.exerciseService.getExercises().subscribe( + (exercises) => { + this.exercises = exercises; + }, + (error) => { + console.error('Error loading exercises:', error); + } + ); + } +} diff --git a/AngularApp/src/app/layouts/admin-layout/admin-layout.module.ts b/AngularApp/src/app/layouts/admin-layout/admin-layout.module.ts index 60eabd9afdabc126f981fcd80c4cf10d9b994e29..08e50bc8cb2ab9e128c685a52a83ae61ee69fcd0 100644 --- a/AngularApp/src/app/layouts/admin-layout/admin-layout.module.ts +++ b/AngularApp/src/app/layouts/admin-layout/admin-layout.module.ts @@ -18,6 +18,10 @@ import {MatRippleModule} from '@angular/material/core'; import {MatFormFieldModule} from '@angular/material/form-field'; import {MatTooltipModule} from '@angular/material/tooltip'; import {MatSelectModule} from '@angular/material/select'; +import {LoginComponent} from "../../login/login.component"; +import {ExerciseComponent} from 'app/exercise/exercise.component'; + + @NgModule({ imports: [ @@ -33,6 +37,8 @@ import {MatSelectModule} from '@angular/material/select'; MatTooltipModule, ], declarations: [ + + LoginComponent, DashboardComponent, UserProfileComponent, TableListComponent, @@ -41,7 +47,8 @@ import {MatSelectModule} from '@angular/material/select'; MapsComponent, NotificationsComponent, UpgradeComponent, - ExercisePageComponent + ExercisePageComponent, + ExerciseComponent, ] }) 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 a4f97e7f2b5d9f1d71dd78f8547848f8ef643791..8d6cade52392e9061c507f5140a64fec51a043df 100644 --- a/AngularApp/src/app/layouts/admin-layout/admin-layout.routing.ts +++ b/AngularApp/src/app/layouts/admin-layout/admin-layout.routing.ts @@ -9,9 +9,14 @@ import { MapsComponent } from '../../maps/maps.component'; import { NotificationsComponent } from '../../notifications/notifications.component'; import { UpgradeComponent } from '../../upgrade/upgrade.component'; import { ExercisePageComponent } from '../../exercise-page/exercise-page.component'; +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'; export const AdminLayoutRoutes: Routes = [ { path: 'dashboard', component: DashboardComponent }, + { path: 'login', component: LoginComponent }, { path: 'user-profile', component: UserProfileComponent }, { path: 'table-list', component: TableListComponent }, { path: 'typography', component: TypographyComponent }, @@ -20,4 +25,9 @@ export const AdminLayoutRoutes: Routes = [ { path: 'notifications', component: NotificationsComponent }, { path: 'exercise-page', component: ExercisePageComponent }, { path: 'upgrade', component: UpgradeComponent }, + { path: 'exercise', component: ExerciseComponent }, + + + ]; + diff --git a/AngularApp/src/app/list-exercise/list-exercise.component.css b/AngularApp/src/app/list-exercise/list-exercise.component.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/AngularApp/src/app/list-exercise/list-exercise.component.html b/AngularApp/src/app/list-exercise/list-exercise.component.html new file mode 100644 index 0000000000000000000000000000000000000000..320bbf69a6b0000ead1a5a738b8d0a4fbe6cfdb5 --- /dev/null +++ b/AngularApp/src/app/list-exercise/list-exercise.component.html @@ -0,0 +1,77 @@ +<!-- list-exercise.component.html --> + +<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</h4> + </div> + <div class="card-body"> + <div class="row"> + <div class="col-md-6"> + <h5>Filtres</h5> + <div *ngFor="let assignmentName of assignmentNames"> + <label> + <input + type="checkbox" + [checked]="selectedAssignmentNames.includes(assignmentName)" + (change)="updateSelectedAssignmentNames(assignmentName)" + /> + {{ assignmentName }} + </label> + </div> + </div> + </div> + <hr /> + <div class="table-responsive"> + <table class="table"> + <thead class="text-primary"> + <tr> + <th>Assignment</th> + <th>Exercice</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let exercise of filteredExercises"> + <td>{{ exercise.assignmentName }}</td> + <td>{{ exercise.name }}</td> + <td> + <a [routerLink]="['/exercise-details', exercise.id]"> + <i class="fa fa-eye"></i> Détails + </a> + + <button class="btn btn-danger" (click)="confirmDelete(exercise.id)"> + <i class="fa fa-trash"></i> Supprimer + </button> + <div class="modal" id="confirmDeleteModal" tabindex="-1" role="dialog"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title">Confirmation de suppression</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + Êtes-vous sûr de vouloir supprimer cet exercice ? + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button> + <button type="button" class="btn btn-danger" (click)="deleteExercise(exercise.id)">Supprimer</button> + </div> + </div> + </div> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/list-exercise/list-exercise.component.spec.ts b/AngularApp/src/app/list-exercise/list-exercise.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..a322b26b3311c3339a4bf7cc164d77f3dd59170f --- /dev/null +++ b/AngularApp/src/app/list-exercise/list-exercise.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ListExerciseComponent } from './list-exercise.component'; + +describe('ListExerciseComponent', () => { + let component: ListExerciseComponent; + let fixture: ComponentFixture<ListExerciseComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ListExerciseComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ListExerciseComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/list-exercise/list-exercise.component.ts b/AngularApp/src/app/list-exercise/list-exercise.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0df7bfd2a75c2e86dcfe9e58fda5ef2564a2153a --- /dev/null +++ b/AngularApp/src/app/list-exercise/list-exercise.component.ts @@ -0,0 +1,70 @@ +// exercise.component.ts + +import { Component, OnInit } from '@angular/core'; +import { ExerciseService } from 'app/exercise.service'; +import { Exercise } from 'app/model/exercise'; +import { Assignment } from 'app/model/assignment'; +import { AssignmentService } from 'app/assignment.service'; + + + +@Component({ + selector: 'app-list-exercise', + templateUrl: './list-exercise.component.html', + styleUrls: ['./list-exercise.component.css'] +}) +export class ListExerciseComponent implements OnInit { + assignmentNames: string[] = []; + selectedAssignmentNames: string[] = []; + exercises: Exercise[] = []; + filteredExercises: Exercise[] = []; + exerciseIdToDelete: string | null = null; + + constructor( + private exerciseService: ExerciseService, + private assignmentService: AssignmentService // Injectez le service d'assignation + ) {} + + 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.assignmentNames = assignments.map(assignment => assignment.name); + }); + } + + updateSelectedAssignmentNames(assignmentName: string): void { + if (this.selectedAssignmentNames.includes(assignmentName)) { + // Retirez l'élément si déjà présent + this.selectedAssignmentNames = this.selectedAssignmentNames.filter(name => name !== assignmentName); + } else { + // Ajoutez l'élément s'il n'est pas déjà présent + this.selectedAssignmentNames.push(assignmentName); + } + + // Appliquez les filtres + this.filterExercises(); + } + + filterExercises(): void { + this.filteredExercises = this.exercises.filter(exercise => + this.selectedAssignmentNames.includes(exercise.assignmentName) + ); + } + + confirmDelete(exerciseId: string): void { + this.exerciseIdToDelete = exerciseId; + // Ouvrir la fenêtre modale + $('#confirmDeleteModal').modal('show'); + } + + deleteExercise(): void { + // TODO + $('#confirmDeleteModal').modal('hide'); + } +} \ No newline at end of file diff --git a/AngularApp/src/app/login/login.component.css b/AngularApp/src/app/login/login.component.css new file mode 100644 index 0000000000000000000000000000000000000000..a3f2430e1428da97b06a497fb3339c06d47c9c1c --- /dev/null +++ b/AngularApp/src/app/login/login.component.css @@ -0,0 +1,37 @@ +/* login.component.css */ + +.login-container { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; +} + +.login-card { + background-color: #fff; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + padding: 20px; + text-align: center; +} + +h2 { + color: #333; +} + +.login-button { + background-color: #3498db; + color: #fff; + border: none; + padding: 10px 20px; + font-size: 16px; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.login-button:hover { + background-color: #2980b9; +} + +/* Add more styles as needed */ diff --git a/AngularApp/src/app/login/login.component.html b/AngularApp/src/app/login/login.component.html new file mode 100644 index 0000000000000000000000000000000000000000..6b7604b6adf0a64022f5bfa840dff1eb1ae3b1fb --- /dev/null +++ b/AngularApp/src/app/login/login.component.html @@ -0,0 +1,23 @@ +<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 ">Login</h4> + <p class="card-category">Connexion via Gitlab</p> + </div> + <div class="card-body"> + <div class="table-responsive"> + <div class="login-container"> + <div class="login-card"> + <button (click)="login()" class="login-button">Se connecter avec GitLab</button> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/AngularApp/src/app/login/login.component.spec.ts b/AngularApp/src/app/login/login.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..10eca249d528f4bcf8ef434696978a242a03e487 --- /dev/null +++ b/AngularApp/src/app/login/login.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture<LoginComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LoginComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/login/login.component.ts b/AngularApp/src/app/login/login.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..86165b663f112a90ca4ed12e8156fea4de8d8b09 --- /dev/null +++ b/AngularApp/src/app/login/login.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from '@angular/core'; +import { AuthService } from "../auth_service"; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.css'] +}) +export class LoginComponent implements OnInit { + username: string = ''; + private res = ""; + + constructor(private route: ActivatedRoute, private authService: AuthService) {} + + ngOnInit(): void { + console.log("Affichage test"); + + // Subscription aux queryParams + this.route.queryParams.subscribe(params => { + const code = params['code']; + + + if (code) { + console.log('Code d\'autorisation récupéré :', code); + this.authService.exchangeCodeForToken(code); + this.res = code; + } else { + console.log("Aucun code d'autorisation trouvé dans les queryParams."); + } + }); + + // Vérification du stockage du code d'autorisation + const isCodeStored = this.authService.isAuthorizationCodeStored(); + console.log('Le code d\'autorisation est stocké :', isCodeStored); + + // Vérification du stockage du jeton d'accès + const isTokenStored = this.authService.isAccessTokenStored(); + console.log('Le jeton d\'accès est stocké :', isTokenStored); + console.log('Code d\'autorisation récupéré :', this.res); + } + + login(): void { + this.authService.authenticateWithGitLab(); + } +} diff --git a/AngularApp/src/app/model/UserRole.ts b/AngularApp/src/app/model/UserRole.ts new file mode 100644 index 0000000000000000000000000000000000000000..290c7cea4bef9f6cd5ba9f540e3253a62213cf10 --- /dev/null +++ b/AngularApp/src/app/model/UserRole.ts @@ -0,0 +1,8 @@ +enum UserRole { + STUDENT = 'STUDENT', + TEACHING_STAFF = 'TEACHING_STAFF', + ADMIN = 'ADMIN' +} + + +export default UserRole; diff --git a/AngularApp/src/app/model/assignment.ts b/AngularApp/src/app/model/assignment.ts new file mode 100644 index 0000000000000000000000000000000000000000..399e1a66fe73c5dd318c03e201f5b196c1b8bf1f --- /dev/null +++ b/AngularApp/src/app/model/assignment.ts @@ -0,0 +1,5 @@ +export interface Assignment { + name : string, + description : string, + language : string +} diff --git a/AngularApp/src/app/model/enonce.ts b/AngularApp/src/app/model/enonce.ts new file mode 100644 index 0000000000000000000000000000000000000000..a660162791f3364aef4ccd573f876774780e01c9 --- /dev/null +++ b/AngularApp/src/app/model/enonce.ts @@ -0,0 +1,7 @@ +import { Assignment } from "./assignment"; + +export interface Enonce { + assignment : Assignment, + nbOfSuccess : Number, + nbExerciseCreated : Number +} diff --git a/AngularApp/src/app/model/exercise.ts b/AngularApp/src/app/model/exercise.ts new file mode 100644 index 0000000000000000000000000000000000000000..348ed8c02cd9c9c035445f1c5313ded58c425593 --- /dev/null +++ b/AngularApp/src/app/model/exercise.ts @@ -0,0 +1,11 @@ +export interface Exercise { + id: string, + assignmentName: string; + name: string; + gitlabId: number; + gitlabLink: string; + gitlabCreationInfo: string; + gitlabLastInfo: string; + gitlabLastInfoDate: string; + secret: string; +} diff --git a/AngularApp/src/app/model/user.ts b/AngularApp/src/app/model/user.ts new file mode 100644 index 0000000000000000000000000000000000000000..a17ca9c700e4b19c9582e1926062418da8dec45c --- /dev/null +++ b/AngularApp/src/app/model/user.ts @@ -0,0 +1,12 @@ +import UserRole from "./UserRole"; + +export interface User { + id: number; + mail: string; + role: UserRole; + deleted: boolean; + gitlabLastInfo: string; + gitlabUsername: string; + isTeachingStaff: boolean; + name: string; +} diff --git a/AngularApp/src/app/user.service.spec.ts b/AngularApp/src/app/user.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f804c9fda82e0654f5cf7fd60a806fcdfcb6498 --- /dev/null +++ b/AngularApp/src/app/user.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UserService } from './user.service'; + +describe('UserService', () => { + let service: UserService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UserService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/AngularApp/src/app/user.service.ts b/AngularApp/src/app/user.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..ece9138de18903bf841d6a98f7f1d8a6d5ff8ed6 --- /dev/null +++ b/AngularApp/src/app/user.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { User } from 'app/model/user'; + +@Injectable({ + providedIn: 'root' +}) +export class UserService { + + private baseUrl = 'http://localhost:3000'; + + constructor(private http: HttpClient) {} + + getUsers(): Observable<User[]> { + return this.http.get<User[]>(`${this.baseUrl}/users`); + } +}