1
0
forked from PGL/Clyde

post User by secretary

This commit is contained in:
Bartha Maxime 2024-04-21 23:14:56 +02:00
parent 608b6e4893
commit 1a266cdfbd
10 changed files with 208 additions and 90 deletions

View File

@ -75,6 +75,7 @@ public class ApplicationsController {
authorizedApps.add(Applications.StudentsList);} authorizedApps.add(Applications.StudentsList);}
if (!authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin},token)){ if (!authServ.isNotIn(new Role[]{Role.Secretary,Role.Admin},token)){
authorizedApps.add(Applications.CreateUser);
authorizedApps.add(Applications.UsersList);} authorizedApps.add(Applications.UsersList);}
if (researchesServ.getResearcherByUser(user) != null) if (researchesServ.getResearcherByUser(user) != null)

View File

@ -86,19 +86,20 @@ public class UserController {
* @return a string clarifying the issue (if there is any) * @return a string clarifying the issue (if there is any)
*/ */
@PatchMapping("/user/{id}") @PatchMapping("/user/{id}")
public ResponseEntity<String> patchUser(@RequestHeader("Authorization") String token, public ResponseEntity<Map<String,Object>> patchUser(@RequestHeader("Authorization") String token,
@RequestBody Map<String,Object> updates, @RequestBody Map<String,Object> updates,
@PathVariable Long id) { @PathVariable Long id) {
if (token == null) return new UnauthorizedResponse<>(null); if (token == null) return new UnauthorizedResponse<>(null);
User poster = authServ.getUserFromToken(token); User poster = authServ.getUserFromToken(token);
if (poster == null) {return new UnauthorizedResponse<>("bad token");} if (poster == null) {return new UnauthorizedResponse<>(null);}
if (!userService.modifyData(id, updates, poster)) User modified = userService.modifyData(id,updates,poster);
if (modified ==null)
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(null, HttpStatus.OK); return new ResponseEntity<>(ProtectionService.userWithoutPassword(modified), HttpStatus.OK);
} }
@GetMapping("/teachers") @GetMapping("/teachers")

View File

@ -43,61 +43,55 @@ public class UserService {
* @param targetId the id of the user to update * @param targetId the id of the user to update
* @return if the changes were done or not * @return if the changes were done or not
*/ */
public boolean modifyData(long targetId, Map<String ,Object> updates, User poster){ public User modifyData(long targetId, Map<String ,Object> updates, User poster){
User target = userRepo.findById(targetId); User target = userRepo.findById(targetId);
if (target == null) if (target == null)
return false; return null;
if (poster.getRegNo().equals(target.getRegNo())){ if (!target.getRegNo().equals(poster.getRegNo()) && !(poster.getRole() == Role.Secretary) &&
for (Map.Entry<String, Object> entry : updates.entrySet()){ !(poster.getRole() == Role.Admin))
return null;
switch (entry.getKey()){ for (Map.Entry<String, Object> entry : updates.entrySet()){
case "firstName": System.out.println(entry.getValue());
target.setFirstName((String) entry.getValue()); switch (entry.getKey()){
break; case "firstName":
case "lastName": target.setFirstName((String) entry.getValue());
target.setLastName((String) entry.getValue()); break;
break; case "lastName":
case "email": target.setLastName((String) entry.getValue());
target.setEmail((String) entry.getValue()); break;
break; case "email":
case "address": target.setEmail((String) entry.getValue());
target.setAddress((String) entry.getValue()); break;
break; case "address":
case "country": target.setAddress((String) entry.getValue());
target.setCountry((String) entry.getValue()); break;
break; case "country":
case "birthDate": target.setCountry((String) entry.getValue());
target.setBirthDate((Date) entry.getValue()); break;
break; case "birthDate":
case "profilePictureUrl": target.setBirthDate((Date) entry.getValue());
target.setProfilePictureUrl((String) entry.getValue()); break;
break; case "profilePictureUrl":
case "password": target.setProfilePictureUrl((String) entry.getValue());
target.setPassword(passwordEncoder.encode((String) entry.getValue())); break;
break; case "password":
} target.setPassword((String) entry.getValue());
} break;
userRepo.save(target); case "role":
return true; //a user can't change his own role
} if (poster.getRole()==Role.Secretary || poster.getRole() == Role.Admin){
// the secretary can change roles (for example if a student becomes a teacher) Role wanted = Role.valueOf((String) entry.getValue());
else if (poster.getRole() == Role.Secretary) if (wanted == Role.Admin && poster.getRole() != Role.Admin)
{ return null;
for (Map.Entry<String, Object> entry : updates.entrySet()){ target.setRole(wanted);
}
if ( entry.getKey().equals("role")) {
if (entry.getValue() == Role.Admin) {return false;}
target.setRole((Role) entry.getValue());
userRepo.save(target);
return true;
}
} }
} }
return false; userRepo.save(target);
return target;
} }
@ -105,7 +99,7 @@ public class UserService {
return passwordEncoder.matches(tryingPassword, user.getPassword()); return passwordEncoder.matches(tryingPassword, user.getPassword());
} }
public User save(User user){ public User save(User user){
user.setPassword(passwordEncoder.encode(user.getPassword())); user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepo.save(user); return userRepo.save(user);
} }

View File

@ -23,5 +23,5 @@ public enum Applications {
ManageResearcherProfile, ManageResearcherProfile,
//the list of all researches (filterable) //the list of all researches (filterable)
ListResearches, StudentsList ListResearches, CreateUser, StudentsList
} }

