From b731c2dd8cc9a055867781dd5d9e5c19be7ef812 Mon Sep 17 00:00:00 2001
From: Pierre-Louis BERTRAND <plbertrand@takima.fr>
Date: Sun, 8 Oct 2023 18:16:46 +0200
Subject: [PATCH] working new student

---
 back-skeleton/initdb/2_DEFAULT_ENTRIES.sql    | 13 ++++++--
 .../takima/backskeleton/DAO/CourseDao.java    |  9 ++++++
 .../controllers/CourseController.java         | 24 ++++++++++++++
 .../controllers/StudentController.java        |  6 ++++
 .../takima/backskeleton/models/Student.java   |  2 +-
 .../backskeleton/services/CourseService.java  | 20 ++++++++++++
 .../backskeleton/services/StudentService.java |  1 +
 .../src/main/resources/application.properties |  2 ++
 .../src/app/services/course.service.ts        |  2 +-
 .../src/app/services/student.service.ts       |  9 ++----
 .../student-details.component.html            | 21 ++++++------
 .../student-details.component.ts              | 32 ++++++++++++++++---
 .../src/app/students/students.component.html  |  5 ++-
 .../src/app/students/students.component.ts    |  9 +++---
 14 files changed, 124 insertions(+), 31 deletions(-)
 create mode 100644 back-skeleton/src/main/java/com/takima/backskeleton/DAO/CourseDao.java
 create mode 100644 back-skeleton/src/main/java/com/takima/backskeleton/controllers/CourseController.java
 create mode 100644 back-skeleton/src/main/java/com/takima/backskeleton/services/CourseService.java

diff --git a/back-skeleton/initdb/2_DEFAULT_ENTRIES.sql b/back-skeleton/initdb/2_DEFAULT_ENTRIES.sql
index ae5925a..321b728 100644
--- a/back-skeleton/initdb/2_DEFAULT_ENTRIES.sql
+++ b/back-skeleton/initdb/2_DEFAULT_ENTRIES.sql
@@ -1,8 +1,17 @@
 INSERT INTO majors (id, name, description) VALUES (1, 'MIN', 'Ouaiiis du code partout');
 
 INSERT INTO students (id, first_name, last_name, birthdate, major_id, image) VALUES (1, 'Paul', 'Harrohide', '2002-06-15', 1, null);
+INSERT INTO students (id, first_name, last_name, birthdate, major_id, image) VALUES (2, 'Jean', 'Bonbeur', '2001-08-21', 1, null);
+INSERT INTO students (id, first_name, last_name, birthdate, major_id, image) VALUES (3, 'Alain', 'Térieur', '2000-01-11', 1, null);
 
-INSERT INTO courses (id, name, hours) VALUES (1, 'Java', 30);
-INSERT INTO student_course (id, student_id, course_id) VALUES (1, 1, 1);
+INSERT INTO courses (id, name, hours) VALUES (1, 'Spanish', 30);
+INSERT INTO courses (id, name, hours) VALUES (2, 'German', 30);
+INSERT INTO courses (id, name, hours) VALUES (3, 'Internet of Things', 30);
+INSERT INTO courses (id, name, hours) VALUES (4, 'Thermodynamic', 30);
+INSERT INTO courses (id, name, hours) VALUES (5, 'Anatomy', 30);
+INSERT INTO courses (id, name, hours) VALUES (6, 'Maths', 30);
+INSERT INTO courses (id, name, hours) VALUES (7, 'Java', 30);
+INSERT INTO courses (id, name, hours) VALUES (8, 'Lean Management', 30);
+INSERT INTO student_course (id, student_id, course_id) VALUES (1, 1, 7);
 
 
diff --git a/back-skeleton/src/main/java/com/takima/backskeleton/DAO/CourseDao.java b/back-skeleton/src/main/java/com/takima/backskeleton/DAO/CourseDao.java
new file mode 100644
index 0000000..97657ed
--- /dev/null
+++ b/back-skeleton/src/main/java/com/takima/backskeleton/DAO/CourseDao.java
@@ -0,0 +1,9 @@
+package com.takima.backskeleton.DAO;
+
+import com.takima.backskeleton.models.Course;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CourseDao extends JpaRepository<Course, Long> {
+}
diff --git a/back-skeleton/src/main/java/com/takima/backskeleton/controllers/CourseController.java b/back-skeleton/src/main/java/com/takima/backskeleton/controllers/CourseController.java
new file mode 100644
index 0000000..b7425bf
--- /dev/null
+++ b/back-skeleton/src/main/java/com/takima/backskeleton/controllers/CourseController.java
@@ -0,0 +1,24 @@
+package com.takima.backskeleton.controllers;
+
+import com.takima.backskeleton.models.Course;
+import com.takima.backskeleton.services.CourseService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@CrossOrigin
+@RequestMapping("courses")
+@RestController
+@RequiredArgsConstructor
+public class CourseController {
+    private final CourseService courseService;
+
+    @GetMapping("")
+    public List<Course> getAllCourses() {
+        return courseService.findAll();
+    }
+}
diff --git a/back-skeleton/src/main/java/com/takima/backskeleton/controllers/StudentController.java b/back-skeleton/src/main/java/com/takima/backskeleton/controllers/StudentController.java
index 0b379e5..16c7382 100644
--- a/back-skeleton/src/main/java/com/takima/backskeleton/controllers/StudentController.java
+++ b/back-skeleton/src/main/java/com/takima/backskeleton/controllers/StudentController.java
@@ -5,6 +5,7 @@ import com.takima.backskeleton.models.Student;
 import com.takima.backskeleton.services.StudentService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
 
