浏览代码

Add user interface

Marcin Jaborski 3 年之前
父节点
当前提交
c19af8a1d7
共有 44 个文件被更改,包括 311 次插入224 次删除
  1. 15 7
      project-back/src/main/java/com/example/projectback/controllers/AuthController.java
  2. 0 26
      project-back/src/main/java/com/example/projectback/controllers/ExampleSecurityRESTController.java
  3. 27 20
      project-back/src/main/java/com/example/projectback/controllers/StudentController.java
  4. 68 16
      project-back/src/main/java/com/example/projectback/controllers/SubjectController.java
  5. 11 1
      project-back/src/main/java/com/example/projectback/message/response/JwtResponse.java
  6. 5 8
      project-back/src/main/java/com/example/projectback/model/Grade.java
  7. 0 1
      project-back/src/main/java/com/example/projectback/model/Student.java
  8. 0 1
      project-back/src/main/java/com/example/projectback/model/SubjectStudent.java
  9. 0 1
      project-back/src/main/java/com/example/projectback/model/SubjectStudentId.java
  10. 3 0
      project-back/src/main/java/com/example/projectback/repository/GradeRepository.java
  11. 2 1
      project-back/src/main/java/com/example/projectback/repository/StudentRepository.java
  12. 1 0
      project-back/src/main/java/com/example/projectback/repository/SubjectRepository.java
  13. 4 0
      project-back/src/main/java/com/example/projectback/repository/SubjectStudentRepository.java
  14. 1 0
      project-back/src/main/java/com/example/projectback/repository/UserRepository.java
  15. 1 2
      project-back/src/main/java/com/example/projectback/security/WebSecurityConfig.java
  16. 1 2
      project-back/src/main/java/com/example/projectback/security/jwt/JwtAuthEntryPoint.java
  17. 1 1
      project-back/src/main/java/com/example/projectback/security/jwt/JwtProvider.java
  18. 5 1
      project-back/src/main/java/com/example/projectback/security/services/UserDetailsServiceImpl.java
  19. 4 4
      project-back/src/main/java/com/example/projectback/security/services/UserPrinciple.java
  20. 0 13
      project-back/src/test/java/com/example/projectback/ProjectBackApplicationTests.java
  21. 0 57
      project-back/src/test/java/com/example/projectback/controllers/StudentControllerTest.java
  22. 3 2
      project-front/src/app/app.component.html
  23. 14 3
      project-front/src/app/app.component.ts
  24. 7 6
      project-front/src/app/app.module.ts
  25. 1 0
      project-front/src/app/auth/jwt-response.ts
  26. 10 0
      project-front/src/app/auth/token-storage.service.ts
  27. 3 0
      project-front/src/app/home/home.component.css
  28. 15 13
      project-front/src/app/home/home.component.html
  29. 2 3
      project-front/src/app/home/home.component.ts
  30. 1 0
      project-front/src/app/login/login.component.ts
  31. 2 2
      project-front/src/app/register/register.component.ts
  32. 1 1
      project-front/src/app/students/add-student-dialog.component.html
  33. 3 5
      project-front/src/app/students/grade.model.ts
  34. 1 5
      project-front/src/app/students/students.component.html
  35. 1 1
      project-front/src/app/students/students.component.ts
  36. 4 2
      project-front/src/app/subject/subject-details/add-student-to-subject-dialog.component.html
  37. 4 0
      project-front/src/app/subject/subject-details/subject-details.component.css
  38. 6 3
      project-front/src/app/subject/subject-details/subject-details.component.html
  39. 11 10
      project-front/src/app/subject/subject-details/subject-details.component.ts
  40. 0 0
      project-front/src/app/subject/subject-for-student/subject-for-student.component.css
  41. 13 0
      project-front/src/app/subject/subject-for-student/subject-for-student.component.html
  42. 25 0
      project-front/src/app/subject/subject-for-student/subject-for-student.component.spec.ts
  43. 20 0
      project-front/src/app/subject/subject-for-student/subject-for-student.component.ts
  44. 15 6
      project-front/src/app/subject/subject.service.ts

+ 15 - 7
project-back/src/main/java/com/example/projectback/controllers/AuthController.java

@@ -8,6 +8,7 @@ import com.example.projectback.model.Role;
 import com.example.projectback.model.RoleName;
 import com.example.projectback.model.User;
 import com.example.projectback.repository.RoleRepository;
+import com.example.projectback.repository.StudentRepository;
 import com.example.projectback.repository.UserRepository;
 import com.example.projectback.security.jwt.JwtProvider;
 import org.springframework.http.HttpStatus;
@@ -29,18 +30,20 @@ import java.util.Set;
 @RequestMapping("/auth")
 public class AuthController {
 
-    AuthenticationManager authenticationManager;
-    UserRepository userRepository;
-    RoleRepository roleRepository;
-    PasswordEncoder passwordEncoder;
-    JwtProvider jwtProvider;
+    final AuthenticationManager authenticationManager;
+    final UserRepository userRepository;
+    final RoleRepository roleRepository;
+    final PasswordEncoder passwordEncoder;
+    final JwtProvider jwtProvider;
+    final StudentRepository studentRepository;
 
-    public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, RoleRepository roleRepository, PasswordEncoder passwordEncoder, JwtProvider jwtProvider) {
+    public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, RoleRepository roleRepository, PasswordEncoder passwordEncoder, JwtProvider jwtProvider, StudentRepository studentRepository) {
         this.authenticationManager = authenticationManager;
         this.userRepository = userRepository;
         this.roleRepository = roleRepository;
         this.passwordEncoder = passwordEncoder;
         this.jwtProvider = jwtProvider;
+        this.studentRepository = studentRepository;
     }
 
     @PostMapping("/login")
@@ -52,7 +55,9 @@ public class AuthController {
         String jwt = jwtProvider.generateJwtToken(authentication);
         UserDetails userDetails = (UserDetails) authentication.getPrincipal();
 
-        return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername(), userDetails.getAuthorities()));
+        User user = userRepository.getByEmail(userDetails.getUsername());
+
+        return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername(), userDetails.getAuthorities(), user.getId()));
     }
 
     @PostMapping("/signup")
