1
0
forked from PGL/Clyde

Merge branch 'master' into wal/front/listingUsers

This commit is contained in:
Wawilski 2024-03-16 19:57:53 +01:00
commit 5a7934b2a3
17 changed files with 316 additions and 102 deletions

View File

@ -2,6 +2,7 @@ package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
@ -9,10 +10,12 @@ import org.springframework.web.bind.annotation.RestController;
import ovh.herisson.Clyde.Services.AuthenticatorService; import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Tables.Applications; import ovh.herisson.Clyde.Tables.Applications;
import ovh.herisson.Clyde.Tables.Role; import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList; import java.util.ArrayList;
@RestController @RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class ApplicationsController { public class ApplicationsController {
AuthenticatorService authServ; AuthenticatorService authServ;
@ -41,12 +44,17 @@ public class ApplicationsController {
} }
public ArrayList<Applications> getAuthorizedApplications(String token){ public ArrayList<Applications> getAuthorizedApplications(String token){
Role posterRole = authServ.getUserFromToken(token).getRole();
ArrayList<Applications> authorizedApps = new ArrayList<>(); ArrayList<Applications> authorizedApps = new ArrayList<>();
authorizedApps.add(Applications.Login); authorizedApps.add(Applications.Login);
authorizedApps.add(Applications.Profile); authorizedApps.add(Applications.Profile);
User user = authServ.getUserFromToken(token);
if(user == null)
return authorizedApps;
Role posterRole = user.getRole();
if (posterRole == Role.Teacher || posterRole == Role.Student || posterRole == Role.Admin){ if (posterRole == Role.Teacher || posterRole == Role.Student || posterRole == Role.Admin){
authorizedApps.add(Applications.Msg); authorizedApps.add(Applications.Msg);
authorizedApps.add(Applications.Forum); authorizedApps.add(Applications.Forum);

View File

@ -0,0 +1,80 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.CourseService;
import ovh.herisson.Clyde.Services.TeacherCourseService;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.TeacherCourse;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
import java.util.Map;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class CourseController {
private final CourseService courseServ;
private final TeacherCourseService teacherCourseServ;
private final AuthenticatorService authServ;
public CourseController(CourseService courseServ, TeacherCourseService teacherCourseServ, AuthenticatorService authServ) {
this.courseServ = courseServ;
this.teacherCourseServ = teacherCourseServ;
this.authServ = authServ;
}
@GetMapping("/course/{id}")
public ResponseEntity<Course> getCourse(@RequestHeader("Authorization") String token, @PathVariable long id){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(courseServ.findById(id), HttpStatus.OK);
}
@PostMapping("/course")
public ResponseEntity<Course> postCourse(@RequestHeader("Authorization") String token, @RequestBody Course course){
if (authServ.isNotSecretaryOrAdmin(token))
return new UnauthorizedResponse<>(null);
return new ResponseEntity<>(courseServ.save(course), HttpStatus.CREATED);
}
@PatchMapping("/course/{id}")
public ResponseEntity<Course> patchCourse(@RequestHeader("Authorization") String token,
@RequestBody Map<String,Object> updates,
@PathVariable long id)
{
if (authServ.IsNotIn(new Role[]{Role.Admin,Role.Teacher,Role.Secretary}, token)){
return new UnauthorizedResponse<>(null);
}
return new ResponseEntity<>(courseServ.modifyData(id, updates, authServ.getUserFromToken(token).getRole()), HttpStatus.OK);
}
@PostMapping("/course/{id}")
public ResponseEntity<String> postTeachers(@RequestHeader("Authorization") String token,
@RequestBody Iterable<Long> teacherIds,
@PathVariable Long id)
{
if (authServ.IsNotIn(new Role[]{Role.Admin,Role.Secretary}, token))
return new UnauthorizedResponse<>(null);
teacherCourseServ.saveAll(teacherIds,courseServ.findById(id));
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -15,6 +15,7 @@ import ovh.herisson.Clyde.Tables.User;
import java.util.Map; import java.util.Map;
@RestController @RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class CurriculumController { public class CurriculumController {
@ -43,4 +44,17 @@ public class CurriculumController {
public ResponseEntity<Iterable<CurriculumCourse>> findAll(){ public ResponseEntity<Iterable<CurriculumCourse>> findAll(){
return new ResponseEntity<>(curriculumCourseServ.findAll(),HttpStatus.OK); return new ResponseEntity<>(curriculumCourseServ.findAll(),HttpStatus.OK);
} }
/**@PostMapping("/curriculum") //todo now
public ResponseEntity<String> postCurriculum(@RequestHeader("Authorization") String token,@RequestBody Curriculum curriculum){
if (!isSecretaryOrAdmin(token)){
return new UnauthorizedResponse<>("you're not allowed to post a Curriculum");
}
CurriculumServ.save(Curriculum);
return new ResponseEntity<>("created !",HttpStatus.CREATED);
}**/
} }

View File

@ -47,6 +47,6 @@ public class LoginController {
@PostMapping("/request/register") @PostMapping("/request/register")
public ResponseEntity<String> register(@RequestBody InscriptionRequest inscriptionRequest){ public ResponseEntity<String> register(@RequestBody InscriptionRequest inscriptionRequest){
authServ.register(inscriptionRequest); authServ.register(inscriptionRequest);
return new ResponseEntity<>("Is OK", HttpStatus.OK); return new ResponseEntity<>("Is OK", HttpStatus.CREATED);
} }
} }

View File

@ -68,10 +68,10 @@ public class MockController {
curriculumService.save(psychologyBab1); curriculumService.save(psychologyBab1);
Course progra1 = new Course(5,"Programmation et algorithimque 1","TODO DELETE"); Course progra1 = new Course(5,"Programmation et algorithimque 1",joke);
Course chemistry1 = new Course(12, "Thermochimie","TODO DELETE"); Course chemistry1 = new Course(12, "Thermochimie",joke);
Course psycho1 = new Course(21, "rien faire t'as cru c'est psycho", "TODO DELETE"); Course psycho1 = new Course(21, "rien faire t'as cru c'est psycho",joke);
Course commun = new Course(2, "cours commun","TODO DELETE"); Course commun = new Course(2, "cours commun",joke);
courseService.save(progra1); courseService.save(progra1);
courseService.save(chemistry1); courseService.save(chemistry1);

View File

@ -9,6 +9,8 @@ import ovh.herisson.Clyde.Services.AuthenticatorService;
import ovh.herisson.Clyde.Services.UserService; import ovh.herisson.Clyde.Services.UserService;
import ovh.herisson.Clyde.Tables.Role; import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User; import ovh.herisson.Clyde.Tables.User;
import java.security.Key;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -72,6 +74,23 @@ public class UserController {
return new ResponseEntity<>("data modified", HttpStatus.OK); return new ResponseEntity<>("data modified", HttpStatus.OK);
} }
@GetMapping("/teachers")
public ResponseEntity<Iterable<HashMap<String,Object>>> getAllTeachers(@RequestHeader("Authorization") String token){
if (authServ.getUserFromToken(token) == null)
return new UnauthorizedResponse<>(null);
Iterable<User> teachers = userService.getAllTeachers();
ArrayList<HashMap<String, Object>> withoutPassword = new ArrayList<>();
for (User t: teachers){
withoutPassword.add(userWithoutPassword(t));
}
return new ResponseEntity<>(withoutPassword, HttpStatus.OK);
}
/** return user's data except password /** return user's data except password
* @param user the user to return * @param user the user to return
* @return all the user data without the password * @return all the user data without the password

View File

@ -0,0 +1,8 @@
package ovh.herisson.Clyde.Repositories;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.TeacherCourse;
public interface TeacherCourseRepository extends CrudRepository<TeacherCourse, Long> {
}

View File

@ -15,4 +15,8 @@ public interface UserRepository extends CrudRepository<User, Long> {
/** /**
@Query(value = "select a.* from Users a ",nativeQuery = true) @Query(value = "select a.* from Users a ",nativeQuery = true)
Iterable<User> findAllUsers();**/ Iterable<User> findAllUsers();**/
@Query("select u from User u where u.role = ovh.herisson.Clyde.Tables.Role.Teacher")
Iterable<User> findAllTeachers();
} }

View File

@ -50,5 +50,18 @@ public class AuthenticatorService {
return poster.getRole() != Role.Secretary || poster.getRole() != Role.Admin; return poster.getRole() != Role.Secretary || poster.getRole() != Role.Admin;
} }
public boolean IsNotIn(Role[] roles, String token){
if (token == null)
return true;
User poster = getUserFromToken(token);
if (poster == null) return true;
for (Role r:roles){
if (poster.getRole() == r)
return false;
}
return true;
}
} }

View File

@ -3,6 +3,10 @@ package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ovh.herisson.Clyde.Repositories.CourseRepository; import ovh.herisson.Clyde.Repositories.CourseRepository;
import ovh.herisson.Clyde.Tables.Course; import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.User;
import java.util.Map;
@Service @Service
public class CourseService { public class CourseService {
@ -13,11 +17,39 @@ public class CourseService {
this.courseRepo = courseRepo; this.courseRepo = courseRepo;
} }
public void save(Course course){ public Course save(Course course){
courseRepo.save(course); return courseRepo.save(course);
} }
public Course findById(long id){ public Course findById(long id){
return courseRepo.findById(id); return courseRepo.findById(id);
} }
public Course modifyData(long id, Map<String, Object> updates, Role role) {
Course target = courseRepo.findById(id);
if (role == Role.Teacher){
for (Map.Entry<String, Object> entry : updates.entrySet()){
if (entry.getKey().equals("title")){
target.setTitle((String) entry.getValue());
return courseRepo.save(target);
}
}
}
for (Map.Entry<String ,Object> entry: updates.entrySet()){
switch (entry.getKey()){
case "title":
target.setTitle((String) entry.getValue());
break;
case "credits":
target.setCredits((Integer) entry.getValue());
break;
case "owner":
target.setOwner((User) entry.getValue()); //todo check if is a teacher !
break;
}
}
return courseRepo.save(target);
}
} }

View File

@ -0,0 +1,39 @@
package ovh.herisson.Clyde.Services;
import org.springframework.stereotype.Controller;
import ovh.herisson.Clyde.Repositories.TeacherCourseRepository;
import ovh.herisson.Clyde.Repositories.UserRepository;
import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.TeacherCourse;
import ovh.herisson.Clyde.Tables.User;
import java.util.ArrayList;
@Controller
public class TeacherCourseService {
private final TeacherCourseRepository teacherCourseRepo;
private final UserRepository userRepo;
public TeacherCourseService(TeacherCourseRepository teacherCourseRepo, UserRepository userRepo) {
this.teacherCourseRepo = teacherCourseRepo;
this.userRepo = userRepo;
}
public boolean saveAll(Iterable<Long> teacherIds, Course course){
ArrayList<Long> addedIds = new ArrayList<>();
for (Long teacherId : teacherIds){
User teacher = userRepo.findById((long) teacherId);
if ( teacher== null){
return false;
}
if (!addedIds.contains(teacherId))
{
teacherCourseRepo.save(new TeacherCourse(teacher,course));
addedIds.add(teacherId);
}
}
return true;
}
}

View File

@ -103,4 +103,8 @@ public class UserService {
public Iterable<User> getAll(){ public Iterable<User> getAll(){
return userRepo.findAll(); return userRepo.findAll();
} }
public Iterable<User> getAllTeachers (){return userRepo.findAllTeachers();}
} }

