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