Updated API connection
This commit is contained in:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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`),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user