View File

@ -1,9 +1,6 @@
package ovh.herisson.Clyde.Tables; package ovh.herisson.Clyde.Tables;
import jakarta.persistence.Entity; import jakarta.persistence.*;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity @Entity
public class Course { public class Course {
@ -12,12 +9,15 @@ public class Course {
private int courseID; private int courseID;
private int credits; private int credits;
private String title; private String title;
private String faculty;
public Course(int credits, String title, String faculty){ @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "Users")
private User owner;
public Course(int credits, String title, User owner){
this.credits = credits; this.credits = credits;
this.title = title; this.title = title;
this.faculty = faculty; this.owner = owner;
} }
public Course() {} public Course() {}
@ -34,14 +34,6 @@ public class Course {
this.credits = credits; this.credits = credits;
} }
public String getFaculty() {
return faculty;
}
public void setFaculty(String faculty){
this.faculty = faculty;
}
public String getTitle() { public String getTitle() {
return title; return title;
} }
@ -49,4 +41,12 @@ public class Course {
public void setTitle(String title){ public void setTitle(String title){
this.title = title; this.title = title;
} }
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
} }

View File

@ -3,30 +3,26 @@ package ovh.herisson.Clyde.Tables;
import jakarta.persistence.*; import jakarta.persistence.*;
@Entity @Entity
public class TeacherGivenCourse { public class TeacherCourse {
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "Users") @JoinColumn(name = "Users")
private User user; private User user;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "Course") @JoinColumn(name = "Course")
private Course course; private Course course;
//This flag helps make the difference between an assistant or a Teacher (who owns the course) public TeacherCourse(User user, Course course){
private boolean owned;
public TeacherGivenCourse(User user, Course course, boolean owned){
this.user = user; this.user = user;
this.course = course; this.course = course;
this.owned = owned;
} }
public TeacherGivenCourse() {} public TeacherCourse() {}
public int getId() { public int getId() {
return id; return id;
@ -48,11 +44,4 @@ public class TeacherGivenCourse {
this.course = course; this.course = course;
} }
public boolean isOwned() {
return owned;
}
public void setOwned(boolean owned) {
this.owned = owned;
}
} }