View File

@ -30,6 +30,7 @@ app.studentList=Students List
app.users=Users app.users=Users
app.manage.researcherProfile=Manage researcher profile app.manage.researcherProfile=Manage researcher profile
app.list.researches=List researches app.list.researches=List researches
app.Create.User=Create User
request.moreInfos=More Infos request.moreInfos=More Infos
request.accept=Accept request.accept=Accept
request.refuse=Refuse request.refuse=Refuse
@ -123,3 +124,9 @@ Researcher.Delete=Delete Researcher Profile
Researcher.Add=Create Researcher Profile Researcher.Add=Create Researcher Profile
Confirm=Confirm Confirm=Confirm
Cancel=Cancel Cancel=Cancel
LastName=Last Name
FirstName=First Name
Profile.Picture=Profile Picture
Role=Role
Password=Password
Create.User=Create User

View File

@ -30,6 +30,7 @@ app.studentList=Liste des étudiants
app.users=Utilisateurs app.users=Utilisateurs
app.manage.researcherProfile= gérer son profil de chercheur app.manage.researcherProfile= gérer son profil de chercheur
app.list.researches=Lister les recherches app.list.researches=Lister les recherches
app.Create.User=créer un utilisateur
request.moreInfos=Plus d'Infos request.moreInfos=Plus d'Infos
request.accept=Accepter request.accept=Accepter
request.refuse=Refuser request.refuse=Refuser
@ -121,3 +122,9 @@ Country=Pays
BirthDate=Date de Naissance BirthDate=Date de Naissance
Confirm=Confirmer Confirm=Confirmer
Cancel=Annuler Cancel=Annuler
LastName=Nom de Famille
FirstName=Prénom
Profile.Picture=Photo de Profil
Role=Role
Password=Mot de Passe
Create.User=Créer l'utilisateur

View File

