1
0

5 Коммиты a28da91827 ... bb43aecb1e

Автор SHA1 Сообщение Дата
  Eldar Mukhtarov bb43aecb1e Setup Security Configuration & Auth Message 10 месяцев назад
  Eldar Mukhtarov 44caf98610 Fix Relational Bigs 10 месяцев назад
  Eldar Mukhtarov 19f6d7085f Role Setup 10 месяцев назад
  Eldar Mukhtarov d52ae0d60c Grade CRUD and Relationships Setup 10 месяцев назад
  Eldar Mukhtarov b209e4391b Setup Subject CRUD and Teacher-Subject Relation 10 месяцев назад
27 измененных файлов с 907 добавлено и 52 удалено
  1. 5 5
      project/backend_springboot/pom.xml
  2. 77 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/GradeController.java
  3. 11 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/StudentController.java
  4. 80 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/SubjectController.java
  5. 10 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/TeacherController.java
  6. 31 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/request/LoginForm.java
  7. 62 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/request/SignUpForm.java
  8. 47 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/response/JwtResponse.java
  9. 18 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/response/ResponseMessage.java
  10. 11 9
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Account.java
  11. 55 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Grade.java
  12. 38 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Role.java
  13. 7 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/RoleName.java
  14. 17 16
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Student.java
  15. 39 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Subject.java
  16. 17 16
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Teacher.java
  17. 14 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/GradeRepository.java
  18. 13 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/RoleRepository.java
  19. 1 1
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/StudentRepository.java
  20. 11 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/SubjectRepository.java
  21. 80 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/WebSecurityConfig.java
  22. 21 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/jwt/JwtAuthEntryPoint.java
  23. 54 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/jwt/JwtAuthTokenFilter.java
  24. 65 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/jwt/JwtProvider.java
  25. 26 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/services/UserDetailsServiceImpl.java
  26. 92 0
      project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/services/UserPrinciple.java
  27. 5 5
      project/backend_springboot/src/main/resources/application.properties

+ 5 - 5
project/backend_springboot/pom.xml

@@ -67,11 +67,11 @@
 			<artifactId>jackson-dataformat-xml</artifactId>
 			<version>2.18.3</version>
 		</dependency>
-		<!-- spring security ____________________________________________ UNCOMMENT LATER ON -->
-<!--		<dependency>-->
-<!--			<groupId>org.springframework.boot</groupId>-->
-<!--			<artifactId>spring-boot-starter-security</artifactId>-->
-<!--		</dependency>-->
+		<!-- spring security -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-security</artifactId>
+		</dependency>
 		<!-- JWT -->
 		<dependency>
 			<groupId>io.jsonwebtoken</groupId>

+ 77 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/GradeController.java