View File

@ -1,36 +1,10 @@
<script setup> <script setup>
import { toast } from 'vue3-toastify'; import { toast } from 'vue3-toastify';
import { ref, computed } from 'vue' import { ref } from 'vue'
import i18n, { setLang } from './i18n.js' import i18n, { setLang } from './i18n.js'
import { isLogged } from '@/rest/Users.js' import { isLogged } from '@/rest/Users.js'
import { appList, currentView } from '@/rest/apps.js'
// Liste des apps
import LoginPage from './Apps/Login.vue'
import Inscription from "./Apps/Inscription.vue"
import Profil from "./Apps/Profil.vue"
import Courses from "./Apps/ManageCourses.vue"
import Students from "./Apps/StudentsList.vue"
import Users from "./Apps/UsersList.vue"
const apps = {
'/login': LoginPage,
'/inscription': Inscription,
'/profil': Profil,
'/manage-courses' : Courses,
'/students' : Students,
'/users' : Users,
}
const currentPath = ref(window.location.hash)
window.addEventListener('hashchange', () => {
Logged.value = isLogged();
currentPath.value = window.location.hash
})
const currentView = computed(() => {
return apps[currentPath.value.slice(1) || '/']
})
const home=ref(i18n("app.home")) const home=ref(i18n("app.home"))
const notifications=ref(i18n("app.notifications")) const notifications=ref(i18n("app.notifications"))
@ -40,6 +14,9 @@
const Logged = ref(isLogged()); const Logged = ref(isLogged());
const apps = ref([])
appList().then(e => apps.value = e)
</script> </script>
<template> <template>
@ -88,38 +65,13 @@
<div class="leftBar"> <div class="leftBar">
<ul class="vertical"> <ul class="vertical">
<li style="margin-top: 25px;" > <li v-for="app in apps">
<a href="#Messages"> <a href="app.path">
<div class="fa-solid fa-comment" style="font-size: 40px;"></div> <div class="fa-solid" :class="app.icon" style="font-size: 40px;"></div>
<div class="text">{{i18n("app.messages")}}</div> <div class="text">{{app.text}}</div>
</a></li> </a>
<li > </li>
<a href="#Notifications"> </ul>
<div class="fa-solid fa-bell" style="font-size: 40px;" ></div>
<div class="text">{{i18n("app.notifications")}}</div>
</a></li>
<li >
<a href="#Schedule">
<div class="fa-solid fa-calendar-days" style="font-size: 40px;"></div>
<div class="text">{{i18n("app.schedules")}}</div>
</a></li>
<li ><a href="#Forum">
<div class="fa-solid fa-envelope" style="font-size: 40px;" ></div>
<div class="text">{{i18n("app.forum")}}</div></a></li>
<li><a href="#/inscription">
<div class="fa-solid fa-users" style="align-self:center;font-size: 40px;"></div>
<div class="text" style="top:0;">{{i18n("app.inscription.requests")}}</div></a></li>
<li><a href="#/manage-courses">
<div class="fa-solid fa-book" style="align-self:center;font-size: 40px;overflow:none;"></div>
<div class="text">{{i18n("app.manage.courses")}}</div></a></li>
<li><a href="#/students">
<div class="fa-solid fa-users-between-lines" style="font-size: 40px"></div>
<div class="text">{{i18n("app.studentList")}}</div></a></li>
<li><a href="#/users">
<div class="fa-solid fa-users" style="font-size: 40px"></div>
<div class="text">{{i18n("app.users")}}</div></a></li>
</ul>
</div> </div>
<div class="page"> <div class="page">
<div style=" margin:50px;"> <div style=" margin:50px;">
@ -289,3 +241,5 @@
} }
</style> </style>
<!-- vim:set noet sts=0 sw=4 ts=2: -->

