Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/swagger docs #17

Open
wants to merge 19 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8ed2721
Feat: create birthdate validator
filipeferreirasoriano Apr 11, 2024
c9d42c2
Feat: added new fields and validation to student registration
filipeferreirasoriano Apr 15, 2024
8463e49
fix: adding new fields in Student model, and removing others in User …
ricardovinicius Apr 15, 2024
67fc311
fix: adding setEntryDate to current system date
ricardovinicius Apr 15, 2024
4598b96
fix: adding new fields in StudentResponseDTO
ricardovinicius Apr 15, 2024
2f09001
Merge branch 'feature/users' into feature/student-model-and-persistence
daviromao Apr 16, 2024
df40308
todo: temporarily disable test
daviromao Apr 16, 2024
ea9c053
fix: adding other fields in StudentResponseDTO
ricardovinicius Apr 16, 2024
83f234e
fix: adding other fields in StudentResponseDTO
ricardovinicius Apr 16, 2024
2f78f5d
fix: changing birthDate type and camelcase in var name, also adding n…
ricardovinicius Apr 16, 2024
76cde66
fix: setting EntryDate as null back
ricardovinicius Apr 16, 2024
ba92d98
fix: adding photoUrl column in User model back
ricardovinicius Apr 16, 2024
5fc3ac9
fix: add birthDate as string again
ricardovinicius Apr 16, 2024
9eb229b
feat softdelete (#12)
ricardovinicius Apr 16, 2024
d1c9ec9
feat: adding swagger and springdoc dependencies
ricardovinicius Apr 18, 2024
e331498
feat: Setting the API title and version on Swagger
ricardovinicius Apr 19, 2024
1f570d4
feat: Adding summary of each endpoint and they parameters
ricardovinicius Apr 19, 2024
a0dbbbf
feat: Adding schemas descriptions and examples for each DTO
ricardovinicius Apr 19, 2024
6842474
feat: Setting configs of Swagger in application.properties
ricardovinicius Apr 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'com.auth0:java-jwt:4.3.0'
implementation 'org.modelmapper:modelmapper:3.0.0'
// https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package com.academy.edge.studentmanager;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand All @@ -8,6 +13,9 @@
import org.springframework.security.crypto.password.PasswordEncoder;

@SpringBootApplication
@OpenAPIDefinition(
info = @Info(title = "Student Manager", version = "1.0.0"))
@SecurityScheme(type = SecuritySchemeType.APIKEY, name = "JWT", in = SecuritySchemeIn.HEADER)
public class StudentManagerApplication {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.academy.edge.studentmanager.dtos.SignInRequestDTO;
import com.academy.edge.studentmanager.models.User;
import com.academy.edge.studentmanager.services.AuthService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -16,7 +17,9 @@
@RequiredArgsConstructor
public class AuthController {
final AuthService authService;

@PostMapping("/login")
@Operation(summary = "Authenticate in the server and retrieves the JWT Token")
public ResponseEntity<JwtAuthResponseDTO> signIn(@Valid @RequestBody SignInRequestDTO requestDTO){
String jwt = authService.login(requestDTO);
JwtAuthResponseDTO responseDTO = new JwtAuthResponseDTO();
Expand All @@ -26,6 +29,7 @@ public ResponseEntity<JwtAuthResponseDTO> signIn(@Valid @RequestBody SignInReque

// TODO: temporary endpoint for getting the current user
@GetMapping("/me")
@Operation(summary = "Temporary endpoint for getting the current user")
public ResponseEntity<User> me(@AuthenticationPrincipal User user){
user.setPassword(null);
return new ResponseEntity<>(user, HttpStatus.OK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.academy.edge.studentmanager.dtos.InstructorResponseDTO;
import com.academy.edge.studentmanager.services.InstructorService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -25,12 +28,14 @@ public InstructorController(InstructorService instructorService) {
}

@GetMapping
@Operation(summary = "Retrieve all Instructors infos", security = {@SecurityRequirement(name = "JWT")})
public ResponseEntity<List<InstructorResponseDTO>> getAllInstructors(){
return new ResponseEntity<>(instructorService.getAllInstructors(), HttpStatus.OK);
}

@GetMapping({"/{email}"})
public ResponseEntity<InstructorResponseDTO> getInstructor(@PathVariable String email){
@Operation(summary = "Retrieve instructors by email", security = {@SecurityRequirement(name = "JWT")})
public ResponseEntity<InstructorResponseDTO> getInstructor(@Parameter(description = "Email of searched Instructor") @PathVariable String email){
return new ResponseEntity<>(instructorService.getInstructorByEmail(email), HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.academy.edge.studentmanager.dtos.InvitationRequestDTO;
import com.academy.edge.studentmanager.dtos.InvitationResponseDTO;
import com.academy.edge.studentmanager.services.InvitationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
Expand All @@ -26,6 +28,7 @@ public InvitationController(InvitationService invitationService) {

@PostMapping
@PreAuthorize("hasAnyRole('ADMIN', 'INSTRUCTOR')")
@Operation(summary = "Invite students by a list of valid emails", security = {@SecurityRequirement(name = "JWT")})
public ResponseEntity<InvitationResponseDTO> register(@Valid @RequestBody InvitationRequestDTO invitationRequestDTO) {
return new ResponseEntity<>(invitationService.sendInvitation(invitationRequestDTO.getEmails()), HttpStatus.MULTI_STATUS);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import com.academy.edge.studentmanager.dtos.StudentCreateDTO;
import com.academy.edge.studentmanager.dtos.StudentResponseDTO;
import com.academy.edge.studentmanager.services.StudentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -22,24 +25,28 @@ public StudentController(StudentService studentService) {

@GetMapping
@PreAuthorize("hasAnyRole('ADMIN','INSTRUCTOR')")
@Operation(summary = "Retrieve all Students infos", security = {@SecurityRequirement(name = "JWT")})
public ResponseEntity<List<StudentResponseDTO>> getAllStudents(){
return new ResponseEntity<>(studentService.getStudents(), HttpStatus.OK);
}

@GetMapping({"/{email}"})
@PreAuthorize("hasAnyRole('ADMIN','INSTRUCTOR') or authentication.name == #email")
public ResponseEntity<StudentResponseDTO> getStudent(@PathVariable String email){
@Operation(summary = "Retrieve Student info by email", security = {@SecurityRequirement(name = "JWT")})
public ResponseEntity<StudentResponseDTO> getStudent(@Parameter(description = "Email of searched Student") @PathVariable String email){
return new ResponseEntity<>(studentService.getStudentByEmail(email), HttpStatus.OK);
}

@PostMapping()
@Operation(summary = "Create Student")
public ResponseEntity<StudentResponseDTO> saveStudent(@Valid @RequestBody StudentCreateDTO studentCreateDTO){
return new ResponseEntity<>(studentService.insertStudent(studentCreateDTO), HttpStatus.CREATED);
}

@DeleteMapping({"/{email}"})
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<Void> deleteStudent(@PathVariable String email){
@Operation(summary = "Delete Student by email (SoftDelete)", security = {@SecurityRequirement(name = "JWT")})
public ResponseEntity<Void> deleteStudent(@Parameter(description = "Email of deleted Student") @PathVariable String email){
studentService.deleteStudent(email);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.academy.edge.studentmanager.dtos;

import com.academy.edge.studentmanager.enums.InstructorSpecialization;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class InstructorResponseDTO {
@Schema(description = "Instructor UUID", example = "f4e5e0a6-8a4a-4c0e-8e3e-1e2b7f8c9d0e")
private String id;
@Schema(description = "Instructor Name", example = "Cookie Monster")
private String name;
private String about;
@Schema(description = "Instructor Photo URL", example = "https://example.com/images/image.jpg")
private String photoUrl;
private String linkedIn;
@Schema(description = "Instructor Specialization", example = "TECHNICAL")
private InstructorSpecialization specialization;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import com.academy.edge.studentmanager.validators.EmailCollection;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.List;
Expand All @@ -10,5 +11,6 @@
public class InvitationRequestDTO {

@EmailCollection
@Schema(description = "List of Emails for Invitation", example = "[elmo@edge.ufal.br, bert@edge.ufal.br]")
private List<String> emails;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.academy.edge.studentmanager.dtos;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class InvitationResponseDTO {
@Schema(description = "List of successful invitation emails", example = "[ernie@edge.ufal.br, snuffy@edge.ufal.br]")
private List<String> successfulEmails= new ArrayList<>();

@Schema(description = "List of failed invitation emails", example = "[chico.bento@ic.ufal.br, cebolinha@gmail.com]")
private List<String> failedEmails = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.academy.edge.studentmanager.dtos;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
public class JwtAuthResponseDTO {
@Schema(description = "JWT Token")
String token;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.academy.edge.studentmanager.dtos;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class SignInRequestDTO {
@Email
@Schema(description = "Email", example = "big.bird@edge.ufal.br")
private String email;

@Size(min = 8, max = 20)
@Schema(description = "Password", example = "Password123", pattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$")
private String password;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,67 @@

import com.academy.edge.studentmanager.enums.Course;
import com.academy.edge.studentmanager.validators.ValidBirthdate;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import lombok.AllArgsConstructor;
import lombok.Getter;


@Getter
@AllArgsConstructor()
public class StudentCreateDTO {
@NotBlank(message = "Nome é obrigatório")
@Schema(description = "Student Name", example = "Elmo")
private String name;

@NotBlank(message = "Insira uma data de nascimento")
@NotNull(message = "Insira uma data de nascimento")
@ValidBirthdate(message = "Informe uma data de nascimento válida")
private String birthdate;
@Schema(description = "Student Birth Date", example = "1985-02-03")
private String birthDate;

@NotBlank(message = "Insira um email")
@Email(message = "Email inválido")
@Schema(description = "Student Email", example = "elmo@edge.ufal.br")
private String email;

@NotBlank(message = "Insira uma senha")
@Size(min = 8, max = 20, message = "A senha deve estar entre 8 e 20 caracteres")
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$",
message = "A senha deve conter ao menos uma letra minúscula, uma maiúscula e um digito")
@Schema(description = "Password", example = "Password123")
private String password;

@NotNull(message = "Curso é obrigatório")
@Schema(description = "Student Course", example = "COMPUTER_SCIENCE")
private Course course;

@NotBlank(message = "Insira um número de matrícula")
@Pattern(regexp = "\\d+", message = "Informe uma matricula válida")
@Size(min = 8, max = 8, message = "Informe uma matrícula válida")
@Schema(description = "Student Registration Number", example = "20201234")
private String registration;

@NotBlank(message = "Insira um número de telefone")
@Pattern(regexp = "\\d{2}9\\d{8}", message = "Informe um número de telefone válido")
@Schema(description = "Student Primary Phone Number", example = "82940028922")
private String phone;

@Pattern(regexp = "(\\d{2}9\\d{8})|($)", message = "Informe um número de telefone secundário válido")
@Schema(description = "Student Secondary Phone Number", example = "82940028922")
private String secondaryPhone;

@NotNull(message = "Insira o periodo")
@Max(10)
@Min(1)
@Schema(description = "Student Current Academy Period", example = "4")
private int period;

@NotBlank(message = "Insira o periodo de entrada no curso")
@Pattern(regexp = "\\d{4}\\.[1-2]", message = "Informe um periodo válido")
@Schema(description = "Student Entry Academy Year (Period)", example = "2021.2")
private String entryPeriod;

@NotBlank(message = "Código de ativação é obrigatório")
@Schema(description = "Student Activation Code of Invitation")
private String activationCode;
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,54 @@
package com.academy.edge.studentmanager.dtos;

import com.academy.edge.studentmanager.enums.Course;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentResponseDTO {
@Schema(description = "Student UUID", example = "f4e5e0a6-8a4a-4c0e-8e3e-1e2b7f8c9d0e")
private String id;

@Schema(description = "Student Name", example = "Elmo")
private String name;
private String about;

@Schema(description = "Student Photo URL", example = "https://example.com/images/image.jpg")
private String photoUrl;
private String linkedIn;

@Schema(description = "Student Birth Date", example = "1985-02-03")
private Date birthDate;

@Schema(description = "Student Course", example = "COMPUTER_SCIENCE")
private Course course;

@Schema(description = "Student Registration Number", example = "20201234")
private String registration;

@Schema(description = "Student Primary Phone Number", example = "82940028922")
private String phone;

@Schema(description = "Student Secondary Phone Number", example = "82940028922")
private String secondaryPhone;

@Schema(description = "Student Current Academy Period", example = "4")
private String period;

@Schema(description = "Student Entry Academy Year (Period)", example = "2021.2")
private String entryPeriod;

@Schema(description = "User Dtype", example = "Student")
private String dtype;

@Schema(description = "Student Email", example = "elmo@edge.ufal.br")
private String email;

@Schema(description = "User Entry Date", example = "2024-01-01")
private Date entryDate;

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.academy.edge.studentmanager.models;

import com.academy.edge.studentmanager.enums.Course;
import com.academy.edge.studentmanager.enums.StudentStatus;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
Expand All @@ -14,6 +13,10 @@
@Table(name = "students")
@PrimaryKeyJoinColumn(name="id")
public class Student extends User{

@Column
private Date birthDate;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
Course course;
Expand All @@ -22,17 +25,16 @@ public class Student extends User{
String registration;

@Column(nullable = false)
int period = 1;
private String phone;

@Column()
String phone;
private String secondaryPhone;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
StudentStatus studentStatus = StudentStatus.ACTIVE;
int period = 1;

@Column(precision = 2)
float coefficient;
@Column(nullable = false)
private String entryPeriod;

@Column()
Date entryDate;
Expand Down
Loading