@@ -0,0 +1,77 @@
+package pl.dmcs.eldarmuk.backend_springboot.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import pl.dmcs.eldarmuk.backend_springboot.model.Account;
+import pl.dmcs.eldarmuk.backend_springboot.model.Grade;
+import pl.dmcs.eldarmuk.backend_springboot.model.Student;
+import pl.dmcs.eldarmuk.backend_springboot.repository.AccountRepository;
+import pl.dmcs.eldarmuk.backend_springboot.repository.GradeRepository;
+import pl.dmcs.eldarmuk.backend_springboot.repository.StudentRepository;
+
+import java.util.List;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:4200")
+@RequestMapping("/grades")
+public class GradeController {
+    private GradeRepository gradeRepository;
+    private AccountRepository accountRepository;
+    private StudentRepository studentRepository;
+
+    @Autowired
+    public GradeController(GradeRepository gradeRepository, AccountRepository accountRepository, StudentRepository studentRepository) {
+        this.gradeRepository = gradeRepository;
+        this.accountRepository = accountRepository;
+        this.studentRepository = studentRepository;
+    }
+
+    @GetMapping(value = "/subject/{id}")
+    public List<Grade> findGradesBySubject(@PathVariable("id") long id){
+        return gradeRepository.findGradesBySubjectId(id);
+    }
+
+    @GetMapping(value = "/student/{username}")
+    public ResponseEntity<List<Grade>> findGradesByStudent(@PathVariable("username") String username){
+        try {
+            Account account = accountRepository.findByUsername(username)
+                    .orElseThrow(() -> new RuntimeException("Error: User not found!"));
+            Student student = studentRepository.findByAccountUsername(account.getUsername());
+            List<Grade> grades = gradeRepository.findGradesByStudentId(student.getId());
+            return new ResponseEntity<>(grades, HttpStatus.OK);
+        } catch (Exception e) {
+            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+        }
+    }
+
+    @PostMapping
+    public ResponseEntity<Grade> addGrade(@RequestBody Grade grade){
+        try {
+            gradeRepository.save(grade);
+            return new ResponseEntity<>(grade, HttpStatus.CREATED);
+        } catch (Exception e) {
+            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @PatchMapping(value = "/edit/{id}")
+    public ResponseEntity<Grade> editGrade(@PathVariable("id") long id, @RequestBody java.util.Map<String, Integer> body){
+        try {
+            Grade currentGrade = gradeRepository.findById(id);
+            if (currentGrade == null){
+                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+            }
+            Integer grade = body.get("grade");
+            if (grade == null) {
+                return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+            }
+            currentGrade.setGrade(grade);
+            gradeRepository.save(currentGrade);
+            return new ResponseEntity<>(currentGrade, HttpStatus.OK);
+        } catch (Exception e) {
+            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+}

+ 11 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/StudentController.java

@@ -1,6 +1,7 @@
 package pl.dmcs.eldarmuk.backend_springboot.controller;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
@@ -25,6 +26,16 @@ public class StudentController {
         return studentRepository.findAll();
     }
 
+    @PostMapping
+    public ResponseEntity<Student> createStudent(@RequestBody Student student) {
+        try {
+            Student savedStudent = studentRepository.save(student);
+            return new ResponseEntity<>(savedStudent, HttpStatus.CREATED);
+        } catch (Exception e) {
+            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
     @DeleteMapping("/{id}")
     public ResponseEntity<?> deleteStudent(@PathVariable("id") long id) {
         try {

+ 80 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/SubjectController.java

@@ -0,0 +1,80 @@
+package pl.dmcs.eldarmuk.backend_springboot.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import pl.dmcs.eldarmuk.backend_springboot.model.Subject;
+import pl.dmcs.eldarmuk.backend_springboot.model.Teacher;
+import pl.dmcs.eldarmuk.backend_springboot.repository.AccountRepository;
+import pl.dmcs.eldarmuk.backend_springboot.repository.SubjectRepository;
+import pl.dmcs.eldarmuk.backend_springboot.repository.TeacherRepository;
+
+import java.util.List;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:4200")
+@RequestMapping("/subjects")
+public class SubjectController {
+    private SubjectRepository subjectRepository;
+    private AccountRepository accountRepository;
+    private TeacherRepository teacherRepository;
+
+    @Autowired
+    public SubjectController(SubjectRepository subjectRepository, AccountRepository accountRepository, TeacherRepository teacherRepository) {
+        this.subjectRepository = subjectRepository;
+        this.accountRepository = accountRepository;
+        this.teacherRepository = teacherRepository;
+    }
+
+    @GetMapping
+    public List<Subject> findAllSubjects() {
+        return subjectRepository.findAll();
+    }
+
+    @GetMapping(value = "/{id}")
+    public ResponseEntity<Subject> findSubject(@PathVariable("id") long id){
+        try {
+            Subject subject = subjectRepository.findById(id);
+            if (subject == null){
+                System.out.println("Subject with id " + id + " not found");
+                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+            }
+            return new ResponseEntity<>(subject, HttpStatus.OK);
+        } catch (Exception e) {
+            System.out.println("Error finding subject: " + e.getMessage());
+            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @PostMapping
+    public ResponseEntity<?> addSubject(@RequestBody Subject subject){
+        try {
+            if(subjectRepository.existsByName(subject.getName())){
+                return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+            }
+            subjectRepository.save(subject);
+            return new ResponseEntity<>(subject, HttpStatus.CREATED);
+        } catch (Exception e) {
+            System.out.println("Error adding subject: " + e.getMessage());
+            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @DeleteMapping(value = "/{id}")
+    public ResponseEntity<Subject> deleteSubject(@PathVariable("id") long id){
+        try {
+            Subject subject = subjectRepository.findById(id);
+            if (subject == null){
+                System.out.println("Subject with id " + id + " not found");
+                return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+            }
+            subjectRepository.delete(subject);
+            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+        } catch (Exception e) {
+            System.out.println("Error deleting subject: " + e.getMessage());
+            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+}

+ 10 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/controller/TeacherController.java

@@ -37,6 +37,16 @@ public class TeacherController {
             return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
         }
     }
+    
+    @PostMapping
+    public ResponseEntity<Teacher> createTeacher(@RequestBody Teacher teacher) {
+        try {
+            Teacher savedTeacher = teacherRepository.save(teacher);
+            return new ResponseEntity<>(savedTeacher, HttpStatus.CREATED);
+        } catch (Exception e) {
+            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
 
     @DeleteMapping("/{id}")
     public ResponseEntity<?> deleteTeacher(@PathVariable("id") long id) {

+ 31 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/request/LoginForm.java

@@ -0,0 +1,31 @@
+package pl.dmcs.eldarmuk.backend_springboot.message.request;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+
+public class LoginForm {
+
+    @NotBlank
+    @Size(min=3, max = 60)
+    private String username;
+
+    @NotBlank
+    @Size(min = 6, max = 40)
+    private String password;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 62 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/request/SignUpForm.java

@@ -0,0 +1,62 @@
+package pl.dmcs.eldarmuk.backend_springboot.message.request;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+
+import java.util.Set;
+
+public class SignUpForm {
+
+    @NotBlank
+    @Size(min = 3, max = 50)
+    private String username;
+
+    private Set<String> role;
+
+    @NotBlank
+    @Size(min = 6, max = 40)
+    private String password;
+
+    private String firstname;
+    private String lastname;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Set<String> getRole() {
+        return role;
+    }
+
+    public void setRole(Set<String> role) {
+        this.role = role;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getFirstname() {
+        return firstname;
+    }
+
+    public void setFirstname(String firstname) {
+        this.firstname = firstname;
+    }
+
+    public String getLastname() {
+        return lastname;
+    }
+
+    public void setLastname(String lastname) {
+        this.lastname = lastname;
+    }
+}

+ 47 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/response/JwtResponse.java

@@ -0,0 +1,47 @@
+package pl.dmcs.eldarmuk.backend_springboot.message.response;
+
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Collection;
+
+public class JwtResponse {
+
+    private String token;
+    private String type = "Bearer";
+    private String username;
+    private Collection<? extends GrantedAuthority> authorities;
+
+    public JwtResponse(String token, String username, Collection<? extends GrantedAuthority> authorities) {
+        this.token = token;
+        this.username = username;
+        this.authorities = authorities;
+    }
+
+    public String getAccessToken() {
+        return token;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.token = accessToken;
+    }
+
+    public String getTokenType() {
+        return type;
+    }
+
+    public void setTokenType(String tokenType) {
+        this.type = tokenType;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return authorities;
+    }
+}

+ 18 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/message/response/ResponseMessage.java

@@ -0,0 +1,18 @@
+package pl.dmcs.eldarmuk.backend_springboot.message.response;
+
+public class ResponseMessage {
+
+    private String message;
+
+    public ResponseMessage(String message) {
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 11 - 9
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Account.java

@@ -1,13 +1,13 @@
 package pl.dmcs.eldarmuk.backend_springboot.model;
 
+import jakarta.persistence.*;
 import org.hibernate.validator.constraints.Length;
 
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.GenerationType;
-import jakarta.persistence.Id;
 import jakarta.validation.constraints.NotBlank;
 
+import java.util.HashSet;
+import java.util.Set;
+
 @Entity
 public class Account {
     @Id
@@ -21,7 +21,9 @@ public class Account {
     @NotBlank
     @Length(min = 6, max = 100)
     private String password;
-    private String email;
+
+    @ManyToMany(fetch = FetchType.EAGER)
+    private Set<Role> roles = new HashSet<>();
 
     public Account() {}
 
@@ -54,11 +56,11 @@ public class Account {
         this.password = password;
     }
 
-    public String getEmail() {
-        return email;
+    public Set<Role> getRoles() {
+        return roles;
     }
 
-    public void setEmail(String email) {
-        this.email = email;
+    public void setRoles(Set<Role> roles) {
+        this.roles = roles;
     }
 }

+ 55 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Grade.java

@@ -0,0 +1,55 @@
+package pl.dmcs.eldarmuk.backend_springboot.model;
+
+import jakarta.persistence.*;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+
+@Entity
+public class Grade {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private long id;
+
+    @Min(2)
+    @Max(5)
+    private int grade;
+
+    @ManyToOne
+    private Student student;
+
+    @ManyToOne
+    private Subject subject;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public int getGrade() {
+        return grade;
+    }
+
+    public void setGrade(int grade) {
+        this.grade = grade;
+    }
+
+    public Student getStudent() {
+        return student;
+    }
+
+    public void setStudent(Student student) {
+        this.student = student;
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+}

+ 38 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Role.java

@@ -0,0 +1,38 @@
+package pl.dmcs.eldarmuk.backend_springboot.model;
+
+import jakarta.persistence.*;
+import org.hibernate.annotations.NaturalId;
+
+@Entity
+public class Role {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private long id;
+
+    @Enumerated(EnumType.STRING)
+    @NaturalId
+    private RoleName name;
+
+    public Role() {}
+
+    public Role(RoleName name) {
+        this.name = name;
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public RoleName getName() {
+        return name;
+    }
+
+    public void setName(RoleName name) {
+        this.name = name;
+    }
+}

+ 7 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/RoleName.java

@@ -0,0 +1,7 @@
+package pl.dmcs.eldarmuk.backend_springboot.model;
+
+public enum RoleName {
+    ROLE_STUDENT,
+    ROLE_TEACHER,
+    ROLE_ADMIN
+}

+ 17 - 16
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Student.java

@@ -1,11 +1,9 @@
 package pl.dmcs.eldarmuk.backend_springboot.model;
 
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.GenerationType;
-import jakarta.persistence.Id;
-import jakarta.persistence.OneToOne;
-import jakarta.persistence.CascadeType;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import jakarta.persistence.*;
+
+import java.util.List;
 
 @Entity
 public class Student {
@@ -14,18 +12,21 @@ public class Student {
     private Long id;
     private String firstName;
     private String lastName;
-    private String email;
 
     @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "account_id")
     private Account account;
 
+    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL)
+    @JsonIgnore
+    private List<Grade> grades;
+
     public Student() {}
 
     public Student(Long id, String firstName, String lastName, String email) {
         this.id = id;
         this.firstName = firstName;
         this.lastName = lastName;
-        this.email = email;
     }
 
     public Long getId() {
@@ -52,14 +53,6 @@ public class Student {
         this.lastName = lastName;
     }
 
-    public String getEmail() {
-        return email;
-    }
-
-    public void setEmail(String email) {
-        this.email = email;
-    }
-
     public Account getAccount() {
         return account;
     }
@@ -67,4 +60,12 @@ public class Student {
     public void setAccount(Account account) {
         this.account = account;
     }
+
+    public List<Grade> getGrades() {
+        return grades;
+    }
+
+    public void setGrades(List<Grade> grades) {
+        this.grades = grades;
+    }
 }

+ 39 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Subject.java

@@ -0,0 +1,39 @@
+package pl.dmcs.eldarmuk.backend_springboot.model;
+
+import jakarta.persistence.*;
+
+@Entity
+public class Subject {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private long id;
+
+    private String name;
+
+    @ManyToOne
+    private Teacher teacher;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Teacher getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(Teacher teacher) {
+        this.teacher = teacher;
+    }
+}

+ 17 - 16
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/model/Teacher.java

@@ -1,11 +1,9 @@
 package pl.dmcs.eldarmuk.backend_springboot.model;
 
-import jakarta.persistence.CascadeType;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.GenerationType;
-import jakarta.persistence.Id;
-import jakarta.persistence.OneToOne;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import jakarta.persistence.*;
+
+import java.util.List;
 
 @Entity
 public class Teacher {
@@ -14,18 +12,21 @@ public class Teacher {
     private Long id;
     private String firstName;
     private String lastName;
-    private String email;
 
     @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "account_id")
     private Account account;
 
+    @OneToMany(mappedBy="teacher", cascade = CascadeType.ALL)
+    @JsonIgnore
+    private List<Subject> subjects;
+
     public Teacher() {}
 
     public Teacher(Long id, String firstName, String lastName, String email) {
         this.id = id;
         this.firstName = firstName;
         this.lastName = lastName;
-        this.email = email;
     }
 
     public Long getId() {
@@ -52,14 +53,6 @@ public class Teacher {
         this.lastName = lastName;
     }
 
-    public String getEmail() {
-        return email;
-    }
-
-    public void setEmail(String email) {
-        this.email = email;
-    }
-
     public Account getAccount() {
         return account;
     }
@@ -67,4 +60,12 @@ public class Teacher {
     public void setAccount(Account account) {
         this.account = account;
     }
+
+    public List<Subject> getSubjects() {
+        return subjects;
+    }
+
+    public void setSubjects(List<Subject> subjects) {
+        this.subjects = subjects;
+    }
 }

+ 14 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/GradeRepository.java

@@ -0,0 +1,14 @@
+package pl.dmcs.eldarmuk.backend_springboot.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import pl.dmcs.eldarmuk.backend_springboot.model.Grade;
+
+import java.util.List;
+
+@Repository
+public interface GradeRepository extends JpaRepository<Grade, Long> {
+    Grade findById(long id);
+    List<Grade> findGradesByStudentId(long id);
+    List<Grade> findGradesBySubjectId(long id);
+}

+ 13 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/RoleRepository.java

@@ -0,0 +1,13 @@
+package pl.dmcs.eldarmuk.backend_springboot.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import pl.dmcs.eldarmuk.backend_springboot.model.Role;
+import pl.dmcs.eldarmuk.backend_springboot.model.RoleName;
+
+import java.util.Optional;
+
+@Repository
+public interface RoleRepository extends JpaRepository<Role, Long> {
+    Optional<Role> findByName(RoleName roleName);
+}

+ 1 - 1
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/StudentRepository.java

@@ -1,8 +1,8 @@
 package pl.dmcs.eldarmuk.backend_springboot.repository;
 
+import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
 import pl.dmcs.eldarmuk.backend_springboot.model.Student;
-import org.springframework.data.jpa.repository.JpaRepository;
 
 @Repository
 public interface StudentRepository extends JpaRepository<Student, Long> {

+ 11 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/repository/SubjectRepository.java

@@ -0,0 +1,11 @@
+package pl.dmcs.eldarmuk.backend_springboot.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import pl.dmcs.eldarmuk.backend_springboot.model.Subject;
+
+@Repository
+public interface SubjectRepository extends JpaRepository<Subject, Long> {
+    Subject findById(long id);
+    boolean existsByName(String name);
+}

+ 80 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/WebSecurityConfig.java

@@ -0,0 +1,80 @@
+package pl.dmcs.eldarmuk.backend_springboot.security;
+
+import jakarta.servlet.DispatcherType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import pl.dmcs.eldarmuk.backend_springboot.security.jwt.JwtAuthEntryPoint;
+import pl.dmcs.eldarmuk.backend_springboot.security.jwt.JwtAuthTokenFilter;
+import pl.dmcs.eldarmuk.backend_springboot.security.services.UserDetailsServiceImpl;
+
+@Configuration
+@EnableWebSecurity
+@EnableMethodSecurity
+public class WebSecurityConfig {
+
+    @Autowired
+    UserDetailsServiceImpl userDetailsService;
+
+    @Autowired
+    private JwtAuthEntryPoint unauthorizedHandler;
+
+    @Bean
+    public JwtAuthTokenFilter authenticationJwtTokenFilter() {
+        return new JwtAuthTokenFilter();
+    }
+
+    @Bean
+    DaoAuthenticationProvider authProvider(){
+        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
+        authProvider.setUserDetailsService(userDetailsService);
+        authProvider.setPasswordEncoder(passwordEncoder());
+        return authProvider;
+    }
+
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+
+        http
+                .cors(Customizer.withDefaults())
+                .csrf(AbstractHttpConfigurer::disable)
+                .authorizeHttpRequests((auth) -> auth
+                        .requestMatchers("/auth/**").permitAll()
+                        .requestMatchers("/students/**").permitAll()
+                        .requestMatchers("/teachers/**").permitAll()
+                        .requestMatchers("/subjects/**").permitAll()
+                        .requestMatchers("/grades/**").permitAll()
+                        .requestMatchers("/error").permitAll() // this enables the body in the exception responses
+                        .anyRequest().authenticated()
+                )
+                .exceptionHandling(unauthorized -> unauthorized
+                        .authenticationEntryPoint(unauthorizedHandler)
+                )
+                .sessionManagement(session -> session
+                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS));
+
+        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
+        return http.build();
+    }
+}
+
+
+
+
+

+ 21 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/jwt/JwtAuthEntryPoint.java

@@ -0,0 +1,21 @@
+package pl.dmcs.eldarmuk.backend_springboot.security.jwt;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Component
+public class JwtAuthEntryPoint implements AuthenticationEntryPoint {
+
+    @Override
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
+                         AuthenticationException e) throws IOException, ServletException {
+        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error -> Unauthorized");
+    }
+}
+

+ 54 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/jwt/JwtAuthTokenFilter.java

@@ -0,0 +1,54 @@
+package pl.dmcs.eldarmuk.backend_springboot.security.jwt;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.web.filter.OncePerRequestFilter;
+import pl.dmcs.eldarmuk.backend_springboot.security.services.UserDetailsServiceImpl;
+
+import java.io.IOException;
+
+public class JwtAuthTokenFilter extends OncePerRequestFilter {
+
+    @Autowired
+    private JwtProvider tokenProvider;
+
+    @Autowired
+    private UserDetailsServiceImpl userDetailsService;
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
+                                    FilterChain filterChain) throws ServletException, IOException {
+        try {
+            String jwt = getJwt(httpServletRequest);
+            if (jwt != null && tokenProvider.validateJwtToken(jwt)) {
+                String username = tokenProvider.getUserNameFromJwtToken(jwt);
+
+                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
+                        userDetails, null, userDetails.getAuthorities());
+                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+
+                SecurityContextHolder.getContext().setAuthentication(authentication);
+            }
+        } catch (Exception e) {
+            logger.error("Can NOT set user authentication -> Message: {}", e);
+        }
+        filterChain.doFilter(httpServletRequest, httpServletResponse);
+    }
+
+    private String getJwt(HttpServletRequest request) {
+        String authHeader = request.getHeader("Authorization");
+        if (authHeader != null && authHeader.startsWith("Bearer ")) {
+            return authHeader.replace("Bearer ", "");
+        }
+        return null;
+    }
+}
+

+ 65 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/jwt/JwtProvider.java

@@ -0,0 +1,65 @@
+package pl.dmcs.eldarmuk.backend_springboot.security.jwt;
+
+import io.jsonwebtoken.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+import pl.dmcs.eldarmuk.backend_springboot.security.services.UserPrinciple;
+
+import java.util.Date;
+
+@Component
+public class JwtProvider {
+
+    @Value("${pl.dmcs.eldarmuk.jwtSecret}")
+    private String jwtSecret;
+
+    @Value("${pl.dmcs.eldarmuk.jwtExpiration}")
+    private int jwtExpiration;
+
+    public String generateJwtToken(Authentication authentication) {
+        UserPrinciple userPrinciple = (UserPrinciple) authentication.getPrincipal();
+
+        return Jwts.builder()
+                .setSubject(userPrinciple.getUsername())
+                .setIssuedAt(new Date())
+                .setExpiration(new Date((new Date()).getTime() + jwtExpiration*1000))
+                .signWith(SignatureAlgorithm.HS512, jwtSecret)
+                .compact();
+    }
+
+    public boolean validateJwtToken(String authToken) {
+        try {
+            Jwts.parser().setSigningKey(jwtSecret).build().parseSignedClaims(authToken);
+            return true;
+        } catch (SignatureException e) {
+            System.out.println("Invalid JWT signature -> Message: {} " + e);
+        } catch (MalformedJwtException e) {
+            System.out.println("Invalid JWT token -> Message: {}" + e);
+        } catch (ExpiredJwtException e) {
+            System.out.println("Expired JWT token -> Message: {}" + e);
+        } catch (UnsupportedJwtException e) {
+            System.out.println("Unsupported JWT token -> Message: {}" + e);
+        } catch (IllegalArgumentException e) {
+            System.out.println("JWT claims string is empty -> Message: {}" + e);
+        }
+
+        return false;
+    }
+
+    public String getUserNameFromJwtToken(String token) {
+        return Jwts.parser()
+                .setSigningKey(jwtSecret)
+                .build()
+                .parseClaimsJws(token)
+                .getBody().getSubject();
+    }
+
+}
+
+
+
+
+
+
+

+ 26 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/services/UserDetailsServiceImpl.java

@@ -0,0 +1,26 @@
+package pl.dmcs.eldarmuk.backend_springboot.security.services;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import pl.dmcs.eldarmuk.backend_springboot.model.Account;
+import pl.dmcs.eldarmuk.backend_springboot.repository.AccountRepository;
+
+@Service
+public class UserDetailsServiceImpl  implements UserDetailsService {
+    @Autowired
+    AccountRepository accountRepository;
+
+    @Override
+    @Transactional
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+
+        Account user = accountRepository.findByUsername(username).orElseThrow(
+                () -> new UsernameNotFoundException("User Not Found with -> username: " + username));
+        return UserPrinciple.build(user);
+    }
+}
+

+ 92 - 0
project/backend_springboot/src/main/java/pl/dmcs/eldarmuk/backend_springboot/security/services/UserPrinciple.java

@@ -0,0 +1,92 @@
+package pl.dmcs.eldarmuk.backend_springboot.security.services;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import pl.dmcs.eldarmuk.backend_springboot.model.Account;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class UserPrinciple implements UserDetails {
+
+    private Long id;
+
+    private String username;
+
+    @JsonIgnore
+    private String password;
+
+    private Collection<? extends GrantedAuthority> authorities;
+
+    public UserPrinciple(Long id, String username, String password, Collection<? extends GrantedAuthority> authorities) {
+        this.id = id;
+        this.username = username;
+        this.password = password;
+        this.authorities = authorities;
+    }
+
+    public static UserPrinciple build(Account user) {
+        List<GrantedAuthority> authorities = user.getRoles().stream()
+            .map(role -> new SimpleGrantedAuthority(role.getName().name()))
+            .collect(Collectors.toList());
+
+        return new UserPrinciple(
+            user.getId(),
+            user.getUsername(),
+            user.getPassword(),
+            authorities
+        );
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    @Override
+    public String getUsername() {
+        return username;
+    }
+
+    @Override
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return authorities;
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+
+        UserPrinciple user = (UserPrinciple) obj;
+        return Objects.equals(id, user.id);
+    }
+}

+ 5 - 5
project/backend_springboot/src/main/resources/application.properties

@@ -28,14 +28,14 @@ spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
 
 # Fix Postgres JPA Error (Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented).
-#spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
+spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
 
 #To change logging levels in the app
-# logging.level.org.springframework.web = trace
-# logging.level.org.hibernate = trace
+ logging.level.org.springframework.web = trace
+ logging.level.org.hibernate = trace
 
 # IMPORTANT: to use data.sql file has to be uncommented
 #spring.sql.init.mode = always
 
-#pl.dmcs.eldarmuk.jwtSecret = jwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKey
-#pl.dmcs.eldarmuk.jwtExpiration = 3600
+pl.dmcs.eldarmuk.jwtSecret = jwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKeyjwtSecretKey
+pl.dmcs.eldarmuk.jwtExpiration = 3600