View File

@ -1,9 +1,60 @@
import { restGet } from './restConsumer.js' import { restGet } from './restConsumer.js'
import { ref, computed } from 'vue'
import i18n from '@/i18n.js'
// Liste des apps
import LoginPage from '@/Apps/Login.vue'
import Inscription from "@/Apps/Inscription.vue"
import Profil from "@/Apps/Profil.vue"
import Courses from "@/Apps/ManageCourses.vue"
const apps = {
'/login': LoginPage,
'/inscription': Inscription,
'/profil': Profil,
'/manage-courses' : Courses,
}
const appsList = {
'Msg': { path: '#/msg', icon: 'fa-comment', text: i18n("app.messages") },
'Notification': { path: '#/notifs', icon: 'fa-bell', text: i18n("app.notifications") },
'Forum': { path: '#/forum', icon: 'fa-envelope', text: i18n("app.forum") },
'Schedule': { path: '#/schedule', icon: 'fa-calendar-days', text: i18n("app.schedules") },
'Inscription': { path: '#/inscription', icon: 'fa-users', text: i18n("app.inscription.requests") },
'ManageCourses': { path: '#/manage-courses', icon: 'fa-book', text: i18n("app.manage.courses") },
}
const currentPath = ref(window.location.hash)
export const currentView = computed(() => {
return apps[currentPath.value.slice(1) || '/']
})
/**
* Return the list of app accesible by a logged (or not)
* user.
*/
export async function appList(){ export async function appList(){
return restGet("/apps") let ret = [];
let userAppList = await restGet("/apps");
for (let userapp in userAppList) {
if(appsList[userAppList[userapp]] != null){
ret.push(appsList[userAppList[userapp]])
}
}
return ret;
} }
/**
* Check if the specified page is authorized for the
* user
*/
export async function checkPage(page){ export async function checkPage(page){
return restGet("/apps/" + page) return restGet("/apps/" + page)
} }
window.addEventListener('hashchange', () => {
currentPath.value = window.location.hash
})
// vim:set noet sts=0 sw=4 ts=2 tw=2:

View File

@ -46,7 +46,6 @@ async function _rest(endPoint, config){
pending: config['pending'] != null ? config['pending'] : 'pending', pending: config['pending'] != null ? config['pending'] : 'pending',
error: config['error'] != null ? config['error'] : 'Network Failure...', error: config['error'] != null ? config['error'] : 'Network Failure...',
success: config['success'] != null ? config['success'] : {render(res){ success: config['success'] != null ? config['success'] : {render(res){
console.log(res);
return res.data.ok ? "Success" : "error"; return res.data.ok ? "Success" : "error";
}}, }},
}) })