@@ -41,4 +42,9 @@ public class StudentController {
     public void updateStudent(@RequestBody StudentDto studentDto, @PathVariable Long id) {
         studentService.updateStudent(studentDto, id);
     }
+
+    @PostMapping("/{id}/picture")
+    public void editStudentPicture(@RequestPart("file") MultipartFile file) {
+
+    }
 }
diff --git a/back-skeleton/src/main/java/com/takima/backskeleton/models/Student.java b/back-skeleton/src/main/java/com/takima/backskeleton/models/Student.java
index 894e4ec..9370abe 100644
--- a/back-skeleton/src/main/java/com/takima/backskeleton/models/Student.java
+++ b/back-skeleton/src/main/java/com/takima/backskeleton/models/Student.java
@@ -24,7 +24,7 @@ public class Student {
             joinColumns = @JoinColumn(name = "student_id"),
             inverseJoinColumns = @JoinColumn(name = "course_id"))
     private List<Course> courses;
-    @ManyToOne()
+    @ManyToOne(cascade = CascadeType.MERGE)
     @JoinColumn(name = "major_id")
     private Major major;
     @Column(name = "image")
diff --git a/back-skeleton/src/main/java/com/takima/backskeleton/services/CourseService.java b/back-skeleton/src/main/java/com/takima/backskeleton/services/CourseService.java
new file mode 100644
index 0000000..68a553c
--- /dev/null
+++ b/back-skeleton/src/main/java/com/takima/backskeleton/services/CourseService.java
@@ -0,0 +1,20 @@
+package com.takima.backskeleton.services;
+
+import com.takima.backskeleton.DAO.CourseDao;
+import com.takima.backskeleton.models.Course;
+import com.takima.backskeleton.models.Major;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@RequiredArgsConstructor
+public class CourseService {
+    private final CourseDao courseDao;
+
+    public List<Course> findAll() {
+        return courseDao.findAll();
+    }
+}
diff --git a/back-skeleton/src/main/java/com/takima/backskeleton/services/StudentService.java b/back-skeleton/src/main/java/com/takima/backskeleton/services/StudentService.java
index f8a8b5a..cc1e205 100644
--- a/back-skeleton/src/main/java/com/takima/backskeleton/services/StudentService.java
+++ b/back-skeleton/src/main/java/com/takima/backskeleton/services/StudentService.java
@@ -43,6 +43,7 @@ public class StudentService {
         } catch (IOException e) {
             throw new RuntimeException("Error with Student image", e);
         }
+
         studentDao.save(student);
     }
 
diff --git a/back-skeleton/src/main/resources/application.properties b/back-skeleton/src/main/resources/application.properties
index ac2ecdf..fa51bd1 100644
--- a/back-skeleton/src/main/resources/application.properties
+++ b/back-skeleton/src/main/resources/application.properties
@@ -1,3 +1,5 @@
 spring.datasource.url=jdbc:postgresql://localhost:5432/${DATABASE_NAME}
 spring.datasource.username=${DATABASE_USER}
 spring.datasource.password=${DATABASE_PASSWORD}
