1
0
forked from PGL/Clyde

Big commit:

make some changes to profile to provide an interface for a student to manage his courses.

implements the submission of exemptions request
This commit is contained in:
LeoMoulin 2024-04-06 16:12:11 +02:00
parent 648b73b585
commit 3c721de18b
14 changed files with 360 additions and 74 deletions

View File

@ -135,4 +135,5 @@ public class CourseController {
courseServ.delete(courseServ.findById(id)); courseServ.delete(courseServ.findById(id));
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);
} }
} }

View File

@ -120,11 +120,11 @@ public class CurriculumController {
} }
@GetMapping("/externalcurriculum/{inscriptionRequestId}") @GetMapping("/externalcurriculum/{inscriptionRequestId}")
public ResponseEntity<Map<String,Object>> getInscriptionRequestExternalCurriculum(@RequestHeader("Authorization") String token, @PathVariable String inscriptionRequestId){ public ResponseEntity<Map<String,Object>> getInscriptionRequestExternalCurriculum(@RequestHeader("Authorization") String token, @PathVariable long inscriptionRequestId){
if (authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin, Role.Teacher},token)) if (authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin, Role.Teacher},token))
return new UnauthorizedResponse<>(null); return new UnauthorizedResponse<>(null);
HashMap<String,Object> toReturn = userCurriculumServ.findAllExternalCurriculumByInscriptionRequestId(Long.parseLong(inscriptionRequestId)); HashMap<String,Object> toReturn = userCurriculumServ.findAllExternalCurriculumByInscriptionRequestId(inscriptionRequestId);
if (toReturn == null) if (toReturn == null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);

View File

@ -79,6 +79,7 @@ public class MockController {
ucr.save(new UserCurriculum(joe, infoBab1, 2022)); ucr.save(new UserCurriculum(joe, infoBab1, 2022));
ucr.save(new UserCurriculum(joe, chemistryBab1, 2023)); ucr.save(new UserCurriculum(joe, chemistryBab1, 2023));
ucr.save(new UserCurriculum(joe, infoBab1, 2023));
ucr.save(new UserCurriculum(joe, psychologyBab1, 2020)); ucr.save(new UserCurriculum(joe, psychologyBab1, 2020));
ucr.save(new UserCurriculum(popo, infoBab1, 2022)); ucr.save(new UserCurriculum(popo, infoBab1, 2022));
ucr.save(new UserCurriculum(popo, infoBab2, 2023)); ucr.save(new UserCurriculum(popo, infoBab2, 2023));
@ -96,7 +97,7 @@ public class MockController {
CurriculumCourseService.save(new CurriculumCourse(infoBab1,progra1)); CurriculumCourseService.save(new CurriculumCourse(infoBab1,progra1));
CurriculumCourseService.save(new CurriculumCourse(infoBab1,commun)); CurriculumCourseService.save(new CurriculumCourse(infoBab1,commun));
CurriculumCourseService.save(new CurriculumCourse(infoBab1, psycho1));
CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,psycho1)); CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,psycho1));
CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,commun)); CurriculumCourseService.save(new CurriculumCourse(psychologyBab1,commun));

View File

