feat: merged Keycloak / postgres
All checks were successful
Format / formatting (push) Successful in 7s
CI / build (push) Successful in 11s

This commit is contained in:
Pierre Tellier 2025-02-18 17:20:08 +01:00
commit 11ab5e1dc4
22 changed files with 258 additions and 84 deletions

View File

@ -6,15 +6,18 @@ import enseirb.myinpulse.postgres_db.repository.ComptesRendusRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.management.relation.RoleNotFoundException;
@SpringBootApplication @SpringBootApplication
@RestController @RestController
public class GetUserInfo { public class GetUserInfo {
@GetMapping("/unauth/random") @GetMapping("/unauth/random")
public boolean rand() { public boolean rand(@RequestHeader("Authorization") String token) throws RoleNotFoundException {
System.err.println(token);
return Math.random() > 0.5; return Math.random() > 0.5;
} }

View File

@ -0,0 +1,7 @@
package enseirb.myinpulse.exceptions;
public class RoleNotFoudException extends RuntimeException {
public RoleNotFoudException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package enseirb.myinpulse.exceptions;
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}

View File

@ -47,6 +47,6 @@ public class ComptesRendusController {
if (contenu_compte_rendu != null) { if (contenu_compte_rendu != null) {
compteRendu.get().setContenu_compte_rendu(contenu_compte_rendu); compteRendu.get().setContenu_compte_rendu(contenu_compte_rendu);
} }
return compteRendu.get(); return this.comptesRendusRepository.save(compteRendu.get());
} }
} }

View File

@ -53,6 +53,6 @@ public class EntrepreneursController {
if (status_snee != null) { if (status_snee != null) {
entrepreneur.get().setStatus_snee(status_snee); entrepreneur.get().setStatus_snee(status_snee);
} }
return entrepreneur.get(); return this.entrepreneursRepository.save(entrepreneur.get());
} }
} }

View File

@ -59,6 +59,6 @@ public class ProjetsController {
if (status_projet != null) { if (status_projet != null) {
projet.get().setStatus_projet(status_projet); projet.get().setStatus_projet(status_projet);
} }
return projet.get(); return this.projetsRepository.save(projet.get());
} }
} }

View File

@ -2,16 +2,14 @@ package enseirb.myinpulse.postgres_db.controller;
import enseirb.myinpulse.postgres_db.model.RendezVous; import enseirb.myinpulse.postgres_db.model.RendezVous;
import enseirb.myinpulse.postgres_db.repository.RendezVousRepository; import enseirb.myinpulse.postgres_db.repository.RendezVousRepository;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Optional;
@RestController @RestController
public class RendezVousController { public class RendezVousController {
@ -41,8 +39,8 @@ public class RendezVousController {
public RendezVous updateRendezVous( public RendezVous updateRendezVous(
@PathVariable Long id, @PathVariable Long id,
LocalDate date_rdv, LocalDate date_rdv,
LocalDateTime heure_rdv, LocalTime heure_rdv,
LocalDateTime duree_rdv, LocalTime duree_rdv,
String lieu_rdv, String lieu_rdv,
String sujet_rdv) { String sujet_rdv) {
Optional<RendezVous> rendezVous = this.rendezVousRepository.findById(id); Optional<RendezVous> rendezVous = this.rendezVousRepository.findById(id);
@ -64,6 +62,6 @@ public class RendezVousController {
if (sujet_rdv != null) { if (sujet_rdv != null) {
rendezVous.get().setSujet_rdv(sujet_rdv); rendezVous.get().setSujet_rdv(sujet_rdv);
} }
return rendezVous.get(); return this.rendezVousRepository.save(rendezVous.get());
} }
} }

View File

@ -55,6 +55,6 @@ public class SectionsController {
if (date_modification != null) { if (date_modification != null) {
section.get().setDate_modification(date_modification); section.get().setDate_modification(date_modification);
} }
return section.get(); return this.sectionsRepository.save(section.get());
} }
} }

View File

@ -62,6 +62,6 @@ public class UtilisateursController {
if (numero_telephone != null) { if (numero_telephone != null) {
utilisateur.get().setNumero_telephone(numero_telephone); utilisateur.get().setNumero_telephone(numero_telephone);
} }
return utilisateur.get(); return this.utilisateursRepository.save(utilisateur.get());
} }
} }

View File

