Initial commit: GBCM Client Quarkus implementation with PrimeFaces and Freya theme

This commit is contained in:
dahoud
2025-10-06 18:45:43 +00:00
commit 9aff13a830
7 changed files with 869 additions and 0 deletions

View File

@@ -0,0 +1,195 @@
package com.gbcm.client.beans.auth;
import com.gbcm.client.service.GBCMServerClient;
import com.gbcm.server.api.dto.UserDTO;
import com.gbcm.server.api.dto.LoginRequestDTO;
import com.gbcm.server.api.dto.LoginResponseDTO;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.io.Serializable;
/**
* Managed Bean pour la gestion de l'authentification
*/
@Named("authBean")
@SessionScoped
public class AuthBean implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private GBCMServerClient serverClient;
// Propriétés de connexion
private String email;
private String password;
private boolean rememberMe;
// Utilisateur connecté
private UserDTO currentUser;
private String authToken;
private boolean authenticated = false;
/**
* Tentative de connexion
*/
public String login() {
try {
LoginRequestDTO loginRequest = new LoginRequestDTO();
loginRequest.setEmail(email);
loginRequest.setPassword(password);
loginRequest.setRememberMe(rememberMe);
LoginResponseDTO response = serverClient.login(loginRequest);
if (response.isSuccess()) {
this.currentUser = response.getUser();
this.authToken = response.getToken();
this.authenticated = true;
// Message de succès
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"Connexion réussie",
"Bienvenue " + currentUser.getFirstName()));
// Redirection selon le rôle
return redirectAfterLogin();
} else {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Erreur de connexion",
response.getMessage()));
return null;
}
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Erreur système",
"Impossible de se connecter au serveur"));
return null;
}
}
/**
* Déconnexion
*/
public String logout() {
try {
if (authToken != null) {
serverClient.logout(authToken);
}
} catch (Exception e) {
// Log l'erreur mais continue la déconnexion
}
// Nettoyage de la session
this.currentUser = null;
this.authToken = null;
this.authenticated = false;
this.email = null;
this.password = null;
this.rememberMe = false;
// Invalidation de la session JSF
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/index?faces-redirect=true";
}
/**
* Redirection après connexion selon le rôle
*/
private String redirectAfterLogin() {
if (currentUser == null) {
return "/index?faces-redirect=true";
}
switch (currentUser.getRole()) {
case "ADMIN":
return "/pages/admin/dashboard?faces-redirect=true";
case "COACH":
return "/pages/coaching/dashboard?faces-redirect=true";
case "CLIENT":
return "/pages/dashboard/client?faces-redirect=true";
default:
return "/pages/dashboard/home?faces-redirect=true";
}
}
/**
* Navigation vers le profil
*/
public String goToProfile() {
return "/pages/profile/edit?faces-redirect=true";
}
/**
* Navigation vers les paramètres
*/
public String goToSettings() {
return "/pages/settings/general?faces-redirect=true";
}
/**
* Vérification des permissions
*/
public boolean hasRole(String role) {
return authenticated && currentUser != null &&
role.equals(currentUser.getRole());
}
public boolean isAdmin() {
return hasRole("ADMIN");
}
public boolean isCoach() {
return hasRole("COACH");
}
public boolean isClient() {
return hasRole("CLIENT");
}
// Getters et Setters
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isRememberMe() {
return rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}
public UserDTO getCurrentUser() {
return currentUser;
}
public String getAuthToken() {
return authToken;
}
public boolean isAuthenticated() {
return authenticated;
}
}

View File