@ -3,36 +3,37 @@ import i18n from "../i18n.js";
import {ref} from "vue"; import {ref} from "vue";
import {fetchAllResearchers} from "@/rest/ScientificPublications/ManageResearch.js"; import {fetchAllResearchers} from "@/rest/ScientificPublications/ManageResearch.js";
import {deleteResearcher, postResearcher} from "@/rest/ScientificPublications/ResearcherProfile.js"; import {deleteResearcher, postResearcher} from "@/rest/ScientificPublications/ResearcherProfile.js";
import {patchUser} from "@/rest/Users.js";
const props = defineProps(['user']) const props = defineProps(['user'])
const modifying =ref(false) const modifying =ref(false)
const toModify = Object.assign({},{}) const toModify = Object.assign({},{})
const toCreate = Object.assign({},{}) const toCreate = Object.assign({},{})
const allResearcher = ref( await fetchAllResearchers()) const allResearcher = ref( await fetchAllResearchers())
const researcher = ref() const researcher = ref()
const user = props.user const user = ref(props.user)
const isResearcher = ref(false) const isResearcher = ref(false)
const creating = ref(false) const creating = ref(false)
for (let i = 0; i < allResearcher.value.length; i++) { for (let i = 0; i < allResearcher.value.length; i++) {
if (user.regNo === allResearcher.value[i].user.regNo){ if (user.value.regNo === allResearcher.value[i].user.regNo){
researcher.value = allResearcher.value[i] researcher.value = allResearcher.value[i]
isResearcher.value = true isResearcher.value = true
} }
} }
function getPP(){ function getPP(){
if(user.profilePictureUrl === null){ if(user.value.profilePictureUrl === null){
return "/Clyde.png" return "/Clyde.png"
} }
return user.profilePictureUrl return user.value.profilePictureUrl
} }
async function createResearcher(){ async function createResearcher(){
toCreate.user = user toCreate.user = user.value
await postResearcher(toCreate) await postResearcher(toCreate)
creating.value = false creating.value = false
for (let i = 0; i < allResearcher.value.length; i++) { for (let i = 0; i < allResearcher.value.length; i++) {
if (user.regNo === allResearcher.value[i].user.regNo){ if (user.value.regNo === allResearcher.value[i].user.regNo){
researcher.value = allResearcher.value[i] researcher.value = allResearcher.value[i]
isResearcher.value = true isResearcher.value = true
} }
@ -46,6 +47,13 @@ async function deleteResearcherById(){
allResearcher.value = await fetchAllResearchers() allResearcher.value = await fetchAllResearchers()
} }
async function modify(){
if (modifying.value){
user.value = await patchUser(user.value.regNo, toModify)
}
modifying.value =!modifying.value
}
</script> </script>
<template> <template>
@ -89,7 +97,7 @@ async function deleteResearcherById(){
</div> </div>
</div> </div>
<div></div> <div></div>
<button id="ModifyButton" @click="modifying= !modifying"> {{i18n("Modify.Data")}}</button> <button id="ModifyButton" @click="modify"> {{i18n("Modify.Data")}}</button>
<div></div> <div></div>
<div> <div>
<button v-if="isResearcher" id="deleteButton" @click="deleteResearcherById"> {{i18n("Researcher.Delete")}}</button> <button v-if="isResearcher" id="deleteButton" @click="deleteResearcherById"> {{i18n("Researcher.Delete")}}</button>
@ -111,8 +119,6 @@ async function deleteResearcherById(){
{{i18n("Domain")}} : {{i18n("Domain")}} :
<input type="text" v-model="toCreate.domain"></li> <input type="text" v-model="toCreate.domain"></li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
@ -133,6 +139,7 @@ async function deleteResearcherById(){
} }
.container{ .container{
margin-top: 25px;
min-width:675px; min-width:675px;
display:grid; display:grid;
grid-template-columns:10vw 50vw; grid-template-columns:10vw 50vw;

View File

@ -0,0 +1,117 @@
<script setup>
import i18n from "@/i18n.js";
import {uploadProfilePicture} from "@/rest/uploads.js";
import {postUser} from "@/rest/Users.js";
import {ref} from "vue";
let toCreate = Object.assign({},{})
const today = new Date()
const date = today.getFullYear() +"-" + ("0" + (today.getMonth()+1)).slice(-2) + "-" + ("0" + today.getDate()).slice(-2);
async function createUser(){
if (toCreate.lastName === null || toCreate.birthDate === null || toCreate.firstName === null ||
toCreate.email === null || toCreate.address === null || toCreate.role === null || toCreate.password === null)
return
await postUser(toCreate)
toCreate = Object.assign({},{})
}
async function getProfilePic(data){
const pp= await uploadProfilePicture(data)
toCreate.profilePictureUrl = pp.url
}
</script>
<template>
<div class="body">
<div class="container">
<div class = "globalInfos">
<div class="infosContainer">
<ul>
<li>{{i18n("LastName")}} : <input type="text" v-model="toCreate.lastName"></li>
<li>{{i18n("FirstName")}} : <input type="text" v-model="toCreate.firstName"></li>
<li> E-mail : <input type="text" v-model="toCreate.email"></li>
<li>{{i18n("Country")}} : <input type="text" v-model="toCreate.country"></li>
<li>{{i18n("Address")}} : <input type="text" v-model="toCreate.address"></li>
<li>{{i18n("BirthDate")}} : <input type="date" min="1924-01-01" :max="date" v-model="toCreate.birthDate"></li>
<li>{{i18n("Profile.Picture")}} :
<input type="file" @change="getProfilePic($event.target.files);" accept="image/*">
</li>
<li>{{i18n("Role")}} :
<select v-model="toCreate.role">
<option value="Student">{{i18n("Student")}}</option>
<option value="Teacher">{{i18n("Teacher")}}</option>
<option value="Secretary">{{i18n("Secretary")}}</option>
<option value="InscriptionService">{{i18n("InscriptionService")}}</option>
</select>
</li>
<li>{{i18n("Password")}} : <input type="password" v-model="toCreate.password"></li>
</ul>
<div style="text-align: end"> <button id="createButton" @click="createUser"> {{i18n("Create.User")}}</button></div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.container{
margin-top: 25px;
min-width:675px;
display:grid;
grid-template-columns:10vw 50vw;
grid-template-rows:200px auto;
column-gap:2.7%;
row-gap:45px;
grid-template-areas:
"profilPic globalInfos"
"minfos minfos";
}
.globalInfos {
grid-area:globalInfos;
align-self :center;
}
.body {
min-width:960px;
width:100%;
display:flex;
align-items:center;
justify-content:center;
margin-top:5%;
}
.infosContainer {
border:2px solid black;
font-size:23px;
color:white;
background-color:rgb(50,50,50);
border-radius:10px;
}
#createButton{
align-self: center;
text-align: center;
border: 2px solid black;
color: white;
font-size: x-large;
background-color: #07bc0c;
border-radius: 20px
}
#createButton:hover{
background: #4cd964;
}
</style>

View File

@ -13,6 +13,10 @@ export function disconnect(){
setCookie("session_token", ";expires= Thu, 01 Jan 1970 00:00:01 GMT") setCookie("session_token", ";expires= Thu, 01 Jan 1970 00:00:01 GMT")
} }
export async function patchUser(id,data){
return restPatch("/user/" +id, data)
}
/** /**
* Register a user (tokenless) * Register a user (tokenless)
* *
@ -43,31 +47,8 @@ export async function register(firstname, lastname, birthDate, password, email,
}); });
} }
/** export async function postUser(data){
* Register a user (by secretary) return restPost("/user", data)
*
* @param firstname
* @param lastname
* @param birthdate
* @param password
* @param mail
* @param address
* @param country
* @param imageId id of the image in database returned when uploaded
*
* PS: the password is not required as it is generated by the backend and sent to the user
* by mail. it's up to the user to change it if he cares about security
*/
export async function createUser(firstname, lastname, birthDate, email, address, country, role, imageId){
return restPost("/user", {
firstname: firstname,
lastname: lastname,
birthDate: birthDate,
password: password,
email: email,
address: address,
country: country,
});
} }
/** /**

View File

@ -15,6 +15,7 @@ import ManageRequests from "@/Apps/Inscription/ManageRequests.vue";
import ManageResearcherProfile from "@/Apps/ScientificPublications/ManageResearcherProfile.vue"; import ManageResearcherProfile from "@/Apps/ScientificPublications/ManageResearcherProfile.vue";
import ListResearches from "@/Apps/ScientificPublications/ListResearches.vue"; import ListResearches from "@/Apps/ScientificPublications/ListResearches.vue";
import ResearcherProfile from "@/Apps/ScientificPublications/ResearcherProfile.vue"; import ResearcherProfile from "@/Apps/ScientificPublications/ResearcherProfile.vue";
import CreateUser from "@/Apps/CreateUser.vue";
const apps = { const apps = {
'/login': LoginPage, '/login': LoginPage,
@ -26,7 +27,8 @@ const apps = {
'/manage-researcher-profile' : ManageResearcherProfile, '/manage-researcher-profile' : ManageResearcherProfile,
'/msg' : Msg, '/msg' : Msg,
'/researches' : ListResearches, '/researches' : ListResearches,
'/researcher-profile': ResearcherProfile '/researcher-profile': ResearcherProfile,
'/create-user': CreateUser
} }
const appsList = { const appsList = {
@ -40,6 +42,7 @@ const appsList = {
'StudentsList':{ path: '#/students-list',icon: 'fa-users',text: i18n("app.studentList")}, 'StudentsList':{ path: '#/students-list',icon: 'fa-users',text: i18n("app.studentList")},
'UsersList':{ path: '#/users-list',icon: 'fa-users',text: i18n("app.users")}, 'UsersList':{ path: '#/users-list',icon: 'fa-users',text: i18n("app.users")},
'ManageResearcherProfile':{path:'#/manage-researcher-profile',icon:'fa-book-bookmark',text:i18n("app.manage.researcherProfile")}, 'ManageResearcherProfile':{path:'#/manage-researcher-profile',icon:'fa-book-bookmark',text:i18n("app.manage.researcherProfile")},
'CreateUser':{path:'#/create-user',icon:'fa-plus', text:i18n("app.Create.User")}
} }