@ -9,7 +9,7 @@ import java.util.List;
@Entity @Entity
@Table(name = "administrateurs") @Table(name = "administrateurs")
@PrimaryKeyJoinColumn(name = "id_administrateur") @PrimaryKeyJoinColumn(name = "id_administrateur", referencedColumnName = "id_utilisateur")
public class Administrateurs extends Utilisateurs { public class Administrateurs extends Utilisateurs {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)

View File

@ -6,7 +6,7 @@ import jakarta.persistence.Table;
@Entity @Entity
@Table(name = "entrepreneurs") @Table(name = "entrepreneurs")
@PrimaryKeyJoinColumn(name = "id_entrepreneur") @PrimaryKeyJoinColumn(name = "id_entrepreneur", referencedColumnName = "id_utilisateur")
public class Entrepreneurs extends Utilisateurs { public class Entrepreneurs extends Utilisateurs {
@Column(length = 255) @Column(length = 255)

View File

@ -4,7 +4,7 @@ import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -36,8 +36,8 @@ public class RendezVous {
private Long id_rdv; private Long id_rdv;
private LocalDate date_rdv; private LocalDate date_rdv;
private LocalDateTime heure_rdv; private LocalTime heure_rdv;
private LocalDateTime duree_rdv; private LocalTime duree_rdv;
@Column(length = 255) @Column(length = 255)
private String lieu_rdv; private String lieu_rdv;
@ -49,8 +49,8 @@ public class RendezVous {
public RendezVous( public RendezVous(
Long id_rdv, Long id_rdv,
LocalDate date_rdv, LocalDate date_rdv,
LocalDateTime heure_rdv, LocalTime heure_rdv,
LocalDateTime duree_rdv, LocalTime duree_rdv,
String lieu_rdv, String lieu_rdv,
String sujet_rdv) { String sujet_rdv) {
this.id_rdv = id_rdv; this.id_rdv = id_rdv;
@ -77,19 +77,19 @@ public class RendezVous {
this.date_rdv = date_rdv; this.date_rdv = date_rdv;
} }
public LocalDateTime getHeure_rdv() { public LocalTime getHeure_rdv() {
return heure_rdv; return heure_rdv;
} }
public void setHeure_rdv(LocalDateTime heure_rdv) { public void setHeure_rdv(LocalTime heure_rdv) {
this.heure_rdv = heure_rdv; this.heure_rdv = heure_rdv;
} }
public LocalDateTime getDuree_rdv() { public LocalTime getDuree_rdv() {
return duree_rdv; return duree_rdv;
} }
public void setDuree_rdv(LocalDateTime duree_rdv) { public void setDuree_rdv(LocalTime duree_rdv) {
this.duree_rdv = duree_rdv; this.duree_rdv = duree_rdv;
} }

View File

@ -25,7 +25,7 @@ public class Utilisateurs {
@Column(length = 255) @Column(length = 255)
private String mail_secondaire; private String mail_secondaire;
@Column(length = 15) @Column(length = 20)
private String numero_telephone; private String numero_telephone;
public Utilisateurs() {} public Utilisateurs() {}

View File

@ -1,3 +1,7 @@
/*
* Source: https://github.com/ChristianHuff-DEV/secure-spring-rest-api-using-keycloak/blob/main/src/main/java/io/betweendata/RestApi/security/oauth2/KeycloakJwtRolesConverter.java
* edited by Pierre Tellier
*/
package enseirb.myinpulse.security; package enseirb.myinpulse.security;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
@ -38,7 +42,7 @@ public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthent
source, source,
Stream.concat( Stream.concat(
new JwtGrantedAuthoritiesConverter().convert(source).stream(), new JwtGrantedAuthoritiesConverter().convert(source).stream(),
TEMPORARNAME(source).stream()) tokenRolesExtractor(source).stream())
.collect(toSet())); .collect(toSet()));
} }
@ -46,7 +50,7 @@ public class KeycloakJwtRolesConverter implements Converter<Jwt, AbstractAuthent
* Extracts the realm and resource level roles from a JWT token distinguishing between them * Extracts the realm and resource level roles from a JWT token distinguishing between them
* using prefixes. * using prefixes.
*/ */
public Collection<GrantedAuthority> TEMPORARNAME(Jwt jwt) { public Collection<GrantedAuthority> tokenRolesExtractor(Jwt jwt) {
// Collection that will hold the extracted roles // Collection that will hold the extracted roles
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>(); Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();

View File

@ -0,0 +1,135 @@
package enseirb.myinpulse.utils.keycloak;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import enseirb.myinpulse.exceptions.UserNotFoundException;
import enseirb.myinpulse.utils.keycloak.datatypes.RoleRepresentation;
import enseirb.myinpulse.utils.keycloak.datatypes.UserRepresentation;
import org.springframework.web.client.RestClient;
import javax.management.relation.RoleNotFoundException;
public class KeycloakApi {
static final String keycloakUrl;
static final String realmName;
static {
if (System.getenv("VITE_KEYCLOAK_URL") == null) {
System.exit(-1);
}
keycloakUrl = System.getenv("VITE_KEYCLOAK_URL");
}
static {
if (System.getenv("VITE_KEYCLOAK_REALM") == null) {
System.exit(-1);
}
realmName = System.getenv("VITE_KEYCLOAK_REALM");
}
/**
* Uses Keycloak API to retrieve a role representation of a role by its name
*
* @param roleName name of the role
* @param bearer authorization header used by the client to authenticate to keycloak
*/
public static RoleRepresentation getRoleRepresentationByName(String roleName, String bearer)
throws RoleNotFoundException {
RoleRepresentation[] response =
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.build()
.get()
.uri("/admin/realms/{realmName}/roles/{roleName}", realmName, roleName)
.retrieve()
.body(RoleRepresentation[].class);
if (response == null || response.length == 0) {
throw new RoleNotFoundException("Role not found");
}
return response[0];
}
/**
* Use keycloak API to to retreive a userID via his name or email.
*
* @param username username or mail of the user
* @param bearer bearer of the user, allowing access to database
* @return the userid, as a String
* @throws UserNotFoundException
*/
public static String getUserIdByName(String username, String bearer)
throws UserNotFoundException {
UserRepresentation[] response =
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.build()
.get()
.uri(
"/admin/realms/{realmName}/users?username={username}",
realmName,
username)
.retrieve()
.body(UserRepresentation[].class);
if (response == null || response.length == 0) {
throw new UserNotFoundException("User not found");
}
return response[0].id;
}
/**
* TODO: check for error
*
* <p>Set a keycloak role to a keycloak user.
*
* <p>Usual roles should be `MyINPulse-admin` and `MyINPulse-entrepreneur`
*
* @param username
* @param roleName
* @param bearer
* @throws RoleNotFoundException
* @throws UserNotFoundException
*/
public static void setRoleToUser(String username, String roleName, String bearer)
throws RoleNotFoundException, UserNotFoundException {
RoleRepresentation roleRepresentation = getRoleRepresentationByName(roleName, bearer);
String userId = getUserIdByName(username, bearer);
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.build()
.post()
.uri(
"/admin/realms/${realmName}/users/${userId}/role-mappings/realm",
realmName,
userId)
.body(roleRepresentation)
.contentType(APPLICATION_JSON)
.retrieve();
}
/**
* Delete a user from Keycloak database. TODO: check the bearer permission.
*
* @param username
* @param bearer
* @throws UserNotFoundException
*/
public static void deleteUser(String username, String bearer) throws UserNotFoundException {
String userId = getUserIdByName(username, bearer);
RestClient.builder()
.baseUrl(keycloakUrl)
.defaultHeader("Authorization", bearer)
.build()
.delete()
.uri("/admin/realms/${realmName}/users/${userId}", realmName, userId)
.retrieve();
}
}

View File

@ -0,0 +1,7 @@
package enseirb.myinpulse.utils.keycloak.datatypes;
public class RoleRepresentation {
public String id;
public String name;
public String description;
}

View File

@ -0,0 +1,6 @@
package enseirb.myinpulse.utils.keycloak.datatypes;
public class UserRepresentation {
public String id;
public String name;
}

View File

@ -1,3 +1,5 @@
TRUNCATE projets, utilisateurs, entrepreneurs, sections, rendez_vous, comptes_rendus CASCADE;
INSERT INTO projets (nom_projet, logo, date_creation, status_projet) INSERT INTO projets (nom_projet, logo, date_creation, status_projet)
VALUES ('Eau du robinet', decode('013d7d16d7ad4fefb61bd95b765c8ceb', 'hex'), TO_DATE('01-OCT-2023', 'DD-MON-YYYY'), VALUES ('Eau du robinet', decode('013d7d16d7ad4fefb61bd95b765c8ceb', 'hex'), TO_DATE('01-OCT-2023', 'DD-MON-YYYY'),
'En cours'), 'En cours'),
@ -7,56 +9,49 @@ VALUES ('Eau du robinet', decode('013d7d16d7ad4fefb61bd95b765c8ceb', 'hex'), TO_
('HDeirbMI', decode('ab548d6c1d595a2975e6476f544d14c55a', 'hex'), TO_DATE('07-DEC-2024', 'DD-MON-YYYY'), ('HDeirbMI', decode('ab548d6c1d595a2975e6476f544d14c55a', 'hex'), TO_DATE('07-DEC-2024', 'DD-MON-YYYY'),
'Lancement'); 'Lancement');
INSERT INTO utilisateurs (nom_utilisateur, prenom_utilisateur, mail_principal, mail_secondaire, numero_telephone) INSERT INTO utilisateurs (nom_utilisateur, prenom_utilisateur, mail_principal, mail_secondaire, numero_telephone) VALUES
VALUES ('Dupont', 'Dupond', 'super@mail.fr', 'super2@mail.fr', '06 45 72 45 98'), ('Dupont', 'Dupond', 'super@mail.fr', 'super2@mail.fr', '06 45 72 45 98'),
('Martin', 'Matin', 'genial@mail.fr', 'genial2@mail.fr', '06 52 14 58 73'), ('Martin', 'Matin', 'genial@mail.fr', 'genial2@mail.fr', '06 52 14 58 73'),
('Charvet', 'Lautre', 'mieux@tmail.fr', 'mieux2@tmail.fr', '07 49 82 16 35'), ('Charvet', 'Lautre', 'mieux@tmail.fr', 'mieux2@tmail.fr', '07 49 82 16 35'),
('Leguez', 'Theo', 'bof@mesmails.fr', 'bof2@mesmails.fr', '+33 6 78 14 25 29'), ('Leguez', 'Theo', 'bof@mesmails.fr', 'bof2@mesmails.fr', '+33 6 78 14 25 29'),
('Kia', 'Bi', 'special@mail.fr', 'special2@mail.fr', '07 65 31 38 95'); ('Kia', 'Bi', 'special@mail.fr', 'special2@mail.fr', '07 65 31 38 95'),
('Ducaillou', 'Pierre', 'maildefou@xyz.fr', 'maildefou2@xyz.fr', '06 54 78 12 62');
INSERT INTO entrepreneurs (ecole, filiere, status_snee)
VALUES ('ENSEIRB-MATMECA', 'INFO', TRUE),
('ENSC', 'Cognitique', TRUE),
('ENSEIRB-MATMECA', 'MATMECA', FALSE),
('SupOptique', 'Classique', TRUE),
('ENSEGID', 'Géoscience', FALSE),
('ENSMAC', 'Matériaux composites - Mécanique', FALSE);
INSERT INTO sections (titre, contenu_section, date_modification) INSERT INTO entrepreneurs (ecole, filiere, status_snee, id_entrepreneur) VALUES
VALUES ("Problème", "les problèmes...", TO_DATE('15-JAN-2025', 'DD-MON-YYYY')), ('ENSEIRB-MATMECA', 'INFO', TRUE, 1),
("Segment de client", "Le segment AB passant le client n°8 est de longueur 32mm. ('ENSC', 'Cognitique', TRUE, 2),
Le segment BC a quant à lui un longueur de 28mm. Quelle la longueur du segment AC ?", ('ENSEIRB-MATMECA', 'MATMECA', FALSE, 3),
TO_DATE('12-OCT-2022', 'DD-MON-YYYY')), ('SupOptique', 'Classique', TRUE, 4),
("Proposition de valeur unique", "'Son prix est de 2594€' 'Ah oui c'est unique en effet'", ('ENSEGID', 'Géoscience', FALSE, 5),
TO_DATE('25-MAY-2024', 'DD-MON-YYYY')), ('ENSMAC', 'Matériaux composites - Mécanique', FALSE, 6);
("Solution", "Un problème ? Une solution", TO_DATE('08-FEB-2024', 'DD-MON-YYYY')),
("Canaux", "Ici nous avons la Seine, là-bas le Rhin, oh et plus loin le canal de Suez",
TO_DATE('19-JUL-2023', 'DD-MON-YYYY')),
("Sources de revenus", "Y'en n'a pas on est pas payé. Enfin y'a du café quoi",
TO_DATE('12-JAN-2025', 'DD-MON-YYYY')),
("Structure des coûts", "'Ah oui là ça va faire au moins 1000€ par mois', Eirbware",
TO_DATE('06-FEB-2025', 'DD-MON-YYYY')),
("Indicateurs clés", "On apprend les clés comme des badges, ça se fait", TO_DATE('05-FEB-2025', 'DD-MON-YYYY')),
("Avantages concurrentiel", "On est meilleur", TO_DATE('23-APR-2024', 'DD-MON-YYYY'));
INSERT INTO rendez_vous (date_rdv, heure_rdv, duree_rdv, lieu_rdv, sujet_rdv) INSERT INTO sections (titre, contenu_section, date_modification) VALUES
VALUES (TO_DATE('24-DEC-2023', 'DD-MON-YYYY'), '00:00:00', '00:37:53', "À la maison", "Ouvrir les cadeaux"), ('Problème', 'les problèmes...', TO_TIMESTAMP('15-JAN-2025 09:30:20', 'DD-MON-YYYY, HH24:MI:SS')),
(TO_DATE('15-AUG-2024', 'DD-MON-YYYY'), '22:35:00', '00:12:36', "Sur les quais ou dans un champ probablement", ('Segment de client', 'Le segment AB passant le client n°8 est de longueur 32mm.
"BOUM BOUM les feux d'artifices (on fête quoi déjà ?)"), Le segment BC a quant à lui un longueur de 28mm. Quelle la longueur du segment AC ?', TO_TIMESTAMP('12-OCT-2022 17:47:38', 'DD-MON-YYYY, HH24:MI:SS')),
(TO_DATE('29-FEB-2023', 'DD-MON-YYYY'), '14:20:00', '00:20:00', "Salle TD 15", ('Proposition de valeur unique', '''Son prix est de 2594€'' ''Ah oui c''est unique en effet', TO_TIMESTAMP('25-MAY-2024 11:12:04', 'DD-MON-YYYY, HH24:MI:SS')),
"Ah mince c'est pas une année bissextile !"), ('Solution', 'Un problème ? Une solution', TO_TIMESTAMP('08-FEB-2024 10:17:53', 'DD-MON-YYYY, HH24:MI:SS')),
(TO_DATE('23-JAN-2024', 'DD-MON-YYYY'), '12:56:27', '11:03:33', "Là où le vent nous porte", ('Canaux', 'Ici nous avons la Seine, là-bas le Rhin, oh et plus loin le canal de Suez', TO_TIMESTAMP('19-JUL-2023 19:22:45', 'DD-MON-YYYY, HH24:MI:SS')),
"Journée la plus importante de l'année"), ('Sources de revenus', 'Y''en n''a pas on est pas payé. Enfin y''a du café quoi', TO_TIMESTAMP('12-JAN-2025 11:40:26', 'DD-MON-YYYY, HH24:MI:SS')),
(TO_DATE('25-AUG-2025', 'DD-MON-YYYY'), '00:09:00', '01:00:00', "Euh c'est par où l'amphi 56 ?", ('Structure des coûts', '''Ah oui là ça va faire au moins 1000€ par mois'', Eirbware', TO_TIMESTAMP('06-FEB-2025 13:04:06', 'DD-MON-YYYY, HH24:MI:SS')),
"Rentrée scolaire (il fait trop froid c'est quoi ça on est en août)"); ('Indicateurs clés', 'On apprend les clés comme des badges, ça se fait', TO_TIMESTAMP('05-FEB-2025 12:42:38', 'DD-MON-YYYY, HH24:MI:SS')),
('Avantages concurrentiel', 'On est meilleur', TO_TIMESTAMP('23-APR-2024 16:24:02', 'DD-MON-YYYY, HH24:MI:SS'));
INSERT INTO comptes_rendus (contenu_compte_rendu) INSERT INTO rendez_vous (date_rdv, heure_rdv, duree_rdv, lieu_rdv, sujet_rdv) VALUES
VALUES ("Ah oui ça c'est super, ah ouais j'aime bien, bien vu de penser à ça"), (TO_DATE('24-DEC-2023', 'DD-MON-YYYY'), '00:00:00', '00:37:53', 'À la maison', 'Ouvrir les cadeaux'),
("Bonne réunion"), (TO_DATE('15-AUG-2024', 'DD-MON-YYYY'), '22:35:00', '00:12:36', 'Sur les quais ou dans un champ probablement', 'BOUM BOUM les feux d''artifices (on fête quoi déjà ?)'),
("Ouais, j'ai rien compris mais niquel on fait comme vous avez dit"), (TO_DATE('28-FEB-2023', 'DD-MON-YYYY'), '14:20:00', '00:20:00', 'Salle TD 15', 'Ah mince c''est pas une année bissextile !'),
("Non non ça va pas du tout ce que tu me proposes, faut tout refaire"), (TO_DATE('23-JAN-2024', 'DD-MON-YYYY'), '12:56:27', '11:03:33', 'Là où le vent nous porte', 'Journée la plus importante de l''année'),
("Réponse de la DSI : non"), (TO_DATE('25-AUG-2025', 'DD-MON-YYYY'), '00:09:00', '01:00:00', 'Euh c''est par où l''amphi 56 ?', 'Rentrée scolaire (il fait trop froid c''est quoi ça on est en août)');
("Trop dommage qu'Apple ait sorti leur logiciel avant nous, on avait la même idée et tout on aurait tellement pu leur faire de la concurrence");
INSERT INTO comptes_rendus (contenu_compte_rendu) VALUES
('Ah oui ça c''est super, ah ouais j''aime bien, bien vu de penser à ça'),
('Bonne réunion'),
('Ouais, j''ai rien compris mais niquel on fait comme vous avez dit'),
('Non non ça va pas du tout ce que tu me proposes, faut tout refaire'),
('Réponse de la DSI : non'),
('Trop dommage qu''Apple ait sorti leur logiciel avant nous, on avait la même idée et tout on aurait tellement pu leur faire de la concurrence');

View File

@ -0,0 +1 @@
DROP TABLE IF EXISTS administrateurs, projets, utilisateurs, entrepreneurs, sections, rendez_vous, comptes_rendus, concerner CASCADE;

View File

@ -20,14 +20,13 @@ CREATE TABLE projets
CREATE TABLE utilisateurs CREATE TABLE utilisateurs
( (
id_utilisateur SERIAL NOT NULL, id_utilisateur SERIAL NOT NULL,
nom_utilisateur VARCHAR(255), nom_utilisateur VARCHAR(255) ,
prenom_utilisateur VARCHAR(255), prenom_utilisateur VARCHAR(255) ,
mail_principal VARCHAR(255), mail_principal VARCHAR(255) ,
mail_secondaire VARCHAR(255), mail_secondaire VARCHAR(255) ,
numero_telephone VARCHAR(15), numero_telephone VARCHAR(20) ,
CONSTRAINT pk_utilisateur PRIMARY KEY (id_utilisateur) CONSTRAINT pk_utilisateur PRIMARY KEY (id_utilisateur) );
);
CREATE TABLE entrepreneurs CREATE TABLE entrepreneurs
( (

View File

@ -14,7 +14,8 @@ axiosInstance.interceptors.response.use(
async (error) => { async (error) => {
const originalRequest = error.config; const originalRequest = error.config;
if ( if (
error.response.status === 401 && ((error.response && error.response.status === 401) ||
error.code == "ERR_NETWORK") &&
!originalRequest._retry && !originalRequest._retry &&
store.authenticated store.authenticated
) { ) {

View File

@ -1,6 +1,9 @@
<script lang="ts" setup> <script lang="ts" setup>
import { store } from "../main.ts"; import { store } from "../main.ts";
import { callApi } from "@/services/api.ts"; import { callApi } from "@/services/api.ts";
import { ref } from "vue";
const CustomRequest = ref("");
</script> </script>
<template> <template>
@ -55,6 +58,14 @@ import { callApi } from "@/services/api.ts";
<td>res</td> <td>res</td>
<td id="3"></td> <td id="3"></td>
</tr> </tr>
<tr>
<td>
<input v-model="CustomRequest" placeholder="edit me" />
</td>
<td>
<button @click="callApi(CustomRequest)">call</button>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</template> </template>