@@ -0,0 +1,47 @@
# GBCM Client Configuration
quarkus.application.name=gbcm-client
quarkus.application.version=1.0.0-SNAPSHOT
# Server Configuration
quarkus.http.port=8080
quarkus.http.host=0.0.0.0
# JSF Configuration
quarkus.servlet.context-path=/gbcm
# Security Configuration
quarkus.security.auth.enabled=true
# REST Client Configuration - GBCM Server API
gbcm.server.api.url=http://localhost:8081/api/v1
quarkus.rest-client."com.gbcm.client.service.GBCMServerClient".url=${gbcm.server.api.url}
# Database Configuration (for session storage)
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=gbcm_user
quarkus.datasource.password=gbcm_password
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/gbcm_client
# Hibernate Configuration
quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.log.sql=false
# Logging Configuration
quarkus.log.level=INFO
quarkus.log.category."com.gbcm".level=DEBUG
# Development Configuration
%dev.quarkus.log.level=DEBUG
%dev.quarkus.hibernate-orm.log.sql=true
%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:gbcm_client_dev;DB_CLOSE_DELAY=-1
%dev.quarkus.datasource.db-kind=h2
# Production Configuration
%prod.quarkus.log.level=WARN
%prod.quarkus.datasource.jdbc.url=${DATABASE_URL}
# PrimeFaces Configuration
primefaces.theme=freya
primefaces.font-awesome=true
primefaces.client-side-validation=true
primefaces.move-scripts-to-bottom=true

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<display-name>GBCM Client Application</display-name>
<description>Interface web GBCM pour la gestion des services de consulting</description>
<!-- JSF Configuration -->
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>jakarta.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<!-- PrimeFaces Configuration -->
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>freya</param-value>
</context-param>
<context-param>
<param-name>primefaces.FONT_AWESOME</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>primefaces.CLIENT_SIDE_VALIDATION</param-name>
<param-value>true</param-value>
</context-param>
<!-- JSF Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!-- Security Configuration -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Pages</web-resource-name>
<url-pattern>/pages/dashboard/*</url-pattern>
<url-pattern>/pages/coaching/*</url-pattern>
<url-pattern>/pages/workshops/*</url-pattern>
<url-pattern>/pages/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
<role-name>coach</role-name>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<!-- Welcome Files -->
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<!-- Error Pages -->
<error-page>
<error-code>404</error-code>
<location>/pages/error/404.xhtml</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/pages/error/500.xhtml</location>
</error-page>
</web-app>

View File

@@ -0,0 +1,135 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>
<ui:insert name="title">GBCM - Global Business Consulting and Management</ui:insert>
</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="description" content="GBCM - Services de conseil en management et développement professionnel"/>
<meta name="author" content="GBCM LLC"/>
<!-- Freya Theme CSS -->
<h:outputStylesheet name="primefaces-freya/theme.css"/>
<!-- Custom CSS -->
<h:outputStylesheet name="css/gbcm-custom.css"/>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="#{request.contextPath}/resources/images/favicon.ico"/>
</h:head>
<h:body>
<div class="layout-wrapper">
<!-- Top Bar -->
<div class="layout-topbar">
<div class="layout-topbar-wrapper">
<div class="layout-topbar-left">
<h:link outcome="/index" styleClass="layout-topbar-logo">
<h:graphicImage name="images/gbcm-logo.png" alt="GBCM Logo" height="40"/>
<span class="layout-topbar-logo-text">GBCM</span>
</h:link>
</div>
<div class="layout-topbar-right">
<ul class="layout-topbar-actions">
<li>
<p:commandButton icon="pi pi-user" styleClass="p-button-text p-button-plain"
onclick="PF('userMenuDialog').show()"/>
</li>
<li>
<p:commandButton icon="pi pi-bell" styleClass="p-button-text p-button-plain"
onclick="PF('notificationDialog').show()"/>
</li>
</ul>
</div>
</div>
</div>
<!-- Sidebar Menu -->
<div class="layout-sidebar">
<div class="layout-menu">
<p:menu model="#{menuBean.menuModel}" styleClass="layout-menu-items"/>
</div>
</div>
<!-- Main Content -->
<div class="layout-main">
<div class="layout-main-content">
<!-- Breadcrumb -->
<div class="content-section">
<p:breadCrumb model="#{breadcrumbBean.breadcrumbModel}" styleClass="custom-breadcrumb"/>
</div>
<!-- Page Content -->
<div class="content-section">
<ui:insert name="content">
<p:panel header="Contenu par défaut">
<p>Aucun contenu spécifique défini pour cette page.</p>
</p:panel>
</ui:insert>
</div>
</div>
</div>
<!-- Footer -->
<div class="layout-footer">
<div class="layout-footer-wrapper">
<span>© 2024 GBCM LLC - Global Business Consulting and Management</span>
<div class="layout-footer-right">
<span>Version 1.0.0</span>
</div>
</div>
</div>
</div>
<!-- User Menu Dialog -->
<p:dialog header="Profil Utilisateur" widgetVar="userMenuDialog" modal="true"
width="400" height="300" resizable="false">
<div class="user-profile-content">
<p:outputLabel value="#{authBean.currentUser.fullName}" styleClass="user-name"/>
<p:outputLabel value="#{authBean.currentUser.email}" styleClass="user-email"/>
<div class="user-actions">
<p:commandButton value="Mon Profil" icon="pi pi-user"
action="#{authBean.goToProfile}" styleClass="p-button-outlined"/>
<p:commandButton value="Paramètres" icon="pi pi-cog"
action="#{authBean.goToSettings}" styleClass="p-button-outlined"/>
<p:commandButton value="Déconnexion" icon="pi pi-sign-out"
action="#{authBean.logout}" styleClass="p-button-danger"/>
</div>
</div>
</p:dialog>
<!-- Notification Dialog -->
<p:dialog header="Notifications" widgetVar="notificationDialog" modal="true"
width="500" height="400" resizable="false">
<p:dataTable value="#{notificationBean.notifications}" var="notification"
emptyMessage="Aucune notification">
<p:column headerText="Message">
<h:outputText value="#{notification.message}"/>
</p:column>
<p:column headerText="Date">
<h:outputText value="#{notification.createdAt}">
<f:convertDateTime pattern="dd/MM/yyyy HH:mm"/>
</h:outputText>
</p:column>
</p:dataTable>
</p:dialog>
<!-- Global Messages -->
<p:growl id="globalMessages" showDetail="true" life="5000"/>
<!-- Custom JavaScript -->
<h:outputScript name="js/gbcm-custom.js"/>
</h:body>
</html>