Updated API connection

This commit is contained in:
Alexis Leboeuf
2026-01-08 14:51:50 +01:00
parent 1b44116936
commit 0e8ba63be5
4 changed files with 100 additions and 12 deletions

View File

@@ -1,10 +1,14 @@
package hackathon.FrisbYEE.jpa.service; package hackathon.FrisbYEE.jpa.service;
import hackathon.FrisbYEE.jpa.metier.Coach;
import hackathon.FrisbYEE.jpa.metier.User; import hackathon.FrisbYEE.jpa.metier.User;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository @Repository
public interface UserDAO extends JpaRepository<User, Integer> { public interface UserDAO extends JpaRepository<User, Integer> {
Optional<Coach> findByKeycloakId(String keycloakId);
} }

View File

@@ -0,0 +1,71 @@
package hackathon.FrisbYEE.rest;
import java.util.ArrayList;
import java.util.List;
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.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import hackathon.FrisbYEE.jpa.dto.AthleteDTO;
import hackathon.FrisbYEE.jpa.dto.UserDTO;
import hackathon.FrisbYEE.jpa.metier.Athlete;
import hackathon.FrisbYEE.jpa.metier.User;
import hackathon.FrisbYEE.jpa.service.UserDAO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@RestController
@RequestMapping("/users")
@CrossOrigin(origins = "http://localhost:3000")
public class UserResource {
@Autowired
private UserDAO userDAO;
@Operation(summary = "Récupère tous les utilisateurs")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Récupère tous les athlètes", content = @Content(mediaType = "application/json", schema = @Schema(implementation = List.class)))
})
@GetMapping("/all")
@PreAuthorize("hasRole('admin') or hasRole('coach')")
public ResponseEntity<List<UserDTO>> all() {
List<User> users = userDAO.findAll();
List<UserDTO> dtos = new ArrayList<>();
for (User user : users) {
dtos.add(mapToDTO(user));
}
return ResponseEntity.ok(dtos);
}
@Operation(summary = "Récupère l'utilisateur ayant l'identifiant correspondant")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class)))
})
@GetMapping("/{id}")
@PreAuthorize("hasRole('admin') or hasRole('coach') or hasRole('athlete')")
public ResponseEntity<UserDTO> getById(@PathVariable String id) {
User user = userDAO.findByKeycloakId(id).get();
return ResponseEntity.ok(mapToDTO(user));
}
private UserDTO mapToDTO(User user) {
UserDTO dto = new UserDTO();
dto.setId_keycloak(user.getKeycloakId());
dto.setName(user.getName());
dto.setPrenom(user.getPrenom());
dto.setRole(user.getRole());
return dto;
}
}

View File

@@ -1,27 +1,36 @@
import axios from "axios"; import axios from "axios";
import keycloak from "./keycloak";
const api = axios.create({ const api = axios.create({
baseURL: "http://localhost:8081/api", // backend listens on 8081 and controllers are mounted at root (no /api prefix)
baseURL: "http://localhost:8081",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
withCredentials: true,
}); });
// Simple interceptor to ensure headers object exists; actual token should be set via setAuthToken()
api.interceptors.request.use((config) => { api.interceptors.request.use((config) => {
if (keycloak?.token) { if (!config.headers) config.headers = {};
// eslint-disable-next-line no-param-reassign
config.headers.Authorization = `Bearer ${keycloak.token}`;
console.log(config.headers.Authorization);
}
return config; return config;
}); });
// Helpers to set/clear the Authorization header programmatically (call after Keycloak login)
export function setAuthToken(token: string | null) {
if (token) {
api.defaults.headers.common["Authorization"] = `Bearer ${token}`;
} else {
delete api.defaults.headers.common["Authorization"];
}
}
export function clearAuthToken() {
delete api.defaults.headers.common["Authorization"];
}
export const athleteService = { export const athleteService = {
create: (data: any) => api.post("/athletes/create", data), create: (data: any) => api.post("/athletes/create", data),
getAll: () => api.get("/athletes/all"), getAll: () => api.get("/athletes/all"),
getById: (id: number | string) => api.get(`/athletes/${id}`), getByKeycloakId: (id: number | string) => api.get(`/athletes/${id}`),
update: (id: number | string, data: any) => api.put(`/athletes/${id}`, data), update: (id: number | string, data: any) => api.put(`/athletes/${id}`, data),
delete: (id: number | string) => api.delete(`/athletes/${id}`), delete: (id: number | string) => api.delete(`/athletes/${id}`),
@@ -63,7 +72,7 @@ export const coachService = {
// controller doesn't declare a class-level path consistently; support both common patterns // controller doesn't declare a class-level path consistently; support both common patterns
create: (data: any) => api.post(`/coach/create`, data), create: (data: any) => api.post(`/coach/create`, data),
getAll: () => api.get(`/coach/all`), getAll: () => api.get(`/coach/all`),
getById: (id: number | string) => api.get(`/coach/${id}`), getByKeycloakId: (id: number | string) => api.get(`/coach/${id}`),
update: (id: number | string, data: any) => api.put(`/coach/update/${id}`, data), update: (id: number | string, data: any) => api.put(`/coach/update/${id}`, data),
delete: (id: number | string) => api.delete(`/coach/delete/${id}`), delete: (id: number | string) => api.delete(`/coach/delete/${id}`),
@@ -73,7 +82,7 @@ export const coachService = {
}; };
export const userService = { export const userService = {
getById: (id: number | string) => api.get(`/users/${id}`), getByKeycloakId: (id: number | string) => api.get(`/users/${id}`),
getAll: () => api.get(`/users`), getAll: () => api.get(`/users`),
}; };

View File

@@ -2,6 +2,7 @@ import { useKeycloak } from '@react-keycloak/web'
import { useEffect } from 'react'; import { useEffect } from 'react';
import { getUserTest, User } from '../classes'; import { getUserTest, User } from '../classes';
import { useLocalData } from '../context/useLocalData'; import { useLocalData } from '../context/useLocalData';
import { setAuthToken, clearAuthToken } from '../api';
export const Login =() =>{ export const Login =() =>{
const {user,setUser} = useLocalData() const {user,setUser} = useLocalData()
@@ -11,6 +12,8 @@ export const Login =() =>{
const syncAndLoadUser = async () => { const syncAndLoadUser = async () => {
if (keycloak.authenticated && keycloak.token) { if (keycloak.authenticated && keycloak.token) {
const tokenParsed = keycloak.tokenParsed; const tokenParsed = keycloak.tokenParsed;
// set axios default auth header for API calls
setAuthToken(keycloak.token);
setUser({ setUser({
id: 0, id: 0,
keycloakId: tokenParsed!.sub!, keycloakId: tokenParsed!.sub!,
@@ -47,6 +50,7 @@ export const Login =() =>{
function handleLogout(): void { function handleLogout(): void {
keycloak.logout() keycloak.logout()
setUser(new User()); setUser(new User());
clearAuthToken();
} }
return( return(
<div> <div>