+spring.servlet.multipart.max-file-size=10MB
+spring.servlet.multipart.max-request-size=10MB
\ No newline at end of file
diff --git a/epf-front-skeleton-main/src/app/services/course.service.ts b/epf-front-skeleton-main/src/app/services/course.service.ts
index bddda45..b0dd5b1 100644
--- a/epf-front-skeleton-main/src/app/services/course.service.ts
+++ b/epf-front-skeleton-main/src/app/services/course.service.ts
@@ -11,7 +11,7 @@ export class CourseService {
   constructor(private constantsMockService: ConstantsMockService, private http: HttpClient) {
   }
 
-  private coursesUrl = "http://localhost:8080/api/courses"
+  private coursesUrl = "http://localhost:8080/courses"
 
   // // FIXME : change to api call with httpclient
   // findAll(): Observable<Course[]> {
diff --git a/epf-front-skeleton-main/src/app/services/student.service.ts b/epf-front-skeleton-main/src/app/services/student.service.ts
index 0522c9a..310ae3f 100644
--- a/epf-front-skeleton-main/src/app/services/student.service.ts
+++ b/epf-front-skeleton-main/src/app/services/student.service.ts
@@ -20,11 +20,11 @@ export class StudentService {
   }
 
   findById(id: number): Observable<Student> {
-    return this.http.get<Student>(this.studentsUrl + `/${id}` )
+    return this.http.get<Student>(`${this.studentsUrl}/${id}`)
   }
 
   update(id: number, student: Student): Observable<Student> {
-    return this.http.post<Student>(this.studentsUrl + `/${id}`, student)
+    return this.http.post<Student>(`${this.studentsUrl}/${id}`, student)
   }
 
   create(student: Student): Observable<Student> {
@@ -32,10 +32,7 @@ export class StudentService {
   }
 
   delete(student: Student) {
-    const index = this.constantsMockService.students.indexOf(student)
-    if (index > -1) {
-      this.constantsMockService.students.splice(index, 1)
-    }
+    return this.http.delete(`${this.studentsUrl}/${student.id}`)
   }
 
   addCourseToStudent(student: Student, course: Course) {
diff --git a/epf-front-skeleton-main/src/app/students/student-details/student-details.component.html b/epf-front-skeleton-main/src/app/students/student-details/student-details.component.html
index ed5d893..46d69fb 100644
--- a/epf-front-skeleton-main/src/app/students/student-details/student-details.component.html
+++ b/epf-front-skeleton-main/src/app/students/student-details/student-details.component.html
@@ -3,10 +3,11 @@
   <form (ngSubmit)="save(student)" #studentForm="ngForm">
     <div class="form-group">
       <label for="image">Picture</label>
-      <input type="file" class="form-control" id="image"
+      <input type="file" class="form-control" id="image" (change)="onFileSelected($event)"
 
         [(ngModel)]="student.image" name="image">
     </div>
+
     <div class="form-group">
       <label for="firstName">First Name</label>
       <input type="text" class="form-control" id="firstName"
@@ -18,6 +19,7 @@
         First Name is required
       </div>
     </div>
+
     <div class="form-group">
       <label for="lastName">Last Name</label>
       <input type="text" class="form-control" id="lastName"
@@ -29,6 +31,7 @@
         Last Name is required
       </div>
     </div>
+
     <div class="form-group">
       <label for="birthDate">Birthdate</label>
       <input type="date" class="form-control" id="birthDate"
@@ -40,17 +43,15 @@
         Birthdate is required
       </div>
     </div>
-    <div class="form-group">
+
+    <div *ngIf="allMajors$ | async; let allMajors" class="form-group">
       <label for="major">Major</label>
-      <input type="text" class="form-control" id="major"
-             required
-             [(ngModel)]="student.major!!.name" name="major"
-             #major="ngModel">
-      <div [hidden]="major.valid || major.pristine"
-           class="alert alert-danger">
-        Major is required
-      </div>
+      <select id="major" [(ngModel)]="majorSelectModel" name="majors" class="form-control">
+        <option [ngValue]="null" [disabled]="true">Select a major</option>
+        <option *ngFor="let major of allMajors" [ngValue]="major">{{major.name}}</option>
+      </select>
     </div>
+
     <div class="student-courses">
       <div class="d-flex align-items-center">
         <h3 class="courses-title">Courses</h3>
diff --git a/epf-front-skeleton-main/src/app/students/student-details/student-details.component.ts b/epf-front-skeleton-main/src/app/students/student-details/student-details.component.ts
index ab90308..e5e35f5 100644
--- a/epf-front-skeleton-main/src/app/students/student-details/student-details.component.ts
+++ b/epf-front-skeleton-main/src/app/students/student-details/student-details.component.ts
@@ -1,10 +1,12 @@
-import { Component } from "@angular/core"
+import { Component, OnInit } from "@angular/core"
 import { map, Observable } from "rxjs"
 import { Student } from "models/student.model"
 import { ActivatedRoute, Router } from "@angular/router"
 import { Course } from "models/course.model"
 import { CourseService } from "services/course.service"
 import { StudentService } from "services/student.service"
+import { Major } from "../../models/major.model"
+import { MajorService } from "../../services/major.service"
 
 @Component({
   selector: "epf-student-details",
@@ -13,17 +15,22 @@ import { StudentService } from "services/student.service"
 })
 export class StudentDetailsComponent {
   student$: Observable<Student> = this._route.data.pipe(map((data) => data["student"]))
+  allMajors$: Observable<Major[]> | undefined
   allCourses$: Observable<Course[]> | undefined
+  majorSelectModel: Major | null = null
   courseSelectModel: Course | null = null
   notSelectedCourse: boolean | undefined
   today = new Date(Date.now())
+  selectedFile: File | null = null
 
   constructor(
     private _route: ActivatedRoute,
     private courseService: CourseService,
     private studentService: StudentService,
+    private majorService: MajorService,
     private router: Router,
   ) {
+    this.allMajors$ = this.majorService.findAll()
   }
 
   courseClick() {
@@ -42,14 +49,31 @@ export class StudentDetailsComponent {
     this.studentService.removeCourseToStudent(student, course)
   }
 
+  onFileSelected(event: any) {
+    this.selectedFile = event.target.files[0]
+  }
+
   save(student: Student) {
     const id = this._route.snapshot.params["id"]
+
+    if (this.selectedFile !== null) {
+      const formData = new FormData()
+      formData.append('file', this.selectedFile)
+    }
+
+    if (this.majorSelectModel !== null) {
+      student.major = this.majorSelectModel
+    }
+
     if (id == "new") {
-      this.studentService.create(student).subscribe()
+      this.studentService.create(student).subscribe(() => {
+        this.router.navigate(["students"])
+      })
     } else {
-      this.studentService.update(id, student).subscribe() // todo mettre à jour le listing
+      this.studentService.update(id, student).subscribe(() => {
+        this.router.navigate(["students"])
+      })
     }
-    this.router.navigate(["students"])
   }
 
   // because the format of the date doesn't fit date picker
diff --git a/epf-front-skeleton-main/src/app/students/students.component.html b/epf-front-skeleton-main/src/app/students/students.component.html
index 35fb895..2af75c7 100644
--- a/epf-front-skeleton-main/src/app/students/students.component.html
+++ b/epf-front-skeleton-main/src/app/students/students.component.html
@@ -17,15 +17,14 @@
   <tbody>
   <tr *ngFor="let student of (students$ | async)" routerLink="/student-details/{{student.id}}">
     <td>
-      <img src="assets/defaultPicture.svg" alt="Photo manquante">
-<!--  todo remplacer cette image par celle récupéré dans le backend -->
+      <img [src]="student.image" alt="Pas de photo">
     </td>
     <td>{{ student.firstName }}</td>
     <td>{{ student.lastName }}</td>
     <td>{{ student.birthdate | date : "dd/MM/yyyy" }}</td>
     <td>{{ student.major!!.name }}</td>
     <td>
-      <button mat-icon-button color="warn" (click)="deleteStudent(student)">
+      <button mat-icon-button color="warn" (click)="deleteStudent($event, student)">
         <mat-icon>delete</mat-icon>
       </button>
     </td>
diff --git a/epf-front-skeleton-main/src/app/students/students.component.ts b/epf-front-skeleton-main/src/app/students/students.component.ts
index d83297a..7b41c90 100644
--- a/epf-front-skeleton-main/src/app/students/students.component.ts
+++ b/epf-front-skeleton-main/src/app/students/students.component.ts
@@ -1,7 +1,7 @@
 import { Component } from "@angular/core"
 import { map, Observable } from "rxjs"
 import { Student } from "models/student.model"
-import { ActivatedRoute } from "@angular/router"
+import { ActivatedRoute, Router } from "@angular/router"
 import { StudentService } from "services/student.service"
 
 @Component({
@@ -12,11 +12,12 @@ import { StudentService } from "services/student.service"
 export class StudentsComponent {
   students$: Observable<Student[]> = this._route.data.pipe(map((data) => data["students"]))
 
-  constructor(private _route: ActivatedRoute, private studentService: StudentService) {
+  constructor(private _route: ActivatedRoute, private studentService: StudentService, private router: Router,) {
   }
 
-  deleteStudent(student: Student) {
-    this.studentService.delete(student)
+  deleteStudent(event: any, student: Student) {
+    event.stopPropagation()
+    this.studentService.delete(student).subscribe(() => this.router.navigate(["students"]))
   }
 
   searchByMajorAndCourse($event: Observable<Student[]>) {
-- 
GitLab