@ -0,0 +1,32 @@
package ovh.herisson.Clyde.EndPoints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ovh.herisson.Clyde.Repositories.ExemptionsRequestRepository;
import ovh.herisson.Clyde.Tables.ExemptionsRequest;
import ovh.herisson.Clyde.Tables.RequestState;
@RestController
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
public class RequestsController {
public final ExemptionsRequestRepository err;
public RequestsController(ExemptionsRequestRepository err) {
this.err = err;
}
@PostMapping(value="/exemptionreq")
public ResponseEntity<String> register(@RequestBody ExemptionsRequest exemptionsRequest){
exemptionsRequest.setState(RequestState.Pending);
err.save(exemptionsRequest);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}

View File

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

View File

@ -9,21 +9,16 @@ public class ExemptionsRequest {
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@ManyToOne private long userRegNo;
@JoinColumn(name = "Users") private long courseId;
private User user;
@ManyToOne
@JoinColumn(name = "Course")
private Course course;
private String justifDocument; private String justifDocument;
private RequestState state; private RequestState state;
public ExemptionsRequest(User user, Course course, String justifDocument, RequestState state){ public ExemptionsRequest(Long userRegNo, long courseId, String justifDocument, RequestState state){
this.user = user; this.userRegNo = userRegNo;
this.course = course; this.courseId = courseId;
this.justifDocument = justifDocument; this.justifDocument = justifDocument;
this.state = state; this.state = state;
} }
@ -31,20 +26,20 @@ public class ExemptionsRequest {
public ExemptionsRequest(){} public ExemptionsRequest(){}
public User getUser() { public Long getUserRegNo() {
return user; return userRegNo;
} }
public void setUser(User user) { public void setUserRegNo(Long userRegNo) {
this.user = user; this.userRegNo = userRegNo;
} }
public Course getCourse() { public long getCourseId() {
return course; return courseId;
} }
public void setCourse(Course course) { public void setCourseId(long courseId) {
this.course = course; this.courseId = courseId;
} }
public String getJustifDocument() { public String getJustifDocument() {

View File

@ -1,8 +1,7 @@
package ovh.herisson.Clyde.Tables; package ovh.herisson.Clyde.Tables;
public enum FileType { public enum FileType {
ProfilePicture, ProfilePicture,
EducationCertificate,
EducationCertificate JustificationDocument
} }

View File

@ -1,13 +1,15 @@
<script setup> <script setup>
import i18n from "@/i18n.js" import i18n from "@/i18n.js"
import {getUser} from '../rest/Users.js' import {getUser} from '../rest/Users.js'
import {getcurriculum, getSomeonesCurriculumList} from "@/rest/curriculum.js"; import {getcurriculum, getExternalCurriculumListByInscrReq, getSomeonesCurriculumList} from "@/rest/curriculum.js";
import {getRegisters} from "@/rest/ServiceInscription.js"; import {getRegisters} from "@/rest/ServiceInscription.js";
import {get} from "jsdom/lib/jsdom/named-properties-tracker.js";
const props = defineProps(['target']); const props = defineProps(['target']);
let request = await getRegisters(props.target); let request = await getRegisters(props.target);
const cursus = await getcurriculum(request.curriculum); const cursus = await getcurriculum(request.curriculum);
const externalCurriculum = await getExternalCurriculumListByInscrReq(request.id)
console.log(externalCurriculum)
function getPP(){ function getPP(){
if(request.profilePictureUrl === null){ if(request.profilePictureUrl === null){
return "/Clyde.png" return "/Clyde.png"
@ -44,6 +46,19 @@ function getPP(){
</div> </div>
</div> </div>
</div> </div>
<div class="moreInfos">
<div class = "oldcursus">
<div class="listTitle">
Cursus extérieurs a l'univesité
</div>
<div class="listElement">
<div class=" containerElement" v-for="item in externalCurriculum">
<div class="formation">item.formation</div>
<div class="school">item.school</div>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -152,4 +167,42 @@ button{
border-radius:20px; border-radius:20px;
} }
.moreInfos {
display:grid;
grid-template-rows:200px auto;
column-gap:50px;
row-gap:45px;
grid-template-areas:
"minfos minfos";
grid-template-columns:600px 600px;
align-items:center;
justify-content:center;
margin-left: 320%;
}
.listTitle{
display: flex;
justify-content: center;
align-items: center;
width:250px;
margin-left:auto;
margin-right:auto;
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;margin-bottom:10px;
}
.listElement{
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;
margin-bottom:10px;
}
</style> </style>

View File

@ -64,7 +64,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="newcursus" > <div class="newcursus">
<div class="listTitle"> <div class="listTitle">
Cursus Actuel Cursus Actuel
</div> </div>

View File

@ -0,0 +1,145 @@
<script setup>
import {reactive, ref} from "vue";
import i18n from "@/i18n.js";
import {getCourse} from "@/rest/courses.js";
import {getcurriculum} from "@/rest/curriculum.js";
import {uploadFile, uploadProfilePicture} from "@/rest/uploads.js";
import {createExemptionsRequest} from "@/rest/requests.js";
import {getSelf} from "@/rest/Users.js";
const props = defineProps(["cursuslist"])
const selectedCurriculum = ref(props.cursuslist[0])
const user = await getSelf()
const courseslist = ref(await getcurriculum(selectedCurriculum.value.curriculumId))
const list = ref(true)
const ppData = ref({})
async function updateCourseList(){
courseslist.value = await getcurriculum(selectedCurriculum.value.curriculumId)
}
async function uploadfileandgetpath(file, type){
const a = await uploadFile(file, type);
exemptReq.justifDocument = a.url
}
async function postExemptionRequest(file, type){
const a = await uploadFile(file, type);
exemptReq.justifDocument = a.url
await createExemptionsRequest(exemptReq)
}
const exemptReq = reactive({
userRegNo : user.regNo,
courseId : null,
justifDocument : "e",
state : null
})
</script>
<template style="margin-top:5%;">
<div v-if="list == true">
<span>Selected Cursus : </span>
<select v-model="selectedCurriculum" @change="updateCourseList">
<option v-for="item in props.cursuslist" :value="item">Bac {{item.year}} {{item.option}}</option>
</select>
<div style="display:flex; justify-content:center;" v-for="item in courseslist.courses">
<div class="bodu">
<div class="container">
<div class="title">{{item.title}}</div>
<div class="firstname">{{item.owner.firstName}}</div>
<div class="lastname">{{item.owner.lastName}}</div>
<div class="credits">credits : {{item.credits}}</div>
<div class="askexemption"><button style="background-color:rgb(105,0,0);" @click="list= !list;exemptReq.courseId=item.courseId">Ask exemption</button></div>
</div>
</div>
</div>
</div>
<div v-else>
<p>Please upload the justification document for the exemption </p>
<label class="browser">
<input type="file" @change="ppData.value = $event.target.files" accept="image/*" ref="filepath">
</label>
<button style="width:15%; margin-top: 5%;" @click="postExemptionRequest(ppData.value, 'JustificationDocument');">
Submit exemption request
</button>
</div>
</template>
<style scoped>
.container{
color:white;
height:100px;
font-size:30px;
display:grid;
grid-template-columns:30% 20% 15% 15% 15%;
grid-template-areas:"title firstname lastname credits askexemption";
column-gap:10px;
}
.title {
grid-area:title;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
font-size: 50%;
margin-left:30px;
}
.credits {
grid-area:credits;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
font-size: 50%;
}
.askexemption {
grid-area:askexemption;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
.lastname{
grid-area:lastname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
font-size: 50%;
}
.firstname{
grid-area:firstname;
align-self:center;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
font-size: 50%;
padding-left: 30%;
}
.bodu {
margin-top:2%;
width:100%;
border:2px solid black;
border-radius:9px;
background-color:rgb(50,50,50);
}
button{
border:none;
background-color:rgb(239, 60, 168);
border-radius:10px;
height:35px;
margin-top:10px;
}
</style>

View File

@ -1,16 +1,18 @@
<script setup> <script setup>
import {reactive, ref } from 'vue' import {reactive, ref } from 'vue'
import {getSelf,alterSelf,disconnect,deleteUser} from '../rest/Users.js' import {getSelf,alterSelf,disconnect,deleteUser} from '../rest/Users.js'
import {getSelfCurriculum, getAllCurriculums} from '../rest/curriculum.js' import {getSelfCurriculum, getAllCurriculums, getSomeonesCurriculumList} from '../rest/curriculum.js'
import {getCourses} from "../rest/courses.js" import {getCourses} from "../rest/courses.js"
import i18n from "@/i18n.js" import i18n from "@/i18n.js"
import { uploadProfilePicture } from '@/rest/uploads.js' import { uploadProfilePicture } from '@/rest/uploads.js'
import CourseList from "@/Apps/CourseList.vue";
const user = ref(await getSelf()); const user = ref(await getSelf());
const UserCurriculum = ref(""); const UserCurriculum = ref("");
const curricula = ref (await getAllCurriculums()); const curricula = ref (await getAllCurriculums());
if(user.value.role === "Student"){ if(user.value.role === "Student"){
UserCurriculum.value = await getSelfCurriculum(); UserCurriculum.value = await getSomeonesCurriculumList(user.value.regNo);
} }
if(user.role === "Teacher"){ if(user.role === "Teacher"){
@ -19,6 +21,7 @@
const modif = ref(false); const modif = ref(false);
const curric = ref(false); const curric = ref(false);
const reg = ref(false); const reg = ref(false);
const courseslist = ref(false);
const pattern = { const pattern = {
profilPictureUrl:null, profilPictureUrl:null,
@ -86,17 +89,35 @@
} }
return user.profilePictureUrl return user.profilePictureUrl
} }
function getYear(){
let date = new Date();
if (date.getMonth() <= 6){
return date.getFullYear()-1
}
return date.getFullYear()
}
//This function travels through the student cursus array and extract the current cursus of the student
function getActualCurriculumList(){
let actualCurriculumList = [];
for (let i = 0; i < UserCurriculum.value.curriculumList.length; i++){
if (UserCurriculum.value.curriculumList[i].dateyear === getYear()){
actualCurriculumList.push(UserCurriculum.value.curriculumList[i]);
}
}
return actualCurriculumList
}
</script> </script>
<template> <template>
<div class="body"> <div class="body">
<div class="container"> <div class="container" v-if="courseslist == false">
<div class="profilPic"> <div class="profilPic">
<img class="subContainter" :src=getPP()> <img class="subContainter" :src=getPP()>
</div> </div>
<div class="globalInfos"> <div class="globalInfos">
<div v-if="modif==false && curric==false && reg==false " class="infosContainer" > <div v-if="modif==false && curric==false && reg==false" class="infosContainer">
<div> <div>
{{user.firstName}} {{user.lastName}} {{user.firstName}} {{user.lastName}}
</div> </div>
@ -119,6 +140,9 @@
<div v-if="(user.role==='Student')"> <div v-if="(user.role==='Student')">
<button @click="curric=!curric">{{i18n("profile.change.curriculum")}}</button> <button @click="curric=!curric">{{i18n("profile.change.curriculum")}}</button>
</div> </div>
<div v-if="(user.role==='Student')">
<button @click="courseslist=!courseslist">Manage Courses</button>
</div>
</div> </div>
<div v-else-if="modif" class="infosContainer"> <div v-else-if="modif" class="infosContainer">
<div> <div>
@ -182,29 +206,38 @@
<button @click=" reg=!reg; resetInputs(personnalInfos,patternInfos);" style="float:right;">{{i18n("courses.back")}}</button> <button @click=" reg=!reg; resetInputs(personnalInfos,patternInfos);" style="float:right;">{{i18n("courses.back")}}</button>
</div> </div>
</div> </div>
</div> </div>
<div v-if="modif==false && curric==false && reg==false "class="moreInfos"> <div v-if="modif==false && curric==false && reg==false "class="moreInfos">
<div class = "oldcursus">
<div v-if="(user.role ==='Student')"> <div class="listTitle">
<div class="listTitle"> Anciens Cursus
{{i18n("profile.course.list")}} </div>
<div class="listElement">
<div class=" containerElement" v-for="item in UserCurriculum.curriculumList">
<div class="year" v-if="parseInt(item.dateyear) !== getYear()">Bac {{item.year}}</div>
<div class="option" v-if="parseInt(item.dateyear) !== getYear()">{{item.option}}</div>
<div class="dateyear" v-if="parseInt(item.dateyear) !== getYear()">Année {{item.dateyear}}-{{item.dateyear+1}}</div>
</div>
</div>
</div> </div>
<div class="listElement" v-for="item in UserCurriculum.courses"> <div class="actualcursus">
<div class=" containerElement"> <div class="listTitle">
<div class="name"> {{item.title}} </div> Cursus Actuel
<div class="teacher">{{item.owner.lastName}}</div> </div>
<div class="credits">Credits:{{item.credits}}</div> <div class="listElement">
<div class=" containerElement" v-for="item in UserCurriculum.curriculumList" >
<div class="year" v-if="parseInt(item.dateyear) === getYear()">Bac {{item.year}}</div>
<div class="option" v-if="parseInt(item.dateyear) === getYear()">{{item.option}}</div>
<div class="dateyear" v-if="parseInt(item.dateyear) === getYear()">Année {{item.dateyear}}-{{item.dateyear+1}}</div>
</div>
</div>
</div> </div>
</div>
</div>
<div>
</div>
</div> </div>
</div> </div>
<div v-if="courseslist === true" style="width: 80%">
<CourseList :cursuslist="getActualCurriculumList()"/>
<button style="width: 10%; margin-top: 5%" @click="courseslist = false">Return to profile</button>
</div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
@ -240,7 +273,32 @@
} }
.moreInfos { .moreInfos {
grid-area:minfos; margin-top: 50%;
display:grid;
grid-template-rows:200px auto;
column-gap:50px;
row-gap:45px;
grid-template-areas:
"minfos minfos";
grid-template-columns:600px 600px;
align-items:center;
justify-content:center;
margin-left: 320%;
}
.listTitle{
display: flex;
justify-content: center;
align-items: center;
width:250px;
margin-left:auto;
margin-right:auto;
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;margin-bottom:10px;
} }
.body { .body {
min-width:960px; min-width:960px;
@ -252,11 +310,12 @@
} }
.containerElement{ .containerElement{
justify-content:center; justify-content:center;
display:grid; display:grid;
grid-template-columns:38.8% 38.8% 22.4%; grid-template-columns:100px 100px 300px;
grid-template-areas: grid-template-areas:
"name teacher credits"; "year option dateyear";
column-gap:10px; column-gap:40px;
padding-left: 25px;
} }
@ -275,24 +334,8 @@
align-self:center; align-self:center;
} }
.listTitle{
min-width:197px;
display: flex;
justify-content: center;
align-items: center;
width:8vw;
margin-left:auto;
margin-right:auto;
border:2px solid black;
font-size:25px;
color:white;
padding:20px;
background-color:rgb(50,50,50);
border-radius:20px;margin-bottom:10px;
}
.listElement{ .listElement{
min-width:625px;
border:2px solid black; border:2px solid black;
font-size:25px; font-size:25px;
color:white; color:white;

View File

@ -3,7 +3,7 @@
* *
* TODO: On time of writing, the backend doesn't support these endpoints so it could be modified in the future. * TODO: On time of writing, the backend doesn't support these endpoints so it could be modified in the future.
*/ */
import {restGet, restPatch} from './restConsumer.js' import {restGet, restPatch, restPost} from './restConsumer.js'
/** /**
* create a new register requests that can be recovered by the registering service * create a new register requests that can be recovered by the registering service

View File

@ -64,3 +64,7 @@ export async function createExternalCurriculum(inscriptionRequestId,school, form
justifdocUrl : justifdocUrl justifdocUrl : justifdocUrl
}) })
} }
export async function getExternalCurriculumListByInscrReq(inscriptionRequestId){
return restGet("/externalCurriculum/"+parseInt(inscriptionRequestId))
}

View File

@ -0,0 +1,5 @@
import {restPost} from "@/rest/restConsumer.js";
export async function createExemptionsRequest(exempReq){
return restPost("/exemptionreq", exempReq)
}