@@ -60,6 +65,9 @@ public class AuthController {
         if (userRepository.existsByEmail(signUpRequest.getEmail())) {
             return new ResponseEntity<>(new ResponseMessage("Fail -> Email is already taken"), HttpStatus.BAD_REQUEST);
         }
+        if(!studentRepository.existsByEmail(signUpRequest.getEmail())) {
+            return new ResponseEntity<>(new ResponseMessage("Student with email " + signUpRequest.getEmail() + " does not exist"), HttpStatus.BAD_REQUEST);
+        }
 
         User user = new User(signUpRequest.getEmail(), passwordEncoder.encode(signUpRequest.getPassword()));
 

+ 0 - 26
project-back/src/main/java/com/example/projectback/controllers/ExampleSecurityRESTController.java

@@ -1,26 +0,0 @@
-package com.example.projectback.controllers;
-
-import org.springframework.security.access.prepost.PreAuthorize;
-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;
-
-@RestController
-@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
-@RequestMapping("/exampleSecurity")
-public class ExampleSecurityRESTController {
-
-    @GetMapping("/user")
-    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
-    public String userAccess() {
-        return ">>> User Contents!";
-    }
-
-    @GetMapping("/admin")
-    @PreAuthorize("hasRole('ADMIN')")
-    public String adminAccess() {
-        return ">>> Admin Contents";
-    }
-
-}

+ 27 - 20
project-back/src/main/java/com/example/projectback/controllers/StudentController.java

@@ -1,17 +1,15 @@
 package com.example.projectback.controllers;
 
 import com.example.projectback.model.*;
-import com.example.projectback.repository.GradeRepository;
-import com.example.projectback.repository.StudentRepository;
-import com.example.projectback.repository.SubjectRepository;
-import com.example.projectback.repository.SubjectStudentRepository;
+import com.example.projectback.repository.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Optional;
 
 @RestController
 @CrossOrigin(origins = "http://localhost:4200")
@@ -21,53 +19,61 @@ public class StudentController {
     private final SubjectRepository subjectRepository;
     private final GradeRepository gradeRepository;
     private final SubjectStudentRepository subjectStudentRepository;
+    private final UserRepository userRepository;
 
     @Autowired
-    public StudentController(StudentRepository studentRepository, SubjectRepository subjectRepository, GradeRepository gradeRepository, SubjectStudentRepository subjectStudentRepository) {
+    public StudentController(StudentRepository studentRepository,
+                             SubjectRepository subjectRepository,
+                             GradeRepository gradeRepository,
+                             SubjectStudentRepository subjectStudentRepository,
+                             UserRepository userRepository) {
         this.studentRepository = studentRepository;
         this.subjectRepository = subjectRepository;
         this.gradeRepository = gradeRepository;
         this.subjectStudentRepository = subjectStudentRepository;
+        this.userRepository = userRepository;
     }
 
     @GetMapping
+    @PreAuthorize("hasRole('ADMIN')")
     public List<Student> getAllStudents() {
         return studentRepository.findAll();
     }
 
     @PostMapping
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Student> addStudent(@RequestBody Student student) {
         studentRepository.save(student);
         return new ResponseEntity<>(student, HttpStatus.CREATED);
     }
 
     @PostMapping("/delete")
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Changeset> deleteStudents(@RequestBody Changeset changeset) {
         for (Long recId : changeset.getRecords()) {
-            studentRepository.deleteById(recId);
+            Optional<Student> student = studentRepository.findById(recId);
+            if (student.isEmpty()) continue;
+            Optional<User> user = userRepository.findByEmail(student.get().getEmail());
+            user.ifPresent(userRepository::delete);
+            List<SubjectStudent> subjectStudents = subjectStudentRepository.getAllByStudent(student.get());
+            subjectStudentRepository.deleteAll(subjectStudents);
+            studentRepository.delete(student.get());
         }
         return new ResponseEntity<>(changeset, HttpStatus.OK);
     }
 
     @PostMapping("/{id}/grades")
-    public ResponseEntity<Grade> addGrade(@PathVariable("id") Long id, @RequestBody LinkedHashMap<String, Object> grade) {
+    @PreAuthorize("hasRole('ADMIN')")
+    public ResponseEntity<Grade> addGrade(@PathVariable("id") Long id, @RequestBody Grade grade) {
         Student student = this.studentRepository.getById(id);
-        Grade newGrade = new Grade();
-        Integer markRequest = (Integer) grade.get("mark");
-        newGrade.setMark(markRequest.longValue());
-        newGrade.setDescription((String) grade.get("description"));
-        LinkedHashMap<String, Object> subjectRequest = (LinkedHashMap<String, Object>) grade.get("subject");
-        Integer subjectIDRequest = (Integer) subjectRequest.get("id");
-        Subject subject = this.subjectRepository.getById(Long.valueOf(subjectIDRequest));
-        newGrade.setSubject(subject);
-
-        student.getGrades().add(newGrade);
-        this.gradeRepository.save(newGrade);
+        student.getGrades().add(grade);
+        this.gradeRepository.save(grade);
         this.studentRepository.save(student);
-        return new ResponseEntity<>(newGrade, HttpStatus.OK);
+        return new ResponseEntity<>(grade, HttpStatus.OK);
     }
 
     @DeleteMapping("/{studentID}/grades/{gradeID}")
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Student> deleteGrade(@PathVariable("studentID") Long studentID, @PathVariable("gradeID") Long gradeID) {
         Student student = this.studentRepository.getById(studentID);
         Grade grade = this.gradeRepository.getById(gradeID);
@@ -78,6 +84,7 @@ public class StudentController {
     }
 
     @PatchMapping("/{studentID}/payment/{subjectID}")
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Student> confirmPayment(@PathVariable("studentID") Long studentID, @PathVariable("subjectID") Long subjectID, @RequestBody SubjectStudent subjectStudentReq) {
         Student student = this.studentRepository.getById(studentID);
         Subject subject = this.subjectRepository.getById(subjectID);

+ 68 - 16
project-back/src/main/java/com/example/projectback/controllers/SubjectController.java

@@ -1,15 +1,11 @@
 package com.example.projectback.controllers;
 
-import com.example.projectback.model.Changeset;
-import com.example.projectback.model.Student;
-import com.example.projectback.model.Subject;
-import com.example.projectback.model.SubjectStudent;
-import com.example.projectback.repository.StudentRepository;
-import com.example.projectback.repository.SubjectRepository;
-import com.example.projectback.repository.SubjectStudentRepository;
+import com.example.projectback.model.*;
+import com.example.projectback.repository.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.ArrayList;
@@ -24,18 +20,45 @@ public class SubjectController {
     private final SubjectRepository subjectRepository;
     private final SubjectStudentRepository subjectStudentRepository;
     private final StudentRepository studentRepository;
+    private final GradeRepository gradeRepository;
+    private final UserRepository userRepository;
 
     @Autowired
-    public SubjectController(SubjectRepository subjectRepository, SubjectStudentRepository subjectStudentRepository, StudentRepository studentRepository) {
+    public SubjectController(SubjectRepository subjectRepository, SubjectStudentRepository subjectStudentRepository,
+                             StudentRepository studentRepository, GradeRepository gradeRepository,
+                             UserRepository userRepository) {
         this.subjectRepository = subjectRepository;
         this.subjectStudentRepository = subjectStudentRepository;
         this.studentRepository = studentRepository;
+        this.gradeRepository = gradeRepository;
+        this.userRepository = userRepository;
     }
 
     @GetMapping
-    public List<Subject> getAllSubjects() {return subjectRepository.findAll();}
+    @PreAuthorize("hasRole('ADMIN')")
+    public List<Subject> getAllSubjects() {
+        return subjectRepository.findAll();
+    }
+
+    @GetMapping("/student/{id}")
+    @PreAuthorize("hasRole('ADMIN') or hasRole('USER')")
+    public List<Subject> getAllSubjectsForStudent(@PathVariable("id") Long studentID) {
+        User user = userRepository.getById(studentID);
+        Student student = studentRepository.getByEmail(user.getEmail());
+        List<SubjectStudent> assoc = subjectStudentRepository.getAllByStudent(student);
+        List<Subject> studentSubjects = new ArrayList<>();
+        for (SubjectStudent subjectStudent: assoc) {
+            Subject subject = subjectStudent.getSubject();
+            List<SubjectStudent> newAssoc = new ArrayList<>();
+            newAssoc.add(new SubjectStudent(subject, student));
+            subject.setStudentsAssoc(newAssoc);
+            studentSubjects.add(subject);
+        }
+        return studentSubjects;
+    }
 
     @GetMapping("/{id}")
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Subject> getSubject(@PathVariable("id") Long id) {
         Optional<Subject> subject = subjectRepository.findById(id);
         if (subject.isEmpty()) {
@@ -45,27 +68,41 @@ public class SubjectController {
     }
 
     @PostMapping
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Subject> addSubject(@RequestBody Subject subject) {
         subjectRepository.save(subject);
         return new ResponseEntity<>(subject, HttpStatus.CREATED);
     }
 
     @PostMapping("/delete")
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Changeset> deleteSubjects(@RequestBody Changeset changeset) {
         for (Long recId : changeset.getRecords()) {
-            subjectRepository.deleteById(recId);
+            Optional<Subject> subject = subjectRepository.findById(recId);
+            if (subject.isEmpty()) continue;
+            List<SubjectStudent> subjectStudents = subjectStudentRepository.getAllBySubject(subject.get());
+            List<Grade> grades = gradeRepository.getAllBySubjectID(subject.get().getId());
+            List<Student> allStudents = studentRepository.findAll();
+            for(Student student: allStudents) {
+                student.getGrades().removeAll(grades);
+                studentRepository.save(student);
+            }
+            subjectStudentRepository.deleteAll(subjectStudents);
+            gradeRepository.deleteAll(grades);
+            subjectRepository.delete(subject.get());
         }
         return new ResponseEntity<>(changeset, HttpStatus.OK);
     }
 
     @PatchMapping("/{id}")
+    @PreAuthorize("hasRole('ADMIN')")
     public ResponseEntity<Subject> updatePartOfSubject(@RequestBody Map<String, Object> updates, @PathVariable("id") Long id) {
-        Subject subject = subjectRepository.getById(id);
-        if (subject == null) {
+        Optional<Subject> subject = subjectRepository.findById(id);
+        if (subject.isEmpty()) {
             return new ResponseEntity<>(HttpStatus.NOT_FOUND);
         }
-        partialUpdates(subject, updates);
-        return new ResponseEntity<>(HttpStatus.OK);
+        partialUpdates(subject.get(), updates);
+        return new ResponseEntity<>(subject.get(), HttpStatus.OK);
     }
 
     private void partialUpdates(Subject subject, Map<String, Object> updates) {
@@ -73,8 +110,8 @@ public class SubjectController {
             subject.setName((String) updates.get("nane"));
         }
         if (updates.containsKey("studentAssoc")) {
-            ArrayList<SubjectStudent> newStudents = new ArrayList<>();
-            for (Integer studentId : (ArrayList<Integer>)updates.get("studentAssoc")) {
+            List<SubjectStudent> newStudents = subject.getStudentsAssoc();
+            for (Integer studentId : (List<Integer>) updates.get("studentAssoc")) {
                 Student student = this.studentRepository.getById(studentId.longValue());
                 SubjectStudent newAssoc = new SubjectStudent(subject, student);
                 this.subjectStudentRepository.save(newAssoc);
@@ -84,4 +121,19 @@ public class SubjectController {
         }
         subjectRepository.save(subject);
     }
+
+    @DeleteMapping("/{subjectID}/{studentID}")
+    @PreAuthorize("hasRole('ADMIN')")
+    public ResponseEntity<Subject> removeStudentFromSubject(@PathVariable("subjectID") Long subjectID, @PathVariable Long studentID) {
+        Optional<Subject> subject = subjectRepository.findById(subjectID);
+        Optional<Student> student = studentRepository.findById(studentID);
+        if (subject.isEmpty() || student.isEmpty()) {
+            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+        }
+        SubjectStudent assoc = this.subjectStudentRepository.getByStudentAndSubject(student.get(), subject.get());
+        subject.get().getStudentsAssoc().remove(assoc);
+        this.subjectStudentRepository.delete(assoc);
+        this.subjectRepository.save(subject.get());
+        return new ResponseEntity<>(subject.get(), HttpStatus.OK);
+    }
 }

+ 11 - 1
project-back/src/main/java/com/example/projectback/message/response/JwtResponse.java

@@ -8,12 +8,14 @@ public class JwtResponse {
     private String token;
     private String type = "Bearer";
     private String username;
+    private Long userID;
     private final Collection<? extends GrantedAuthority> authorities;
 
-    public JwtResponse(String token, String username, Collection<? extends GrantedAuthority> authorities) {
+    public JwtResponse(String token, String username, Collection<? extends GrantedAuthority> authorities, Long userID) {
         this.token = token;
         this.username = username;
         this.authorities = authorities;
+        this.userID = userID;
     }
 
     public String getToken() {
@@ -43,4 +45,12 @@ public class JwtResponse {
     public Collection<? extends GrantedAuthority> getAuthorities() {
         return authorities;
     }
+
+    public Long getUserID() {
+        return userID;
+    }
+
+    public void setUserID(Long userID) {
+        this.userID = userID;
+    }
 }

+ 5 - 8
project-back/src/main/java/com/example/projectback/model/Grade.java

@@ -1,6 +1,5 @@
 package com.example.projectback.model;
 
-import com.fasterxml.jackson.annotation.JsonBackReference;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
 import javax.persistence.*;
@@ -15,9 +14,7 @@ public class Grade {
     private Long mark;
     private String description;
 
-    @OneToOne
-    @JsonBackReference
-    private Subject subject;
+    private Long subjectID;
 
     public Grade() {
     }
@@ -46,11 +43,11 @@ public class Grade {
         this.description = description;
     }
 
-    public Subject getSubject() {
-        return subject;
+    public Long getSubjectID() {
+        return subjectID;
     }
 
-    public void setSubject(Subject subject) {
-        this.subject = subject;
+    public void setSubjectID(Long subject) {
+        this.subjectID = subject;
     }
 }

+ 0 - 1
project-back/src/main/java/com/example/projectback/model/Student.java

@@ -1,6 +1,5 @@
 package com.example.projectback.model;
 
-import com.fasterxml.jackson.annotation.JsonBackReference;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
 import javax.persistence.*;

+ 0 - 1
project-back/src/main/java/com/example/projectback/model/SubjectStudent.java

@@ -1,6 +1,5 @@
 package com.example.projectback.model;
 
-import com.fasterxml.jackson.annotation.JsonBackReference;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
 import javax.persistence.*;

+ 0 - 1
project-back/src/main/java/com/example/projectback/model/SubjectStudentId.java

@@ -1,6 +1,5 @@
 package com.example.projectback.model;
 
-import javax.persistence.Embeddable;
 import java.io.Serializable;
 import java.util.Objects;
 

+ 3 - 0
project-back/src/main/java/com/example/projectback/repository/GradeRepository.java

@@ -3,5 +3,8 @@ package com.example.projectback.repository;
 import com.example.projectback.model.Grade;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.List;
+
 public interface GradeRepository extends JpaRepository<Grade, Long> {
+    List<Grade> getAllBySubjectID(Long subjectID);
 }

+ 2 - 1
project-back/src/main/java/com/example/projectback/repository/StudentRepository.java

@@ -4,5 +4,6 @@ import com.example.projectback.model.Student;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 public interface StudentRepository extends JpaRepository<Student, Long> {
-    Student findById(long id);
+    Student getByEmail(String email);
+    Boolean existsByEmail(String email);
 }

+ 1 - 0
project-back/src/main/java/com/example/projectback/repository/SubjectRepository.java

@@ -4,4 +4,5 @@ import com.example.projectback.model.Subject;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 public interface SubjectRepository extends JpaRepository<Subject, Long> {
+    Subject findById(long id);
 }

+ 4 - 0
project-back/src/main/java/com/example/projectback/repository/SubjectStudentRepository.java

@@ -5,6 +5,10 @@ import com.example.projectback.model.Subject;
 import com.example.projectback.model.SubjectStudent;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.List;
+
 public interface SubjectStudentRepository extends JpaRepository<SubjectStudent, Long> {
     SubjectStudent getByStudentAndSubject(Student student, Subject subject);
+    List<SubjectStudent> getAllByStudent(Student student);
+    List<SubjectStudent> getAllBySubject(Subject subject);
 }

+ 1 - 0
project-back/src/main/java/com/example/projectback/repository/UserRepository.java

@@ -7,5 +7,6 @@ import java.util.Optional;
 
 public interface UserRepository extends JpaRepository<User, Long> {
     Optional<User> findByEmail(String email);
+    User getByEmail(String email);
     Boolean existsByEmail(String email);
 }

+ 1 - 2
project-back/src/main/java/com/example/projectback/security/WebSecurityConfig.java

@@ -1,6 +1,5 @@
 package com.example.projectback.security;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -22,7 +21,7 @@ import com.example.projectback.security.services.UserDetailsServiceImpl;
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
-    UserDetailsServiceImpl userDetailsService;
+    final UserDetailsServiceImpl userDetailsService;
 
     private final JwtAuthEntryPoint unauthorizedHandler;
 

+ 1 - 2
project-back/src/main/java/com/example/projectback/security/jwt/JwtAuthEntryPoint.java

@@ -4,7 +4,6 @@ import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.stereotype.Component;
 
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -13,7 +12,7 @@ import java.io.IOException;
 public class JwtAuthEntryPoint implements AuthenticationEntryPoint {
 
     @Override
-    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
         httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error -> Unauthorized");
     }
 }

+ 1 - 1
project-back/src/main/java/com/example/projectback/security/jwt/JwtProvider.java

@@ -23,7 +23,7 @@ public class JwtProvider {
         return Jwts.builder()
                 .setSubject(userPrinciple.getUsername())
                 .setIssuedAt(new Date())
-                .setExpiration(new Date((new Date()).getTime() + jwtExpiration*1000))
+                .setExpiration(new Date((new Date()).getTime() + jwtExpiration* 1000L))
                 .signWith(SignatureAlgorithm.HS512, jwtSecret)
                 .compact();
     }

+ 5 - 1
project-back/src/main/java/com/example/projectback/security/services/UserDetailsServiceImpl.java

@@ -12,9 +12,13 @@ import com.example.projectback.repository.UserRepository;
 @Service
 public class UserDetailsServiceImpl  implements UserDetailsService {
 
-    @Autowired
+    final
     UserRepository userRepository;
 
+    public UserDetailsServiceImpl(UserRepository userRepository) {
+        this.userRepository = userRepository;
+    }
+
     @Override
     @Transactional
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

+ 4 - 4
project-back/src/main/java/com/example/projectback/security/services/UserPrinciple.java

@@ -13,14 +13,14 @@ import java.util.stream.Collectors;
 
 public class UserPrinciple implements UserDetails {
 
-    private Long id;
+    private final Long id;
 
-    private String username;
+    private final String username;
 
     @JsonIgnore
-    private String password;
+    private final String password;
 
-    private Collection<? extends GrantedAuthority> authorities;
+    private final Collection<? extends GrantedAuthority> authorities;
 
     public UserPrinciple(Long id, String username, String password, Collection<? extends GrantedAuthority> authorities) {
         this.id = id;

+ 0 - 13
project-back/src/test/java/com/example/projectback/ProjectBackApplicationTests.java

@@ -1,13 +0,0 @@
-package com.example.projectback;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class ProjectBackApplicationTests {
-
-	@Test
-	void contextLoads() {
-	}
-
-}

+ 0 - 57
project-back/src/test/java/com/example/projectback/controllers/StudentControllerTest.java

@@ -1,57 +0,0 @@
-package com.example.projectback.controllers;
-
-import com.example.projectback.model.Student;
-import com.example.projectback.repository.StudentRepository;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.http.MediaType;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.MvcResult;
-import org.springframework.test.web.servlet.RequestBuilder;
-import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
-import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
-import org.springframework.web.context.WebApplicationContext;
-
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.when;
-
-@ExtendWith(SpringExtension.class)
-@WebMvcTest(StudentController.class)
-class StudentControllerTest {
-
-    @MockBean
-    private StudentRepository studentRepository;
-
-    @Autowired
-    private WebApplicationContext webApplicationContext;
-
-    @Autowired
-    private MockMvc mvc;
-
-    @Test
-    void addStudent() throws Exception {
-        mvc.perform(MockMvcRequestBuilders.post("/students").contentType(MediaType.APPLICATION_JSON)
-                .content("{\"firstname\": \"John\", \"lastname\": \"Smith\", \"email\": \"john.smith@example.com\", \"telephone\": \"600345624\"}")).andExpect(MockMvcResultMatchers.status().isCreated());
-    }
-
-    @Test
-    void getAllStudents() throws Exception {
-        Student testStudent = new Student();
-        testStudent.setFirstname("John");
-        testStudent.setLastname("Smith");
-        testStudent.setEmail("john.smith@example.com");
-        testStudent.setTelephone("600345624");
-
-        when(studentRepository.findAll()).thenReturn(List.of(testStudent));
-
-        RequestBuilder request = MockMvcRequestBuilders.get("/students");
-        mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.jsonPath("$[0].firstname").value("John"));
-    }
-
-}

+ 3 - 2
project-front/src/app/app.component.html

@@ -2,8 +2,9 @@
   <div>Grade-book</div>
   <div class="right">
     <a mat-raised-button [routerLink]="['/home']">Home</a>
-    <a mat-raised-button [routerLink]="['/students']">Students</a>
-    <a mat-raised-button [routerLink]="['/subjects']">Subjects</a>
+    <a *ngIf="authority === 'admin'" mat-raised-button [routerLink]="['/students']">Students</a>
+    <a *ngIf="authority === 'admin'" mat-raised-button [routerLink]="['/subjects']">Subjects</a>
+    <a *ngIf="authority === 'user'" mat-raised-button [routerLink]="['/student/subjects']">Subjects</a>
     <a *ngIf="!authority" mat-raised-button [routerLink]="['/auth/login']">Login</a>
     <a *ngIf="!authority" mat-raised-button [routerLink]="['/auth/signup']">Register</a>
     <button *ngIf="authority" mat-raised-button (click)="logout()">Logout</button>

+ 14 - 3
project-front/src/app/app.component.ts

@@ -1,5 +1,6 @@
 import { Component } from '@angular/core';
 import { TokenStorageService } from "./auth/token-storage.service";
+import { NavigationEnd, Router } from "@angular/router";
 
 @Component({
   selector: 'app-root',
@@ -7,14 +8,20 @@ import { TokenStorageService } from "./auth/token-storage.service";
   styleUrls: ['./app.component.css']
 })
 export class AppComponent {
-  title = 'angular13-iwa2022-http-students';
+  title = 'Grade-book';
   private roles?: string[];
   authority?: string;
 
-  constructor(private tokenStorage: TokenStorageService, private token: TokenStorageService) {
+  constructor(private tokenStorage: TokenStorageService, private token: TokenStorageService, private router: Router) {
+    this.setAuthorities();
+    this.router.events.subscribe((event) => {
+      if (event instanceof NavigationEnd) {
+        this.setAuthorities();
+      }
+    })
   }
 
-  ngOnInit() {
+  setAuthorities(): void {
     if (this.tokenStorage.getToken()) {
       this.roles = this.tokenStorage.getAuthorities();
       this.roles.every(role => {
@@ -33,4 +40,8 @@ export class AppComponent {
     window.location.reload();
   }
 
+  public getAuthority() {
+    return this.authority;
+  }
+
 }

+ 7 - 6
project-front/src/app/app.module.ts

@@ -16,14 +16,14 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { MaterialModule } from "./material/material.module";
 import { AddSubjectDialog, SubjectListComponent } from './subject/subject-list/subject-list.component';
 import { StudentSelectionDialog, SubjectDetailsComponent } from './subject/subject-details/subject-details.component';
+import { SubjectForStudentComponent } from './subject/subject-for-student/subject-for-student.component';
 
 const routes: Routes = [
   { path: 'home', component: HomeComponent },
-  { path: 'students', component: StudentsComponent },
-  { path: 'subjects', component: SubjectListComponent },
-  { path: 'subjects/:id', component: SubjectDetailsComponent },
-  { path: 'user', component: UserComponent, canActivate: [RoleGuard], data: { roles: ['ROLE_USER', 'ROLE_ADMIN'] }, },
-  { path: 'admin', component: AdminComponent, canActivate: [RoleGuard], data: { roles: ['ROLE_ADMIN'] }, },
+  { path: 'students', component: StudentsComponent, canActivate: [RoleGuard], data: { roles: ['ROLE_ADMIN'] }, },
+  { path: 'subjects', component: SubjectListComponent, canActivate: [RoleGuard], data: { roles: ['ROLE_ADMIN'] }, },
+  { path: 'subjects/:id', component: SubjectDetailsComponent, canActivate: [RoleGuard], data: { roles: ['ROLE_ADMIN'] }, },
+  { path: 'student/subjects', component: SubjectForStudentComponent, canActivate: [RoleGuard], data: { roles: ['ROLE_USER'] }, },
   { path: 'auth/login', component: LoginComponent },
   { path: 'auth/signup', component: RegisterComponent },
   { path: '', redirectTo: 'home', pathMatch: 'full' }
@@ -43,6 +43,7 @@ const routes: Routes = [
     SubjectDetailsComponent,
     AddStudentDialog,
     StudentSelectionDialog,
+    SubjectForStudentComponent,
   ],
   imports: [
     BrowserModule,
@@ -53,7 +54,7 @@ const routes: Routes = [
     MaterialModule,
     ReactiveFormsModule
   ],
-  providers: [httpInterceptorProviders],
+  providers: [httpInterceptorProviders, AppComponent],
   bootstrap: [AppComponent]
 })
 export class AppModule {

+ 1 - 0
project-front/src/app/auth/jwt-response.ts

@@ -3,4 +3,5 @@ export class JwtResponse {
   type?: string;
   username?: string;
   authorities?: string[];
+  userID?: string;
 }

+ 10 - 0
project-front/src/app/auth/token-storage.service.ts

@@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
 const TOKEN_KEY = 'AuthToken';
 const USERNAME_KEY = 'AuthUsername';
 const AUTHORITIES_KEY = 'AuthAuthorities';
+const USER_ID_KEY = 'AuthUserID';
 
 @Injectable({
   providedIn: 'root'
@@ -49,4 +50,13 @@ export class TokenStorageService {
 
     return this.roles;
   }
+
+  public saveUserID(userID: string): void {
+    window.sessionStorage.removeItem(USER_ID_KEY);
+    window.sessionStorage.setItem(USER_ID_KEY, JSON.stringify(userID));
+  }
+
+  public getUserID(): string {
+    return sessionStorage.getItem(USER_ID_KEY) || '{}';
+  }
 }

+ 3 - 0
project-front/src/app/home/home.component.css

@@ -0,0 +1,3 @@
+.wrapper {
+    padding: 30px;
+}

+ 15 - 13
project-front/src/app/home/home.component.html

@@ -1,15 +1,17 @@
-<p>home component works!</p>
-<div *ngIf="info.token != '{}'; else loggedOut">
-  <h5 class="text-primary">Your Information</h5>
-  <p>
+<div class="wrapper">
+  <h1 class="mat-display-2" xmlns="http://www.w3.org/1999/html">Grade book by Marcin Jaborski index no. 234680</h1>
+  <div *ngIf="info.token != '{}'; else loggedOut">
+    <h1 class="mat-display-1">Your Information</h1>
     <strong>Username:</strong> {{info.username}}<br/>
-    <strong>Roles:</strong> {{info.authorities}}<br />
-    <strong>Token:</strong> {{info.token}}.
-  </p>
-  <button class="btn btn-secondary" (click)="logout()">Logout</button>
-</div>
-
-<ng-template #loggedOut>
-  Please login.
-</ng-template>
+    <span *ngIf="isAdmin()">
+    <strong>Logged as Teacher</strong>
+  </span>
+    <span *ngIf="!isAdmin()">
+    <strong>Logged as Student</strong>
+  </span>
+  </div>
 
+  <ng-template #loggedOut>
+    <h1 class="mat-display-1">Please login in order to access students, grades and subjects.</h1>
+  </ng-template>
+</div>

+ 2 - 3
project-front/src/app/home/home.component.ts

@@ -20,9 +20,8 @@ export class HomeComponent implements OnInit {
     };
   }
 
-  logout() {
-    this.token.signOut();
-    window.location.reload();
+  isAdmin(): boolean {
+    return this.info.authorities.includes('ROLE_ADMIN');
   }
 
 }

+ 1 - 0
project-front/src/app/login/login.component.ts

@@ -56,6 +56,7 @@ export class LoginComponent implements OnInit {
         this.tokenStorage.saveToken(data.token || '{}');
         this.tokenStorage.saveUsername(data.username || '{}');
         this.tokenStorage.saveAuthorities(data.authorities || []);
+        this.tokenStorage.saveUserID(data.userID || '{}');
 
         this.isLoginFailed = false;
         this.isLoggedIn = true;

+ 2 - 2
project-front/src/app/register/register.component.ts

@@ -50,10 +50,10 @@ export class RegisterComponent implements OnInit {
     this.signupInfo = new SignupInfo(this.form.value.email, this.form.value.password);
 
     this.authService.signUp(this.signupInfo).subscribe(
-      data => {
+      () => {
         this.isSignedUp = true;
         this.isSignUpFailed = false;
-        this.router.navigate(['/auth/login']);
+        this.router.navigate(['/auth/login']).then();
       },
       error => {
         this._snackBar.open(error.error?.message || 'Oops! Error occurred', 'Dismiss');

+ 1 - 1
project-front/src/app/students/add-student-dialog.component.html

@@ -1,4 +1,4 @@
-<h1 mat-dialog-title>Add new subject</h1>
+<h1 mat-dialog-title>Add new student</h1>
 <div mat-dialog-content>
   <mat-form-field appearance="fill">
     <mat-label>Firstname</mat-label>

+ 3 - 5
project-front/src/app/students/grade.model.ts

@@ -1,14 +1,12 @@
-import { Subject } from "../subject/subject.model";
-
 export class Grade {
   id?: number;
   mark: number;
   description: string;
-  subject: Subject;
+  subjectID: number;
 
-  constructor(mark: number, description: string, subject: Subject) {
+  constructor(mark: number, description: string, subjectID: number) {
     this.mark = mark;
     this.description = description;
-    this.subject = subject;
+    this.subjectID = subjectID;
   }
 }

+ 1 - 5
project-front/src/app/students/students.component.html

@@ -1,6 +1,6 @@
 <h1 class="mat-display-1">Students</h1>
 <button mat-raised-button color="primary" (click)="openDialog()">Add</button>
-<button mat-raised-button color="primary" (click)="delete()">Remove</button>
+<button mat-raised-button color="primary" (click)="delete()">Delete</button>
 <br>
 <mat-form-field appearance="fill">
   <mat-label>Filter</mat-label>
@@ -47,10 +47,6 @@
 
   <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
   <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
-
-  <tr class="mat-row" *matNoDataRow>
-    <td class="mat-cell" colspan="5">No data matching the filter "{{filter.value}}"</td>
-  </tr>
 </table>
 
 <mat-paginator [pageSizeOptions]="[5, 10, 20]"

+ 1 - 1
project-front/src/app/students/students.component.ts

@@ -13,7 +13,7 @@ import { MatSort } from "@angular/material/sort";
   styleUrls: ['./students.component.css']
 })
 export class StudentsComponent implements OnInit, AfterViewInit {
-  displayedColumns: string[] = ['select', 'firstname', 'lastname', 'email', 'lastname'];
+  displayedColumns: string[] = ['select', 'firstname', 'lastname', 'email', 'telephone'];
   studentList = new MatTableDataSource<Student>([]);
   student?: Student;
   selection = new SelectionModel<Student>(true, []);

+ 4 - 2
project-front/src/app/subject/subject-details/add-student-to-subject-dialog.component.html

@@ -1,12 +1,14 @@
 <h1 mat-dialog-title>Select students</h1>
 <div mat-dialog-content>
   <mat-selection-list #selection>
-    <mat-list-option *ngFor="let student of allStudents" [value]="student.id">
+    <mat-list-option *ngFor="let student of possibleStudents" [value]="student.id">
       {{student.firstname}} {{student.lastname}}
     </mat-list-option>
   </mat-selection-list>
+  <span *ngIf="possibleStudents?.length === 0">You cannot add more students</span>
 </div>
 <div mat-dialog-actions>
   <button mat-button (click)="onNoClick()">Cancel</button>
-  <button mat-button [mat-dialog-close]="selection.selectedOptions.selected">Add</button>
+  <button *ngIf="possibleStudents !== undefined && possibleStudents.length > 0" mat-button [mat-dialog-close]="selection.selectedOptions.selected">Add
+  </button>
 </div>

+ 4 - 0
project-front/src/app/subject/subject-details/subject-details.component.css

@@ -8,4 +8,8 @@ mat-form-field {
 
 button, h1 {
     margin: 20px !important;
+}
+
+.mat-menu-content button {
+    margin: initial !important;
 }

+ 6 - 3
project-front/src/app/subject/subject-details/subject-details.component.html

@@ -8,7 +8,10 @@
         {{studentAssoc.student.firstname}} {{studentAssoc.student.lastname}}
       </mat-panel-title>
       <mat-panel-description>
-        <mat-checkbox #payment [checked]="studentAssoc.paymentConfirmed" (change)="confirmPayment(studentAssoc.student.id!, payment.checked)">Payment confirmed</mat-checkbox>
+        <mat-checkbox #payment [checked]="studentAssoc.paymentConfirmed"
+                      (change)="confirmPayment(studentAssoc.student.id!, payment.checked)"
+                      (click)="$event.stopPropagation()">Payment confirmed
+        </mat-checkbox>
       </mat-panel-description>
     </mat-expansion-panel-header>
     <mat-form-field appearance="fill">
@@ -28,12 +31,12 @@
     Grades:
     <span *ngFor=" let grade of studentAssoc.student.grades" [matTooltip]="grade.description"
           [matMenuTriggerFor]="menu">
-      {{grade.mark}},
+      <span *ngIf="grade.subjectID === subject!.id">{{grade.mark}},</span>
       <mat-menu #menu="matMenu">
         <button (click)="deleteGrade(studentAssoc.student.id!, grade.id!)" mat-menu-item>Delete</button>
       </mat-menu>
     </span>
     <br>
-    <button mat-raised-button color="primary" (click)="deleteStudent(studentAssoc.student.id!)">Delete student</button>
+    <button mat-raised-button color="primary" (click)="deleteStudent(studentAssoc.student)">Delete student</button>
   </mat-expansion-panel>
 </mat-accordion>

+ 11 - 10
project-front/src/app/subject/subject-details/subject-details.component.ts

@@ -36,20 +36,18 @@ export class SubjectDetailsComponent implements OnInit {
   addStudent(): void {
     const dialogRef = this.dialog.open(StudentSelectionDialog, {
       width: '250px',
-      data: {},
+      data: { studentsInSubject: this.subject?.studentsAssoc },
     });
     dialogRef.afterClosed().subscribe(result => {
       if (result) {
         const ids = result.map((student: MatListOption) => student.value);
-        this.subjectService.addStudentToSubject(this.subject!, ids).subscribe();
+        this.subjectService.addStudentsToSubject(this.subject!, ids).subscribe((subject: Subject) => this.subject = subject);
       }
     });
   }
 
-  deleteStudent(studentIdToDelete: number): void {
-    let ids = this.subject!.studentsAssoc!.map((studentAssoc: StudentAssoc) => studentAssoc.student.id!);
-    ids = ids.filter((id: number) => id !== studentIdToDelete);
-    this.subjectService.addStudentToSubject(this.subject!, ids).subscribe();
+  deleteStudent(student: Student): void {
+    this.subjectService.removeStudentFromSubject(this.subject!, student).subscribe((subject: Subject) => this.subject = subject);
   }
 
   addGrade(studentId: number, gradeEl: HTMLInputElement, descriptionEl: HTMLInputElement): void {
@@ -61,7 +59,7 @@ export class SubjectDetailsComponent implements OnInit {
     this.studentService.addGrade(studentId, {
       mark: grade,
       description: descriptionEl.value,
-      subject: this.subject!,
+      subjectID: this.subject!.id!,
     }).subscribe(() => this.getSubject());
   }
 
@@ -80,9 +78,9 @@ export class SubjectDetailsComponent implements OnInit {
   templateUrl: 'add-student-to-subject-dialog.component.html',
 })
 export class StudentSelectionDialog implements OnInit {
-  allStudents?: Student[];
+  possibleStudents?: Student[];
 
-  constructor(public dialogRef: MatDialogRef<StudentSelectionDialog>, @Inject(MAT_DIALOG_DATA) public subject: Subject,
+  constructor(public dialogRef: MatDialogRef<StudentSelectionDialog>, @Inject(MAT_DIALOG_DATA) public subject: any,
               private studentService: StudentService) {
   }
 
@@ -91,6 +89,9 @@ export class StudentSelectionDialog implements OnInit {
   }
 
   ngOnInit(): void {
-    this.studentService.getStudents().subscribe(studentList => this.allStudents = studentList);
+    this.studentService.getStudents().subscribe(studentList => {
+      const studentIdsToExclude = this.subject.studentsInSubject.map((assoc: StudentAssoc) => assoc.student.id);
+      this.possibleStudents = studentList.filter((student: Student) => !studentIdsToExclude.includes(student.id));
+    });
   }
 }

+ 0 - 0
project-front/src/app/subject/subject-for-student/subject-for-student.component.css


+ 13 - 0
project-front/src/app/subject/subject-for-student/subject-for-student.component.html

@@ -0,0 +1,13 @@
+<mat-accordion *ngIf="subjects">
+  <mat-expansion-panel hideToggle *ngFor="let subject of subjects">
+    <mat-expansion-panel-header>
+      <mat-panel-title>
+        {{subject.name}}
+      </mat-panel-title>
+    </mat-expansion-panel-header>
+    Grades:<br>
+    <span *ngFor="let grade of subject.studentsAssoc![0].student.grades" [matTooltip]="grade.description">
+      <span *ngIf="grade.subjectID === subject.id">{{grade.mark}},</span>
+    </span>
+  </mat-expansion-panel>
+</mat-accordion>

+ 25 - 0
project-front/src/app/subject/subject-for-student/subject-for-student.component.spec.ts

@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SubjectForStudentComponent } from './subject-for-student.component';
+
+describe('SubjectForStudentComponent', () => {
+  let component: SubjectForStudentComponent;
+  let fixture: ComponentFixture<SubjectForStudentComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ SubjectForStudentComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(SubjectForStudentComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 20 - 0
project-front/src/app/subject/subject-for-student/subject-for-student.component.ts

@@ -0,0 +1,20 @@
+import { Component, OnInit } from '@angular/core';
+import { Subject } from "../subject.model";
+import { SubjectService } from "../subject.service";
+
+@Component({
+  selector: 'app-subject-for-student',
+  templateUrl: './subject-for-student.component.html',
+  styleUrls: ['./subject-for-student.component.css']
+})
+export class SubjectForStudentComponent implements OnInit {
+  subjects?: Subject[];
+
+  constructor(private subjectService: SubjectService) {
+  }
+
+  ngOnInit(): void {
+    this.subjectService.getSubjects().subscribe((result) => this.subjects = result);
+  }
+
+}

+ 15 - 6
project-front/src/app/subject/subject.service.ts

@@ -3,6 +3,7 @@ import { HttpClient, HttpHeaders } from "@angular/common/http";
 import { catchError, Observable, of, tap } from "rxjs";
 import { Subject } from "./subject.model";
 import { Student } from "../students/student.model";
+import { TokenStorageService } from "../auth/token-storage.service";
 
 const httpOptions = {
   headers: new HttpHeaders({ 'Content-Type': 'application/json' })
@@ -17,11 +18,19 @@ export interface Changeset {
 })
 export class SubjectService {
 
-  private subjectsUrl = 'http://localhost:8080/subjects';
+  private readonly subjectsUrl = 'http://localhost:8080/subjects';
+  private readonly subjectsForStudentUrl;
 
-  constructor(private http: HttpClient) { }
+  constructor(private http: HttpClient, private token: TokenStorageService) {
+    if (!token.getAuthorities().includes('ROLE_ADMIN')) {
+      this.subjectsForStudentUrl = `http://localhost:8080/subjects/student/${token.getUserID()}`;
+    }
+  }
 
   getSubjects(): Observable<Subject[]> {
+    if (!this.token.getAuthorities().includes('ROLE_ADMIN')) {
+      return this.http.get<Subject[]>(this.subjectsForStudentUrl!);
+    }
     return this.http.get<Subject[]>(this.subjectsUrl);
   }
 
@@ -42,13 +51,13 @@ export class SubjectService {
     return this.http.post(`${this.subjectsUrl}/delete`, {records: ids}, httpOptions);
   }
 
-  addStudentToSubject(subject: Subject, ids: Number[]): Observable<any> {
+  addStudentsToSubject(subject: Subject, ids: Number[]): Observable<any> {
     return this.http.patch(`${this.subjectsUrl}/${subject.id}`, {studentAssoc: ids}, httpOptions);
   }
 
-  // removeStudentFromSubject(subject: Subject, student: Student): Observable<any> {
-  //
-  // }
+  removeStudentFromSubject(subject: Subject, student: Student): Observable<any> {
+    return this.http.delete(`${this.subjectsUrl}/${subject.id}/${student.id}`, httpOptions);
+  }
 
   private log(message: string): void {
     console.log('SubjectService: ' + message);